#!/usr/bin/perl # # Written by Gene Cutler, February 2011 # Loosely based on postfix_mailstats # Graphs various qpsmtpd responses (greylisting, bad recipient, bad sender, etc.) # # config: # [qpsmtpd_mailstats] # env.logfile - Full path to qpsmtpd logfile, default = '/var/log/qpsmtpd/qpsmtpd.log' # # Parameters understood: # # config (required) # autoconf (optional - used by munin-config) # # #%# family=auto use strict; my $LOGFILE = $ENV{'logfile'} || '/var/log/qpsmtpd/qpsmtpd.log'; my $STATEFILE= $ENV{MUNIN_PLUGSTATE} . '/qpsmtpd_mailstats.state'; my $LINE_N = 0; my %REJECT_CODES = ( 250 => '250 queued', 450 => '450 greylisted', 451 => '451 bad recipient', 501 => '501 bad sender', 503 => '503 MAIL first', 550 => '550 bad dnsbl', 554 => '554 spamtrap', ); if (defined($ARGV[0]) and ($ARGV[0] eq 'config')) { do_config(); exit(0); } $LINE_N = get_state(); $LINE_N ||= 0; sub get_state { my $fh; open $fh,$STATEFILE; $_ = <$fh>; close $fh; /^(\d+)$/; return $1; } sub save_state { my $n = shift; my $fh; open $fh, ">$STATEFILE"; print $fh "$n\n"; close $fh; } do_stats($LINE_N); sub do_stats { my $start_at = shift; my $fh; my $stop_at = (stat $LOGFILE)[7]; $start_at = 0 if $stop_at < $start_at; my %counts = (); open $fh, $LOGFILE or die "$!: $LOGFILE"; seek $fh, $start_at, 0 if $start_at > 0; my $where; while (($where = tell $fh) < $stop_at) { my $line = <$fh>; if ($line =~ /: 250 Queued!/) { $counts{'250'}++; } elsif ($line =~ /: (\d+)/ and defined $REJECT_CODES{$1}) { $counts{$1}++; } } close $fh; save_state($stop_at); foreach my $rc (sort {$a<=>$b} keys %REJECT_CODES) { $counts{$rc} ||= 0; print "r$rc.value $counts{$rc}\n"; } } sub do_config { my $k; print "graph_title QPSMTPD Responses graph_category mail graph_args --base 1000 -l 0 graph_vlabel responses / \${graph_period} graph_scale no graph_period minute graph_total Total "; get_state(); my $type; foreach $k (sort {$a<=>$b} keys %REJECT_CODES) { print "r$k.label $REJECT_CODES{$k} r$k.type ABSOLUTE r$k.min 0 r$k.draw AREASTACK "; } }; # vim:syntax=perl