From 29e732d7ee389a3a96c4181fb46565a2b9ae795c Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Tue, 7 Jan 2014 17:13:40 +0100 Subject: [PATCH] Add new plugin : postfwd2 --- plugins/mail/postfwd2 | 269 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100755 plugins/mail/postfwd2 diff --git a/plugins/mail/postfwd2 b/plugins/mail/postfwd2 new file mode 100755 index 00000000..e1967d71 --- /dev/null +++ b/plugins/mail/postfwd2 @@ -0,0 +1,269 @@ +#!/usr/bin/perl +# vim: set filetype=perl sw=4 tabstop=4 expandtab smartindent: # + +=head1 NAME + + postfwd2 - plugin to get stats from postfwd2 + +=head1 AUTHOR AND COPYRIGHT + + Copyright 2013 Luc Didry + +=head1 HOWTO CONFIGURE AND USE : + +=over + +=item - /etc/munin/plugin-conf.d/postfwd2 + + [postfwd2] + user root + env.path /usr/local/sbin/postfwd2 # OPTIONAL : looks for postfwd2 in /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin + env.include .*ISBAD #OPTIONAL + env.exclude .*ISGOOD #OPTIONAL + +=item - env.include and env.exclude + + This are perl regexp. + If env.include is set and env.exclude is not, only the policy which name + matchs will be used. + If env.exclude is set and env.include is not, only the policy which name NOT + matchs will be used. + If both are set, a policy which name matchs the both regex will be used, a + policy which matchs only the exclude regexp will NOT be used and a policy + which match not the exclude regex will be used, even if it not matchs the + include regexp. + if none are set, all the policy will be used. + + +=item - /etc/munin/plugins + + cp postfwd2 /etc/munin/plugins + + +=item - restart Munin node + + service munin-node restart + +=back + +=head1 LICENSE + + 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 3 of the License, or 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, see . + +=cut + +use warnings; +use strict; +use Munin::Plugin; + +need_multigraph(); + +my @keys =qw/cache_queries cache_stats policy_requests policy_timeout policy_matchs/; +my %graphs = ( + cache_queries => { + title => 'Cache queries', + vlabel => 'Nb of cache queries', + series => { + cache_queries => { + label => 'Cache queries', + type => 'COUNTER' + } + }, + }, + cache_stats => { + title => 'Cache stats', + vlabel => 'percent', + series => { + cache_requests => { + label => 'Requests hitrate', + type => 'GAUGE' + }, + cache_dns => { + label => 'Dns hitrate', + type => 'GAUGE' + }, + cache_rates => { + label => 'Rates hitrate', + type => 'GAUGE' + } + }, + }, + policy_requests => { + title => 'Policy requests', + vlabel => 'Nb of policy requests', + series => { + policy_requests => { + label => 'Policy requests', + type => 'COUNTER' + } + }, + }, + policy_timeout => { + title => 'Policy timeout', + vlabel => 'Nb of policy timeout', + series => { + policy_timeout => { + label => 'Policy timeout', + type => 'COUNTER' + } + } + }, + policy_matchs => { + title => 'Policy matchs', + vlabel => 'Matchs percentage' + } +); + +my $PLUGIN_NAME = 'postfwd2'; +my $CACHEFILE="$Munin::Plugin::pluginstatedir/postfwd2.cache"; + +my ($include, $exclude) = ($ENV{include}, $ENV{exclude}); +if (defined($include) && (!defined($exclude))) { + $exclude = '.*'; +} + +##### Cache file, to continue to graph old policies which doesn't exist anymore +if (!(-f $CACHEFILE) || !(-e $CACHEFILE)) { + open (FILE, ">", $CACHEFILE) or munin_exit_fail(); + close(FILE); +} +open (FILE, "<", $CACHEFILE) or munin_exit_fail(); +my @policies = ; +close(FILE); +my %policies = map { $_, 1 } @policies; +foreach my $policy (keys %policies) { + chomp $policy; + $graphs{policy_matchs}->{series}->{$policy}->{type} = 'GAUGE'; + $graphs{policy_matchs}->{series}->{$policy}->{label} = $policy; + $graphs{policy_matchs}->{series}->{$policy}->{value} = 0; +} + +##### Check postfwd2 path +if (!defined($ENV{path}) || !(-x $ENV{path})) { + foreach my $path (qw{/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin}) { + $ENV{path} = $path.'/postfwd2' if (!defined($ENV{path}) && -x $path.'/postfwd2'); + last if (defined($ENV{path})); + } +} +munin_exit_fail() unless (defined($ENV{path}) && -x $ENV{path}); + +##### I have to parse the output BEFORE config, since policy matchs are dependant of the postfwd --dumpstats output +open(DATA, $ENV{path}.' --dumpstats |') or munin_exit_fail(); +my $total_requests; +while(defined (my $data = )) { + if ($data =~ m/^\[STATS\] postfwd2::cache .*: (\d+) queries since/) { + $graphs{cache_queries}->{series}->{cache_queries}->{value} = $1; + } + if ($data =~ m/^\[STATS\] Hitrates: ([\.\d]+)% requests, ([\.\d]+)% dns, ([\.\d]+)% rates$/) { + $graphs{cache_stats}->{series}->{cache_requests}->{value} = $1; + $graphs{cache_stats}->{series}->{cache_dns}->{value} = $2; + $graphs{cache_stats}->{series}->{cache_rates}->{value} = $3; + } + if ($data =~ m/^\[STATS\] postfwd2::policy .*: (\d+) requests since/) { + $graphs{policy_requests}->{series}->{policy_requests}->{value} = $1; + $total_requests = $1; + } + if ($data =~ m/^\[STATS\] Timeouts: .*% \((\d+) of \d+ dns queries\)$/) { + $graphs{policy_timeout}->{series}->{policy_timeout}->{value} = $1; + } + if ($data =~ m/^\[STATS\] +(\d+) matches for id: (.*)$/) { + my ($value, $label) = ($1, $2); + if ( ( !defined($exclude) ) || ( $label !~ m/$exclude/ || ( defined($include) && $label =~ m/$include/ ) ) ) { + if (!defined($policies{$label})) { + open (FILE, ">>", $CACHEFILE) or munin_exit_fail(); + print FILE $label, "\n"; + close(FILE); + $graphs{policy_matchs}->{series}->{$label}->{type} = 'GAUGE'; + $graphs{policy_matchs}->{series}->{$label}->{label} = $label; + } + $graphs{policy_matchs}->{series}->{$label}->{value} = sprintf("%.2f", 100*$value/$total_requests); + } + } +} +close(DATA); + +##### config +if( (defined $ARGV[0]) && ($ARGV[0] eq 'config') ) { + foreach my $key (@keys) { + print 'multigraph postfwd2_', $key, "\n"; + print 'graph_title Postfwd2 ', $graphs{$key}->{title}, "\n"; + print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n"; + my $args = ($key eq 'cache_stats') ? ' --upper-limit 100 --rigid' : ''; + print 'graph_args --lower-limit 0', $args, "\n"; + print 'graph_category mail', "\n"; + if ($key eq 'policy_matchs') { + print 'graph_width 600', "\n"; + my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}}; + foreach my $label (@pol_keys) { + print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n"; + print $label, '.draw LINE', "\n"; + print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n"; + } + foreach my $label (@pol_keys) { + print 'multigraph postfwd2_', $key, '.', $label, "\n"; + print 'graph_title Postfwd2 ', $label, "\n"; + print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n"; + print 'graph_width 600', "\n"; + print 'graph_args --lower-limit 0 ', $args, "\n"; + print 'graph_category others', "\n"; + print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n"; + print $label, '.draw LINE', "\n"; + print $label, '.type GAUGE', "\n"; + } + } else { + foreach my $label (keys %{$graphs{$key}->{series}}) { + print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n"; + print $label, '.draw AREASTACK', "\n"; + print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n"; + } + } + } + munin_exit_done(); +} + +##### fetch +foreach my $key (@keys) { + print 'multigraph postfwd2_', $key, "\n"; + if ($key eq 'policy_matchs') { + my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}}; + foreach my $label (@pol_keys) { + print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n"; + } + foreach my $label (@pol_keys) { + print 'multigraph postfwd2_', $key, '.', $label, "\n"; + print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n"; + } + } else { + foreach my $label (keys %{$graphs{$key}->{series}}) { + print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n"; + } + } +} +munin_exit_done(); + +# +## +### INTERNALS FONCTIONS +############################################################################### +sub munin_exit_done { + munin_exit(0); +} ## sub munin_exit_done + +sub munin_exit_fail { + munin_exit(1); +} ## sub munin_exit_fail + +sub munin_exit { + my $exitcode = shift; + exit($exitcode) if(defined $exitcode); + exit(1); +} ## sub munin_exit