6f1c0dc719f0823c5e6ab06f7d2a2df837250ce2
1 #!/usr/bin/perl
2 # $Id: Collectd.pm 7 2006-12-07 06:13:12Z formorer $
4 =head1 NAME
6 Collectd - plugin for filling collectd with stats
8 =head1 INSTALLATION
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.
14 =head1 SYNOPSIS
16 loadplugin Mail::SpamAssassin::Plugin::Collectd
18 =head1 USER SETTINGS
20 =over 4
22 =item collectd_socket [ socket path ] (default: /tmp/.collectd-email)
24 Where the collectd socket is
26 =cut
28 =item collectd_buffersize [ size ] (default: 256)
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.
35 =cut
36 =head1 DESCRIPTION
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
43 =head1 AUTHOR
45 Alexander Wirt <formorer@formorer.de>
47 =head1 COPYRIGHT
49 Copyright 2006 Alexander Wirt <formorer@formorer.de>
51 This program is free software; you can redistribute it and/or modify
52 it under the the terms of either:
54 a) the Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
56 or
58 b) the "Artistic License" which comes with perl
59 (http://www.perl.com/pub/a/language/misc/Artistic.html)
61 use whatever you like more.
63 =cut
65 package Mail::SpamAssassin::Plugin::Collectd;
67 use Mail::SpamAssassin::Plugin;
68 use Mail::SpamAssassin::Logger;
69 use strict;
70 use bytes;
71 use warnings;
72 use IO::Socket;
74 use vars qw(@ISA);
75 @ISA = qw(Mail::SpamAssassin::Plugin);
77 sub new {
78 my ($class, $mailsa) = @_;
80 # the usual perlobj boilerplate to create a subclass object
81 $class = ref($class) || $class;
82 my $self = $class->SUPER::new($mailsa);
83 bless ($self, $class);
85 # register our config options
86 $self->set_config($mailsa->{conf});
88 # and return the new plugin object
89 return $self;
90 }
92 sub set_config {
93 my ($self, $conf) = @_;
94 my @cmds = ();
96 push (@cmds, {
97 setting => 'collectd_buffersize',
98 default => 256,
99 type =>
100 $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
101 });
103 push (@cmds, {
104 setting => 'collectd_socket',
105 default => '/tmp/.collectd-email',
106 type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
107 });
109 push (@cmds, {
110 setting => 'collectd_timeout',
111 default => 2,
112 type =>
113 $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
114 });
116 $conf->{parser}->register_commands(\@cmds);
117 }
119 sub check_end {
120 my ($self, $params) = @_;
121 my $message_status = $params->{permsgstatus};
122 #create new connection to our socket
123 eval {
124 local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
125 die "alarm\n";
126 #generate a timeout
127 alarm $self->{main}->{conf}->{collectd_timeout};
129 my $sock = new IO::Socket::UNIX ( $self->{main}->{conf}->{collectd_socket});
130 # debug some informations if collectd is not running or anything else went
131 # wrong
132 if ( ! $sock ) {
133 dbg("collect: could not connect to " .
134 $self->{main}->{conf}->{collectd_socket} . ": $! - collectd plugin
135 disabled");
136 return 0;
137 }
138 $sock->autoflush(1);
140 my $score = $message_status->{score};
141 #get the size of the message
142 my $body = $message_status->{msg}->{pristine_body};
144 my $len = length($body);
146 if ($message_status->{score} >= $self->{main}->{conf}->{required_score} ) {
147 #hey we have spam
148 print $sock "e:spam:$len\n";
149 } else {
150 print $sock "e:ham:$len\n";
151 }
152 print $sock "s:$score\n";
153 my @tmp_array;
154 my @tests = @{$message_status->{test_names_hit}};
156 my $buffersize = $self->{main}->{conf}->{collectd_buffersize};
157 dbg("collectd: buffersize: $buffersize");
159 while (scalar(@tests) > 0) {
160 push (@tmp_array, pop(@tests));
161 if (length(join(',', @tmp_array) . '\n') > $buffersize) {
162 push (@tests, pop(@tmp_array));
163 if (length(join(',', @tmp_array) . '\n') > $buffersize or scalar(@tmp_array) == 0) {
164 dbg("collectd: this shouldn't happen. Do you have tests"
165 ." with names that have more than ~ $buffersize Bytes?");
166 return 1;
167 } else {
168 dbg ( "collectd: c:" . join(',', @tmp_array) . "\n" );
169 print $sock "c:" . join(',', @tmp_array) . "\n";
170 #clean the array
171 @tmp_array = ();
172 }
173 } elsif ( scalar(@tests) == 0 ) {
174 dbg ( "collectd: c:" . join(',', @tmp_array) . '\n' );
175 print $sock "c:" . join(',', @tmp_array) . "\n";
176 }
177 }
178 close($sock);
179 alarm 0;
180 };
181 if ($@ eq "alarm\n") {
182 info("Connection to collectd timed out");
183 return -1;
184 }
185 }
187 1;
189 # vim: syntax=perl sw=4 ts=4 noet shiftround