[Nagiosplug-devel] check_mailq: extended to multiqueue and source and destinations

Carlos Canau canau at keka.KPNQwest.pt
Thu Apr 10 09:52:07 CEST 2003


Dear all,

I've extended  check_mailq to support  multiqueues on sendmail  and to
check the  FROM's and TO's of the  messages in the queue  and to sound
the alarm if they are too many.

I've attached the code if somebody finds it interesting.

regards,
</canau

-------------- next part --------------
#!/usr/local/bin/perl -w

# check_mailq - check to see how many messages are in the smtp queue awating
#   transmittal. check for sources and destinations
#
# Initial version support sendmail's mailq command

# License Information:
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
############################################################################

use POSIX;
use strict;
use Getopt::Long;
use vars qw($opt_V $opt_h $opt_v $verbose $PROGNAME $opt_w $opt_c $opt_t $status $state $msg $msg_q $opt_W $opt_C %srcdomains %dstdomains);
use lib  utils.pm;
use utils qw(%ERRORS &print_revision &support &usage );

#my $MAILQ = "/usr/bin/mailq";   # need to migrate support to utils.pm and autoconf


sub print_help ();
sub print_usage ();
sub process_arguments ();

$ENV{'PATH'}='';
$ENV{'BASH_ENV'}=''; 
$ENV{'ENV'}='';
$PROGNAME = "check_mailq";

Getopt::Long::Configure('bundling');
$status = process_arguments();
if ($status){
	print "ERROR: processing arguments\n";
	exit $ERRORS{"UNKNOWN"};
}

$SIG{'ALRM'} = sub {
	print ("ERROR: timed out waiting for $utils::PATH_TO_MAILQ \n");
	exit $ERRORS{"WARNING"};
};
alarm($opt_t);

## open mailq 
if ( defined $utils::PATH_TO_MAILQ && -x $utils::PATH_TO_MAILQ ) {
	if (! open (MAILQ, "$utils::PATH_TO_MAILQ | " ) ) {
		print "ERROR: could not open $utils::PATH_TO_MAILQ \n";
		exit $ERRORS{'UNKNOWN'};
	}
}else{
	print "ERROR: Could not find mailq executable!\n";
	exit $ERRORS{'UNKNOWN'};
}

#  single queue empty
##/var/spool/mqueue is empty
#  single queue: 1
##                /var/spool/mqueue (1 request)
##----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------
##h32E30p01763     2782 Wed Apr  2 15:03 <joao.silva at kpnqwest.pt>
##      8BITMIME
##                                       <maria.silva at eunet.pt>

#  multi queue empty
##/var/spool/mqueue/q0/df is empty
##/var/spool/mqueue/q1/df is empty
##/var/spool/mqueue/q2/df is empty
##/var/spool/mqueue/q3/df is empty
##/var/spool/mqueue/q4/df is empty
##/var/spool/mqueue/q5/df is empty
##/var/spool/mqueue/q6/df is empty
##/var/spool/mqueue/q7/df is empty
##/var/spool/mqueue/q8/df is empty
##/var/spool/mqueue/q9/df is empty
##/var/spool/mqueue/qA/df is empty
##/var/spool/mqueue/qB/df is empty
##/var/spool/mqueue/qC/df is empty
##/var/spool/mqueue/qD/df is empty
##/var/spool/mqueue/qE/df is empty
##/var/spool/mqueue/qF/df is empty
##                Total Requests: 0
#  multi queue: 1
##/var/spool/mqueue/q0/df is empty
##/var/spool/mqueue/q1/df is empty
##/var/spool/mqueue/q2/df is empty
##                /var/spool/mqueue/q3/df (1 request)
##----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------
##h32De2f23534*      48 Wed Apr  2 14:40 nocol
##                                       nouser at EUnet.pt
##                                       canau
##/var/spool/mqueue/q4/df is empty
##/var/spool/mqueue/q5/df is empty
##/var/spool/mqueue/q6/df is empty
##/var/spool/mqueue/q7/df is empty
##/var/spool/mqueue/q8/df is empty
##/var/spool/mqueue/q9/df is empty
##/var/spool/mqueue/qA/df is empty
##/var/spool/mqueue/qB/df is empty
##/var/spool/mqueue/qC/df is empty
##/var/spool/mqueue/qD/df is empty
##/var/spool/mqueue/qE/df is empty
##/var/spool/mqueue/qF/df is empty
##                Total Requests: 1

$msg_q = 0 ;
while (<MAILQ>) {
    if ( (/<.*@.*\.(\w+\.\w+)>/) || (/<.*@(\w+\.\w+)>/) ) {
	my $domain = $1;
	if (/^\w+/) {
	    print "$utils::PATH_TO_MAILQ = srcdomain = $domain \n" if $verbose ;
	    $srcdomains{$domain} ++;
	}
###	else { ### see comment below. this code counts messages in queue like sendmail
###            $dstdomains{$domain} ++;
###        }

	next;
    }
    #
    # ...
    # sendmail considers a message with more than one destiny, say N, to the same MX 
    # to have N messages in queue.
    # we will only consider one in this code
    if (( /\s\(reply:\sread\serror\sfrom\s.*\.(\w+\.\w+)\.$/ ) || ( /\s\(reply:\sread\serror\sfrom\s(\w+\.\w+)\.$/ ) ||
	( /\s\(timeout\swriting\smessage\sto\s.*\.(\w+\.\w+)\.:/ ) || ( /\s\(timeout\swriting\smessage\sto\s(\w+\.\w+)\.:/ ) ||
	( /\s\(host\smap:\slookup\s\(.*\.(\w+\.\w+)\):/ ) || ( /\s\(host\smap:\slookup\s\((\w+\.\w+)\):/ ) || 
	( /\s\(Deferred:\s.*\s.*\.(\w+\.\w+)\.\)/ ) || ( /\s\(Deferred:\s.*\s(\w+\.\w+)\.\)/ ) ) {
	print "$utils::PATH_TO_MAILQ = dstdomain = $1 \n" if $verbose ;
	$dstdomains{$1} ++;
    }
    if (/\s+\(I\/O\serror\)/) {
	print "$utils::PATH_TO_MAILQ = dstdomain = UNKNOWN \n" if $verbose ;
	$dstdomains{'UNKNOWN'} ++;
    }
    # ...
    # 
    if (/mqueue/) {
	print "$utils::PATH_TO_MAILQ = $_ \n" if $verbose ;
	if (/ \((\d+) request/) {
	    #
	    # single queue: first line
	    # multi queue: one for each queue. overwrite on multi queue below
	    $msg_q = $1 ;
	}
    } elsif (/^\s+Total\sRequests:\s(\d+)$/) {
	print "$utils::PATH_TO_MAILQ = $_ \n" if $verbose ;
	#
	# multi queue: last line
	$msg_q = $1 ;
    }
}

if ($msg_q == 0) {
    $msg = "OK: mailq is empty";
    $state = $ERRORS{'OK'};
} else {
    print "msg_q = $msg_q warn=$opt_w crit=$opt_c\n" if $verbose;

    if ($msg_q < $opt_w) {
	$msg = "OK: mailq ($msg_q) is below threshold ($opt_w/$opt_c)";
	$state = $ERRORS{'OK'};
    }elsif ($msg_q >= $opt_w  && $msg_q < $opt_c) {
	$msg = "WARNING: mailq is $msg_q (threshold w = $opt_w)";
	$state = $ERRORS{'WARNING'};
    }else {
	$msg = "CRITICAL: mailq is $msg_q (threshold c = $opt_c)";
	$state = $ERRORS{'CRITICAL'};
    }

    my @srckeys = sort { $srcdomains{$b} <=> $srcdomains{$a} } keys %srcdomains;
    my $srcmaxkey = $srckeys[0];
    print "src max is $srcmaxkey with $srcdomains{$srcmaxkey} messages\n" if $verbose;
    if ($srcdomains{$srcmaxkey} >= $opt_W && $srcdomains{$srcmaxkey} < $opt_C) {
	if ($state == $ERRORS{'OK'}) {
	    $msg = "WARNING: $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'WARNING'};
	} elsif (($state == $ERRORS{'WARNING'}) || ($state == $ERRORS{'CRITICAL'})){
	    $msg .= " -and- $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold W = $opt_W)";
	} else {
	    $msg = "WARNING: $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'WARNING'};
	}
    } elsif ($srcdomains{$srcmaxkey} >= $opt_C) {
	if ($state == $ERRORS{'OK'}) {
	    $msg = "CRITICAL: $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold C = $opt_C)";
	    $state = $ERRORS{'CRITICAL'};
	} elsif ($state == $ERRORS{'WARNING'}) {
	    $msg = "CRITICAL: $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold C = $opt_C) -and- " . $msg;
	    $msg =~ s/WARNING: //;
	} elsif ($state == $ERRORS{'CRITICAL'}) {
	    $msg .= " -and- $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold W = $opt_W)";
	} else {
	    $msg = "CRITICAL: $srcdomains{$srcmaxkey} messages in queue FROM $srcmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'CRITICAL'};
	}
    } else {
	if ($srcdomains{$srcmaxkey} > 0) {
	    $msg .= " $srcdomains{$srcmaxkey} msgs. FROM $srcmaxkey is below threshold ($opt_W/$opt_C)";
	}
    }

    my @dstkeys = sort { $dstdomains{$b} <=> $dstdomains{$a} } keys %dstdomains;
    my $dstmaxkey = $dstkeys[0];
    print "dst max is $dstmaxkey with $dstdomains{$dstmaxkey} messages\n" if $verbose;
    if ($dstdomains{$dstmaxkey} >= $opt_W && $dstdomains{$dstmaxkey} < $opt_C) {
	if ($state == $ERRORS{'OK'}) {
	    $msg = "WARNING: $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'WARNING'};
	} elsif (($state == $ERRORS{'WARNING'}) || ($state == $ERRORS{'CRITICAL'})){
	    $msg .= " -and- $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold W = $opt_W)";
	} else {
	    $msg = "WARNING: $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'WARNING'};
	}
    } elsif ($dstdomains{$dstmaxkey} >= $opt_C) {
	if ($state == $ERRORS{'OK'}) {
	    $msg = "CRITICAL: $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold C = $opt_C)";
	    $state = $ERRORS{'CRITICAL'};
	} elsif ($state == $ERRORS{'WARNING'}) {
	    $msg = "CRITICAL: $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold C = $opt_C) -and- " . $msg;
	    $msg =~ s/WARNING: //;
	} elsif ($state == $ERRORS{'CRITICAL'}) {
	    $msg .= " -and- $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold W = $opt_W)";
	} else {
	    $msg = "CRITICAL: $dstdomains{$dstmaxkey} messages in queue TO $dstmaxkey (threshold W = $opt_W)";
	    $state = $ERRORS{'CRITICAL'};
	}
    } else {
	if ($dstdomains{$dstmaxkey} > 0) {
	    $msg .= " $dstdomains{$dstmaxkey} msgs. TO $dstmaxkey is below threshold ($opt_W/$opt_C)";
	}
    }
}

close (MAILQ); 
# declare an error if we also get a non-zero return code from mailq
# unless already set to critical
if ( $? ) {
	print "stderr = $? : $! \n" if $verbose;
	$state = $state == $ERRORS{"CRITICAL"} ? $ERRORS{"CRITICAL"} : $ERRORS{"UNKNOWN"}  ;
	print "MAILQ error: $!\n" if $verbose;
}
## close mailq

# Perfdata support
print "$msg | mailq = $msg_q\n";
exit $state;


#####################################
#### subs


sub process_arguments(){
	GetOptions
		("V"   => \$opt_V, "version"	=> \$opt_V,
		 "v"   => \$opt_v, "verbose"	=> \$opt_v,
		 "h"   => \$opt_h, "help"		=> \$opt_h,
		 "w=i" => \$opt_w, "warning=i"  => \$opt_w,   # warning if above this number
		 "c=i" => \$opt_c, "critical=i" => \$opt_c,	  # critical if above this number
		 "W=i" => \$opt_W, "Warning=i"  => \$opt_W,   # warning if above this number
		 "C=i" => \$opt_C, "Critical=i" => \$opt_C,	  # critical if above this number
		 "t=i" => \$opt_t, "timeout=i"  => \$opt_t 
		 );

	if ($opt_V) {
		print_revision($PROGNAME,'$Revision: 1.1 $ ');
		exit $ERRORS{'OK'};
	}

	if ($opt_h) {
		print_help();
		exit $ERRORS{'OK'};
	}

	if (defined $opt_v ){
		$verbose = $opt_v;
	}

	unless (defined $opt_t) {
		$opt_t = $utils::TIMEOUT ;	# default timeout
	}

	unless ( defined $opt_w &&  defined $opt_c ) {
		print_usage();
		exit $ERRORS{'UNKNOWN'};
	}
	unless ( defined $opt_W &&  defined $opt_W ) {
		print_usage();
		exit $ERRORS{'UNKNOWN'};
	}

	if ( $opt_w >= $opt_c) {
		print "Warning cannot be greater than Critical!\n";
		exit $ERRORS{'UNKNOWN'};
	}
	if ( $opt_W >= $opt_C) {
		print "Warning cannot be greater than Critical!\n";
		exit $ERRORS{'UNKNOWN'};
	}

	return $ERRORS{'OK'};
}

sub print_usage () {
	print "Usage: $PROGNAME [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>] [-t <timeout>] [-v verbose]\n";
}

sub print_help () {
	print_revision($PROGNAME,'$Revision: 1.1 $');
	print "Copyright (c) 2002 Subhendu Ghosh\n";
	print "\n";
	print_usage();
	print "\n";
	print "   Checks the number of messages in the mail queue\n";
	print "   Feedback/patches to support non-sendmail mailqueue welcome\n\n";
	print "-w (--warning)   = Min. number of messages in queue to generate warning\n";
	print "-c (--critical)  = Min. number of messages in queue to generate critical alert ( w < c )\n";
	print "-W (--Warning)   = Min. number of messages for same domain in queue to generate warning\n";
	print "-C (--Critical)  = Min. number of messages for same domain in queue to generate critical alert ( W < C )\n";
	print "-t (--timeout)   = Plugin timeout in seconds (default = $utils::TIMEOUT)\n";
	print "-h (--help)\n";
	print "-V (--version)\n";
	print "-v (--verbose)   = debugging output\n";
	print "\n\n";
	support();
}


More information about the Devel mailing list