PageRenderTime 37ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/SpamAssassin/Collectd.pm

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