#!/usr/bin/perl =head1 NAME mailman - Plugin to monitor activity on mailman mailing list management systems =head1 CONFIGURATION Configuration for this plugin depends on the mailman's settings on the system. Here are the defaults: [mailman] env.logfile /var/log/mailman/post env.libdir /var/lib/mailman env.lister /usr/lib/mailman/bin/list_members =head1 AUTHOR Author unknown. Source code strongly related to the Exim plugin of old. =head1 LICENSE License unknown =head1 MAGIC MARKERS #%# family=contrib #%# capabilities=autoconf =cut $statefile = "$ENV{MUNIN_PLUGSTATE}/munin-mailman-log.state"; $pos = undef; $posts = 0; $members = 0; # System paths $logfile = $ENV{'logfile'} || "/var/log/mailman/post"; $libdir = $ENV{'libdir'} || "/var/lib/mailman"; $lister = $ENV{'lister'} || "/usr/lib/mailman/bin/list_members"; if (-f "$logfile.0") { $rotlogfile = $logfile . ".0"; } elsif (-f "$logfile.1") { $rotlogfile = $logfile . ".1"; } elsif (-f "$logfile.01") { $rotlogfile = $logfile . ".01"; } else { $rotlogfile = undef; } if($ARGV[0] and $ARGV[0] eq "config") { print "graph_title Mailman usage\n"; print "graph_args --base 1000\n"; print "graph_category mailinglist\n"; print "posts.label posts per minute\n"; print "posts.type DERIVE\n"; print "posts.min 0\n"; print "members.label members\n"; print "members.type GAUGE\n"; exit 0; } if($ARGV[0] and $ARGV[0] eq "autoconf") { if(-f $logfile && -d $libdir && -x $lister ) { print "yes\n"; } else { print "no (can not find file $logfile or dir $libdir or executable $lister)\n"; } exit 0; } if(! -f $logfile && ! -d $libdir && ! -x $lister) { print "posts.value U\n"; print "posts.extinfo Can't find any log files\n"; print "members.value U\n"; exit 0; } if(-f $statefile) { open(IN, "<$statefile") or die "Can't open $statefile for reading: $!"; if( =~ /^(\d+):(\d+)/) { ($pos,$posts) = ($1, $2); } close(IN); } $startsize = (stat $logfile)[7]; if(!defined $pos) { # Initial run. $pos = $startsize; $startsize = 0; } elsif($startsize < $pos) { # Log rotated if(defined $rotlogfile) { parseMailmanLog($rotlogfile, $pos, (stat $rotlogfile)[7]); } $pos = 0; } parseMailmanLog($logfile, $pos, $startsize); $pos = $startsize; parseMailmanLists(); print "posts.value $posts\n"; print "members.value $members\n"; open (OUT, ">$statefile") or die "Can't open $statefile for writing: $!"; print OUT "$pos:$posts\n"; close OUT; sub parseMailmanLog { my($fname, $start, $stop) = @_; open(LOGFILE, $fname) or die "Can't open $fname for reading: $!"; seek(LOGFILE, $start, 0) or die "Can't seek in $fname: $!"; while(tell(LOGFILE) < $stop) { my $line = ; if($line =~ / post to/) { $posts++; } } close(LOGFILE); } sub parseMailmanLists { my @domains = &mailmanDomains; for(my $i = 0; $i < @domains; $i++) { my @lists = &mailmanLists($domains[$i]); for(my $j = 0; $j < @lists; $j++) { $members += &mailmanMembers($domains[$i], $lists[$j]); } } } sub mailmanDomains { my @domains; if (-e "$libdir/data") { @domains = ("."); } else { opendir(DOMAINS, $libdir) or die "Can't open directory $libdir for reading: $!"; @domains = grep ( { !/^\@/ && !/^\./ && -d "$libdir/$_" } readdir(DOMAINS) ); closedir(DOMAINS); } return @domains; } sub mailmanLists { my ($domain) = @_; opendir(LISTS, "$libdir/$domain/lists") or die "Can't open directory $libdir/$domain/lists for reading: $!"; my @lists = grep ( { !/^\@/ && !/^\./ && -d "$libdir/$domain/lists/$_" } readdir(LISTS) ); closedir(LISTS); return @lists; } sub mailmanMembers { my ($domain, $list) = @_; return 0 unless $domain; return 0 unless $list; my $cnt = 0; open(MEMBERS, "DOMAIN=$domain $lister $list|") or die "Cannot execute pipe: $lister $list: $!"; while() { $cnt++; } close(MEMBERS); return $cnt; }