#!/usr/bin/perl -w =encoding utf8 =head1 NAME courier_mta_mailstats - Plugin to monitor the number of mails delivered and rejected by courier-mta. =head1 CONFIGURATION The following environment variables are used: logdir - Where to find logfiles (default "/var/log") logfile - What file to read in logdir (default "mail.log") courier - Path to "courier" (default "/usr/sbin/courier") =head1 AUTHOR Rune Nordbøe Skillingstad =head1 LICENSE Unknown =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =cut my $statefile = "$ENV{MUNIN_PLUGSTATE}/munin-plugin-courier_mta_mailstats.state"; my $pos = undef; my $delivered = 0; my $rejects = {}; my $LOGDIR = $ENV{'logdir'} || '/var/log'; my $LOGFILE = $ENV{'logfile'} || 'mail.log'; my $COURIER = $ENV{'courier'} || '/usr/sbin/courier'; if ( $ARGV[0] and $ARGV[0] eq "autoconf" ) { my $logfile; if(-x $COURIER) { if(-d $LOGDIR) { $logfile = "$LOGDIR/$LOGFILE"; if(-f $logfile) { if(-r "$logfile") { print "yes\n"; exit 0; } else { print "no (logfile not readable)\n"; } } else { print "no (logfile not found)\n"; } } else { print "no (could not find logdir)\n"; } } else { print "no (could not find executable)\n"; } exit 0; } my $logfile = "$LOGDIR/$LOGFILE"; my $prevdate = get_prev_date(); if(-f "$logfile.$prevdate") { $rotlogfile = "$logfile.$prevdate"; } elsif (-f "$logfile.0") { $rotlogfile = $logfile . ".0"; } elsif (-f "$logfile.1") { $rotlogfile = $logfile . ".1"; } elsif (-f "$logfile.01") { $rotlogfile = $logfile . ".01"; } else { $rotlogfile = $logfile . ".0"; } if(-f "$statefile") { open (IN, "$statefile") or exit 4; if( =~ /^(\d+):(\d+)/) { ($pos, $delivered) = ($1, $2); } while () { if (/^(\d+):(\d+)$/) { $rejects->{$1} = $2; } } close IN; } if(! -f $logfile and ! -f $rotlogfile) { print "delivered.value U\n"; foreach my $i (keys %{$rejects}) { print "r$i.value U\n"; } exit 0; } $startsize = (stat $logfile)[7]; if(!defined $pos) { # Initial run. $pos = $startsize; } if($startsize < $pos) { # Log rotated parseLogfile ($rotlogfile, $pos, (stat $rotlogfile)[7]); $pos = 0; } parseLogfile ($logfile, $pos, $startsize); $pos = $startsize; if($ARGV[0] and $ARGV[0] eq "config") { print "graph_title Courier MTA mail throughput\n"; print "graph_category mail\n"; print "graph_args --base 1000 -l 0\n"; print "graph_vlabel mails / \${graph_period}\n"; print "graph_scale no\n"; print "graph_total Total\n"; print "delivered.label delivered\n"; print "delivered.type DERIVE\n"; print "delivered.draw AREA\n"; print "delivered.min 0\n"; foreach my $i (keys %{$rejects}) { print "r$i.label reject $i\n"; print "r$i.type DERIVE\n"; print "r$i.draw STACK\n"; print "r$i.min 0\n"; } exit 0; } print "delivered.value $delivered\n"; foreach my $i (keys %{$rejects}) { print "r$i.value ", $rejects->{$i}, "\n"; } if(-l $statefile) { die("$statefile is a symbolic link, refusing to touch it."); } open (OUT, ">$statefile") or exit 4; print OUT "$pos:$delivered\n"; foreach my $i (keys %{$rejects}) { print OUT "$i:", $rejects->{$i}, "\n"; } close OUT; sub parseLogfile { my ($fname, $start, $stop) = @_; open (LOGFILE, $fname) or exit 3; seek (LOGFILE, $start, 0) or exit 2; while (tell (LOGFILE) < $stop) { my $line =; chomp ($line); if($line =~ /(?:courierlocal|courieresmtp): id=.*,from=.*,addr=.*,size=\d+,success:.*delivered/) { $delivered++; } elsif($line =~ /courieresmtpd: error,relay=.*(?:\d{1,3}\.){3}\d{1,3},from=[^:]+: (\d{3})/) { $rejects->{$1} ++; } } close(LOGFILE); } sub get_prev_date { my @date = localtime (time - 86400); my $prevdate = $date[5]+1900 . $date[4]+1 . $date[3]; return $prevdate; }