#! /usr/bin/perl # Copyright (C) 2008 Joey Schulze # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 dated June, 1991. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. # Rewrite of the postfix_mailstats plugin with Munin::Plugin # Source: http://www.infodrom.org/Infodrom/tools/munin.html # Supported configuration: # # [postfix_mailstats] # user root # group adm # env.logdir /var/log # env.logfile mail.log use strict; use warnings; use Munin::Plugin; my $LOGDIR = $ENV{'logdir'} || '/var/log'; my $LOGFILE = $ENV{'logfile'} || 'mail.log'; my $logfile = $LOGDIR .'/'. $LOGFILE; my $delivered; my %rejects; sub autoconf { if (-d $LOGDIR) { if (-f $logfile) { if (open(my $f, $logfile)) { while (<$f>) { if (m,postfix/smtpd\[\d+\]: ,) { close $f; print "yes\n"; exit 0; } } print "no (no smtpd logs in logfile)\n"; close $f; } else { print "no (logfile not readable)\n"; } } else { print "no (logfile not found)\n"; } } else { print "no (could not find logdir)\n"; } exit 0; } sub config { print "graph_title Postfix message throughput\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 "graph_category mail\n"; print "delivered.label delivered\n"; print "delivered.type ABSOLUTE\n"; print "delivered.draw AREA\n"; print "delivered.min 0\n"; foreach my $code (sort keys %rejects) { my $name = clean_fieldname('reject ' . $code); printf "%s.label reject %d\n", $name, $code; printf "%s.type ABSOLUTE\n", $name; printf "%s.draw STACK\n", $name; printf "%s.min 0\n", $name; } exit 0; } sub parse { my $logfile = shift; my $pos = shift; my ($log,$rotated) = tail_open $logfile, $pos; while (<$log>) { if (m,.* postfix/smtpd\[\d+\]: NOQUEUE: reject: [^:]+: (\d+) .*,) { $rejects{$1}++; next; } elsif (m/qmgr.*from=.*size=[0-9]*/) { $delivered++; next; } } return tail_close $log; } autoconf if $#ARGV > -1 && $ARGV[0] eq "autoconf"; my @state_vector = restore_state; my $pos = shift @state_vector || 0; my $time = shift @state_vector; $delivered = shift @state_vector || 0; %rejects = @state_vector; config if $#ARGV > -1 && $ARGV[0] eq "config"; if (defined $time) { if ($time < time-(60*5)+15) { $delivered = 0; $rejects{$_} = 0 foreach keys %rejects; $pos = parse $logfile, $pos; save_state $pos, time, $delivered, %rejects; } } else { # Prevent start peak $pos = (stat $logfile)[7]; save_state $pos, time, $delivered; exit 0; } printf "delivered.value %d\n", $delivered; foreach my $code (sort keys %rejects) { printf "%s.value %d\n", clean_fieldname('reject ' . $code), $rejects{$code}; }