efc356f2fff8ccfec49ed25137abfc839bcc50cb
[collectd.git] / contrib / SpamAssassin / Collectd.pm
1 #!/usr/bin/perl
2 # $Id: Collectd.pm 7 2006-12-07 06:13:12Z formorer $
3
4 =head1 NAME
5
6 Collectd - plugin for filling collectd with stats 
7
8 =head1 INSTALLATION
9
10 Just copy Collectd.pm into your SpamAssassin Plugin path 
11 (e.g /usr/share/perl5/Mail/SpamAssassin/Plugin/) and
12 add a loadplugin call into your init.pre file. 
13
14 =head1 SYNOPSIS
15
16   loadplugin    Mail::SpamAssassin::Plugin::Collectd
17
18 =head1 USER SETTINGS
19
20 =over 4
21
22 =item collectd_socket [ socket path ]       (default: /tmp/.collectd-email)
23
24 Where the collectd socket is
25
26 =cut 
27
28 =item collectd_buffersize [ size ] (default: 256) 
29
30 the email plugin uses a fixed buffer, if a line exceeds this size
31 it has to be continued in another line. (This is of course handled internally)
32 If you have changed this setting please get it in sync with the SA Plugin
33 config. 
34
35 =cut 
36 =head1 DESCRIPTION
37
38 This modules uses the email plugin of collectd from Sebastian Harl to
39 collect statistical informations in rrd files to create some nice looking
40 graphs with rrdtool. They communicate over a unix socket that the collectd
41 plugin creates. The generated graphs will be placed in /var/lib/collectd/email
42
43 =head1 AUTHOR
44
45 Alexander Wirt <formorer@formorer.de>
46
47 =head1 COPYRIGHT
48
49  Copyright 2006 Alexander Wirt <formorer@formorer.de> 
50  
51  This program is free software; you can redistribute it and/or modify 
52  it under the the terms of either: 
53
54  a) the Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
55
56  or
57
58  b) the GPL (http://www.gnu.org/copyleft/gpl.html)  
59
60  use whatever you like more. 
61
62 =cut
63
64 package Mail::SpamAssassin::Plugin::Collectd;
65
66 use Mail::SpamAssassin::Plugin;
67 use Mail::SpamAssassin::Logger;
68 use strict;
69 use bytes; 
70 use warnings;
71 use IO::Socket;
72
73 use vars qw(@ISA);
74 @ISA = qw(Mail::SpamAssassin::Plugin);
75
76 sub new {
77     my ($class, $mailsa) = @_;
78
79     # the usual perlobj boilerplate to create a subclass object
80     $class = ref($class) || $class;
81     my $self = $class->SUPER::new($mailsa);
82     bless ($self, $class);
83
84     # register our config options
85     $self->set_config($mailsa->{conf});
86
87     # and return the new plugin object
88     return $self;
89 }
90
91 sub set_config {
92     my ($self, $conf) = @_;
93     my @cmds = ();
94
95     push (@cmds, {
96             setting => 'collectd_buffersize',
97             default => 256,
98             type =>
99             $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
100         });
101
102     push (@cmds, {
103             setting => 'collectd_socket', 
104             default => '/tmp/.collectd-email',
105             type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
106     });
107
108         push (@cmds, {
109                         setting => 'collectd_timeout',
110                         default => 2,
111                         type =>
112                         $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
113         });
114
115     $conf->{parser}->register_commands(\@cmds);
116 }
117
118 sub check_end {
119     my ($self, $params) = @_;
120     my $message_status = $params->{permsgstatus};
121         #create  new connection to our socket
122         eval {
123                 local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
124
125                 #generate a timeout
126                 alarm $self->{main}->{conf}->{collectd_timeout};
127
128                 my $sock = new IO::Socket::UNIX ( $self->{main}->{conf}->{collectd_socket});
129                 # debug some informations if collectd is not running or anything else went
130                 # wrong
131                 if ( ! $sock ) {
132                         dbg("collect: could not connect to " .
133                                 $self->{main}->{conf}->{collectd_socket} . ": $! - collectd plugin
134                                 disabled"); 
135                         return 0; 
136                 }
137                 $sock->autoflush(1);
138
139                 my $score = $message_status->{score};
140                 #get the size of the message 
141                 my $body = $message_status->{msg}->{pristine_body};
142
143                 my $len = length($body);
144
145                 if ($message_status->{score} >= $self->{main}->{conf}->{required_score} ) {
146                         #hey we have spam
147                         print $sock "e:spam:$len\n";
148                 } else {
149                         print $sock "e:ham:$len\n";
150                 }
151                 print $sock "s:$score\n";
152                 my @tmp_array; 
153                 my @tests = @{$message_status->{test_names_hit}};
154
155                 my $buffersize = $self->{main}->{conf}->{collectd_buffersize}; 
156                 dbg("collectd: buffersize: $buffersize"); 
157
158                 while  (scalar(@tests) > 0) {
159                 push (@tmp_array, pop(@tests)); 
160                         if (length(join(',', @tmp_array) . '\n') > $buffersize) {
161                                 push (@tests, pop(@tmp_array)); 
162                                         if (length(join(',', @tmp_array) . '\n') > $buffersize or scalar(@tmp_array) == 0) {
163                                                 dbg("collectd: this shouldn't happen. Do you have tests"
164                                                         ." with names that have more than ~ $buffersize Bytes?");
165                                                 return 1; 
166                                         } else {
167                                                 dbg ( "collectd: c:" . join(',', @tmp_array) . "\n" ); 
168                                                 print $sock "c:" . join(',', @tmp_array) . "\n"; 
169                                                 #clean the array
170                                                 @tmp_array = ();
171                                         } 
172                         } elsif ( scalar(@tests) == 0 ) {
173                                 dbg ( "collectd: c:" . join(',', @tmp_array) . '\n' );
174                                 print $sock "c:" . join(',', @tmp_array) . "\n";
175                         }
176                 }
177                 close($sock); 
178                 alarm 0; 
179         };
180         if ($@ eq "alarm\n") {
181                 info("Connection to collectd timed out");
182                 return -1; 
183         }
184 }
185
186 1;
187
188 # vim: syntax=perl sw=4 ts=4 noet shiftround