1 #!/usr/bin/perl
2 # $Id: Collectd.pm 4 2006-12-02 15:18:14Z 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 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.
61 =cut
63 package Mail::SpamAssassin::Plugin::Collectd;
65 use Mail::SpamAssassin::Plugin;
66 use Mail::SpamAssassin::Logger;
67 use strict;
68 use bytes;
69 use warnings;
70 use IO::Socket;
72 use vars qw(@ISA);
73 @ISA = qw(Mail::SpamAssassin::Plugin);
75 sub new {
76 my ($class, $mailsa) = @_;
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);
83 # register our config options
84 $self->set_config($mailsa->{conf});
86 # and return the new plugin object
87 return $self;
88 }
90 sub set_config {
91 my ($self, $conf) = @_;
92 my @cmds = ();
94 push (@cmds, {
95 setting => 'collectd_buffersize',
96 default => 256,
97 type =>
98 $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
99 });
101 push (@cmds, {
102 setting => 'collectd_socket',
103 default => '/tmp/.collectd-email',
104 type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
105 });
107 $conf->{parser}->register_commands(\@cmds);
108 }
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);
125 my $score = $message_status->{score};
126 #get the size of the message
127 my $body = $message_status->{msg}->{pristine_body};
129 my $len = length($body);
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}};
141 my $buffersize = $self->{main}->{conf}->{collectd_buffersize};
142 dbg("collectd: buffersize: $buffersize");
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 }
166 1;
168 # vim: syntax=perl sw=4 ts=4 noet shiftround