Merge branch 'master' of octo@verplant.org:/var/lib/git/collectd
[collectd.git] / contrib / SpamAssassin / Collectd.pm
1 #!/usr/bin/perl
2 # $Id: Collectd.pm 4 2006-12-02 15:18:14Z 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  Licensed under the Apache License,  Version 2.0 (the "License"); 
52  you may not use this file except in compliance
53  with the License. You may obtain a copy of the License at
54  http://www.apache.org/licenses/LICENSE-2.0 Unless required 
55  by applicable law or agreed to in writing, software distributed 
56  under the License is distributed on an "AS IS" BASIS, WITHOUT 
57  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
58  See the License for the specific language governing permissions 
59  and limitations under the License.
60
61 =cut
62
63 package Mail::SpamAssassin::Plugin::Collectd;
64
65 use Mail::SpamAssassin::Plugin;
66 use Mail::SpamAssassin::Logger;
67 use strict;
68 use bytes; 
69 use warnings;
70 use IO::Socket;
71
72 use vars qw(@ISA);
73 @ISA = qw(Mail::SpamAssassin::Plugin);
74
75 sub new {
76     my ($class, $mailsa) = @_;
77
78     # the usual perlobj boilerplate to create a subclass object
79     $class = ref($class) || $class;
80     my $self = $class->SUPER::new($mailsa);
81     bless ($self, $class);
82
83     # register our config options
84     $self->set_config($mailsa->{conf});
85
86     # and return the new plugin object
87     return $self;
88 }
89
90 sub set_config {
91     my ($self, $conf) = @_;
92     my @cmds = ();
93
94     push (@cmds, {
95             setting => 'collectd_buffersize',
96             default => 256,
97             type =>
98             $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
99         });
100
101     push (@cmds, {
102             setting => 'collectd_socket', 
103             default => '/tmp/.collectd-email',
104             type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
105     });
106
107     $conf->{parser}->register_commands(\@cmds);
108 }
109
110 sub check_end {
111     my ($self, $params) = @_;
112     my $message_status = $params->{permsgstatus};
113         #create  new connection to our socket
114         my $sock = new IO::Socket::UNIX ( $self->{main}->{conf}->{collectd_socket});
115         # debug some informations if collectd is not running or anything else went
116         # wrong
117         if ( ! $sock ) {
118                 dbg("collect: could not connect to " .
119                         $self->{main}->{conf}->{collectd_socket} . ": $! - collectd plugin
120                         disabled"); 
121                 return 0; 
122         }
123         $sock->autoflush(1);
124
125         my $score = $message_status->{score};
126         #get the size of the message 
127         my $body = $message_status->{msg}->{pristine_body};
128
129         my $len = length($body);
130
131         if ($message_status->{score} >= $self->{main}->{conf}->{required_score} ) {
132                 #hey we have spam
133                 print $sock "e:spam:$len\n";
134         } else {
135                 print $sock "e:ham:$len\n";
136         }
137         print $sock "s:$score\n";
138         my @tmp_array; 
139         my @tests = @{$message_status->{test_names_hit}};
140
141         my $buffersize = $self->{main}->{conf}->{collectd_buffersize}; 
142         dbg("collectd: buffersize: $buffersize"); 
143
144         while  (scalar(@tests) > 0) {
145          push (@tmp_array, pop(@tests)); 
146                 if (length(join(',', @tmp_array) . '\n') > $buffersize) {
147                         push (@tests, pop(@tmp_array)); 
148                                 if (length(join(',', @tmp_array) . '\n') > $buffersize or scalar(@tmp_array) == 0) {
149                                         dbg("collectd: this shouldn't happen. Do you have tests"
150                                                 ." with names that have more than ~ $buffersize Bytes?");
151                                         return 1; 
152                                 } else {
153                                         dbg ( "collectd: c:" . join(',', @tmp_array) . "\n" ); 
154                                         print $sock "c:" . join(',', @tmp_array) . "\n"; 
155                                         #clean the array
156                                         @tmp_array = ();
157                                 } 
158                 } elsif ( scalar(@tests) == 0 ) {
159                         dbg ( "collectd: c:" . join(',', @tmp_array) . '\n' );
160                         print $sock "c:" . join(',', @tmp_array) . "\n";
161                 }
162         }
163         close($sock); 
164 }
165
166 1;
167
168 # vim: syntax=perl sw=4 ts=4 noet shiftround