Code

configure gbp's debian-branch
[pkg-collectd.git] / contrib / SpamAssassin / Collectd.pm
1 #!/usr/bin/perl
3 =head1 NAME
5 Collectd - plugin for filling collectd with stats 
7 =head1 INSTALLATION
9 Just copy Collectd.pm into your SpamAssassin Plugin path 
10 (e.g /usr/share/perl5/Mail/SpamAssassin/Plugin/) and
11 add a loadplugin call into your init.pre file. 
13 =head1 SYNOPSIS
15   loadplugin    Mail::SpamAssassin::Plugin::Collectd
17 =head1 USER SETTINGS
19 =over 4
21 =item collectd_socket [ socket path ]       (default: /var/run/collectd-email)
23 Where the collectd socket is
25 =cut 
27 =item collectd_buffersize [ size ] (default: 256) 
29 the email plugin uses a fixed buffer, if a line exceeds this size
30 it has to be continued in another line. (This is of course handled internally)
31 If you have changed this setting please get it in sync with the SA Plugin
32 config. 
34 =cut 
36 =item collectd_timeout [ sec ] (default: 2) 
38 if sending data to to collectd takes too long the connection will be aborted. 
40 =cut
42 =item collectd_retries [ tries ] (default: 3)
44 the collectd plugin uses a tread pool, if this is empty the connection fails,
45 the SA Plugin then tries to reconnect. With this variable you can indicate how
46 often it should try. 
48 =cut
50 =head1 DESCRIPTION
52 This modules uses the email plugin of collectd from Sebastian Harl to
53 collect statistical informations in rrd files to create some nice looking
54 graphs with rrdtool. They communicate over a unix socket that the collectd
55 plugin creates. The generated graphs will be placed in /var/lib/collectd/email
57 =head1 AUTHOR
59 Alexander Wirt <formorer@formorer.de>
61 =head1 COPYRIGHT
63  Copyright 2006 Alexander Wirt <formorer@formorer.de> 
64  
65  This program is free software; you can redistribute it and/or modify 
66  it under the the terms of either: 
68  a) the Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
70  or
72  b) the GPL (http://www.gnu.org/copyleft/gpl.html)  
74  use whatever you like more. 
76 =cut
78 package Mail::SpamAssassin::Plugin::Collectd;
80 use Mail::SpamAssassin::Plugin;
81 use Mail::SpamAssassin::Logger;
82 use strict;
83 use bytes; 
84 use warnings;
85 use Time::HiRes qw(usleep);
86 use IO::Socket;
88 use vars qw(@ISA);
89 @ISA = qw(Mail::SpamAssassin::Plugin);
91 sub new {
92     my ($class, $mailsa) = @_;
94     # the usual perlobj boilerplate to create a subclass object
95     $class = ref($class) || $class;
96     my $self = $class->SUPER::new($mailsa);
97     bless ($self, $class);
99     # register our config options
100     $self->set_config($mailsa->{conf});
102     # and return the new plugin object
103     return $self;
106 sub set_config {
107     my ($self, $conf) = @_;
108     my @cmds = ();
110     push (@cmds, {
111             setting => 'collectd_buffersize',
112             default => 256,
113             type =>
114             $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
115         });
117     push (@cmds, {
118             setting => 'collectd_socket', 
119             default => '/var/run/collectd-email',
120             type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
121     });
123         push (@cmds, {
124                         setting => 'collectd_timeout',
125                         default => 2,
126                         type =>
127                         $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
128         });
130         push (@cmds, {
131                         setting => 'collectd_retries',
132                         default => 3,
133                         type =>
134                         $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
135         });
138     $conf->{parser}->register_commands(\@cmds);
141 sub check_end {
142     my ($self, $params) = @_;
143     my $message_status = $params->{permsgstatus};
144         #create  new connection to our socket
145         eval {
146                 local $SIG{ALRM} = sub { die "Sending to collectd timed out.\n" }; # NB: \n required
148                 #generate a timeout
149                 alarm $self->{main}->{conf}->{collectd_timeout};
151                 my $sock;
152                 #try at least $self->{main}->{conf}->{collectd_retries} to get a
153                 #connection
154                 for (my $i = 0; $i < $self->{main}->{conf}->{collectd_retries} ; ++$i) {
155                         last if $sock = new IO::Socket::UNIX
156                                 ($self->{main}->{conf}->{collectd_socket});
157                         #sleep a random value between 0 and 50 microsecs to try for a new
158                         #thread
159                         usleep(int(rand(50))); 
160                 }
162                 die("could not connect to " .
163                                 $self->{main}->{conf}->{collectd_socket} . ": $! - collectd plugin disabled") unless $sock; 
165                 $sock->autoflush(1);
167                 my $score = $message_status->{score};
168                 #get the size of the message 
169                 my $body = $message_status->{msg}->{pristine_body};
171                 my $len = length($body);
173                 if ($message_status->{score} >= $self->{main}->{conf}->{required_score} ) {
174                         #hey we have spam
175                         print $sock "e:spam:$len\n";
176                 } else {
177                         print $sock "e:ham:$len\n";
178                 }
179                 print $sock "s:$score\n";
180                 my @tmp_array; 
181                 my @tests = @{$message_status->{test_names_hit}};
183                 my $buffersize = $self->{main}->{conf}->{collectd_buffersize}; 
184                 dbg("collectd: buffersize: $buffersize"); 
186                 while  (scalar(@tests) > 0) {
187                 push (@tmp_array, pop(@tests)); 
188                         if (length(join(',', @tmp_array) . '\n') > $buffersize) {
189                                 push (@tests, pop(@tmp_array)); 
190                                         if (length(join(',', @tmp_array) . '\n') > $buffersize or scalar(@tmp_array) == 0) {
191                                                 dbg("collectd: this shouldn't happen. Do you have tests"
192                                                         ." with names that have more than ~ $buffersize Bytes?");
193                                                 return 1; 
194                                         } else {
195                                                 dbg ( "collectd: c:" . join(',', @tmp_array) . "\n" ); 
196                                                 print $sock "c:" . join(',', @tmp_array) . "\n"; 
197                                                 #clean the array
198                                                 @tmp_array = ();
199                                         } 
200                         } elsif ( scalar(@tests) == 0 ) {
201                                 dbg ( "collectd: c:" . join(',', @tmp_array) . '\n' );
202                                 print $sock "c:" . join(',', @tmp_array) . "\n";
203                         }
204                 }
205                 close($sock); 
206                 alarm 0; 
207         };
208         if ($@) {
209                 my $message = $@; 
210                 chomp($message); 
211                 info("collectd: $message");
212                 return -1; 
213         }
216 1;
218 # vim: syntax=perl sw=4 ts=4 noet shiftround