Révision 29e732d7
Add new plugin : postfwd2
| plugins/mail/postfwd2 | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
# vim: set filetype=perl sw=4 tabstop=4 expandtab smartindent: # |
|
| 3 |
|
|
| 4 |
=head1 NAME |
|
| 5 |
|
|
| 6 |
postfwd2 - plugin to get stats from postfwd2 |
|
| 7 |
|
|
| 8 |
=head1 AUTHOR AND COPYRIGHT |
|
| 9 |
|
|
| 10 |
Copyright 2013 Luc Didry <luc AT didry.org> |
|
| 11 |
|
|
| 12 |
=head1 HOWTO CONFIGURE AND USE : |
|
| 13 |
|
|
| 14 |
=over |
|
| 15 |
|
|
| 16 |
=item - /etc/munin/plugin-conf.d/postfwd2 |
|
| 17 |
|
|
| 18 |
[postfwd2] |
|
| 19 |
user root |
|
| 20 |
env.path /usr/local/sbin/postfwd2 # OPTIONAL : looks for postfwd2 in /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin |
|
| 21 |
env.include .*ISBAD #OPTIONAL |
|
| 22 |
env.exclude .*ISGOOD #OPTIONAL |
|
| 23 |
|
|
| 24 |
=item - env.include and env.exclude |
|
| 25 |
|
|
| 26 |
This are perl regexp. |
|
| 27 |
If env.include is set and env.exclude is not, only the policy which name |
|
| 28 |
matchs will be used. |
|
| 29 |
If env.exclude is set and env.include is not, only the policy which name NOT |
|
| 30 |
matchs will be used. |
|
| 31 |
If both are set, a policy which name matchs the both regex will be used, a |
|
| 32 |
policy which matchs only the exclude regexp will NOT be used and a policy |
|
| 33 |
which match not the exclude regex will be used, even if it not matchs the |
|
| 34 |
include regexp. |
|
| 35 |
if none are set, all the policy will be used. |
|
| 36 |
|
|
| 37 |
|
|
| 38 |
=item - /etc/munin/plugins |
|
| 39 |
|
|
| 40 |
cp postfwd2 /etc/munin/plugins |
|
| 41 |
|
|
| 42 |
|
|
| 43 |
=item - restart Munin node |
|
| 44 |
|
|
| 45 |
service munin-node restart |
|
| 46 |
|
|
| 47 |
=back |
|
| 48 |
|
|
| 49 |
=head1 LICENSE |
|
| 50 |
|
|
| 51 |
This program is free software: you can redistribute it and/or modify it under |
|
| 52 |
the terms of the GNU General Public License as published by the Free Software |
|
| 53 |
Foundation, either version 3 of the License, or any later version. |
|
| 54 |
|
|
| 55 |
This program is distributed in the hope that it will be useful, but WITHOUT |
|
| 56 |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
| 57 |
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|
| 58 |
|
|
| 59 |
You should have received a copy of the GNU General Public License along with |
|
| 60 |
this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 61 |
|
|
| 62 |
=cut |
|
| 63 |
|
|
| 64 |
use warnings; |
|
| 65 |
use strict; |
|
| 66 |
use Munin::Plugin; |
|
| 67 |
|
|
| 68 |
need_multigraph(); |
|
| 69 |
|
|
| 70 |
my @keys =qw/cache_queries cache_stats policy_requests policy_timeout policy_matchs/; |
|
| 71 |
my %graphs = ( |
|
| 72 |
cache_queries => {
|
|
| 73 |
title => 'Cache queries', |
|
| 74 |
vlabel => 'Nb of cache queries', |
|
| 75 |
series => {
|
|
| 76 |
cache_queries => {
|
|
| 77 |
label => 'Cache queries', |
|
| 78 |
type => 'COUNTER' |
|
| 79 |
} |
|
| 80 |
}, |
|
| 81 |
}, |
|
| 82 |
cache_stats => {
|
|
| 83 |
title => 'Cache stats', |
|
| 84 |
vlabel => 'percent', |
|
| 85 |
series => {
|
|
| 86 |
cache_requests => {
|
|
| 87 |
label => 'Requests hitrate', |
|
| 88 |
type => 'GAUGE' |
|
| 89 |
}, |
|
| 90 |
cache_dns => {
|
|
| 91 |
label => 'Dns hitrate', |
|
| 92 |
type => 'GAUGE' |
|
| 93 |
}, |
|
| 94 |
cache_rates => {
|
|
| 95 |
label => 'Rates hitrate', |
|
| 96 |
type => 'GAUGE' |
|
| 97 |
} |
|
| 98 |
}, |
|
| 99 |
}, |
|
| 100 |
policy_requests => {
|
|
| 101 |
title => 'Policy requests', |
|
| 102 |
vlabel => 'Nb of policy requests', |
|
| 103 |
series => {
|
|
| 104 |
policy_requests => {
|
|
| 105 |
label => 'Policy requests', |
|
| 106 |
type => 'COUNTER' |
|
| 107 |
} |
|
| 108 |
}, |
|
| 109 |
}, |
|
| 110 |
policy_timeout => {
|
|
| 111 |
title => 'Policy timeout', |
|
| 112 |
vlabel => 'Nb of policy timeout', |
|
| 113 |
series => {
|
|
| 114 |
policy_timeout => {
|
|
| 115 |
label => 'Policy timeout', |
|
| 116 |
type => 'COUNTER' |
|
| 117 |
} |
|
| 118 |
} |
|
| 119 |
}, |
|
| 120 |
policy_matchs => {
|
|
| 121 |
title => 'Policy matchs', |
|
| 122 |
vlabel => 'Matchs percentage' |
|
| 123 |
} |
|
| 124 |
); |
|
| 125 |
|
|
| 126 |
my $PLUGIN_NAME = 'postfwd2'; |
|
| 127 |
my $CACHEFILE="$Munin::Plugin::pluginstatedir/postfwd2.cache"; |
|
| 128 |
|
|
| 129 |
my ($include, $exclude) = ($ENV{include}, $ENV{exclude});
|
|
| 130 |
if (defined($include) && (!defined($exclude))) {
|
|
| 131 |
$exclude = '.*'; |
|
| 132 |
} |
|
| 133 |
|
|
| 134 |
##### Cache file, to continue to graph old policies which doesn't exist anymore |
|
| 135 |
if (!(-f $CACHEFILE) || !(-e $CACHEFILE)) {
|
|
| 136 |
open (FILE, ">", $CACHEFILE) or munin_exit_fail(); |
|
| 137 |
close(FILE); |
|
| 138 |
} |
|
| 139 |
open (FILE, "<", $CACHEFILE) or munin_exit_fail(); |
|
| 140 |
my @policies = <FILE>; |
|
| 141 |
close(FILE); |
|
| 142 |
my %policies = map { $_, 1 } @policies;
|
|
| 143 |
foreach my $policy (keys %policies) {
|
|
| 144 |
chomp $policy; |
|
| 145 |
$graphs{policy_matchs}->{series}->{$policy}->{type} = 'GAUGE';
|
|
| 146 |
$graphs{policy_matchs}->{series}->{$policy}->{label} = $policy;
|
|
| 147 |
$graphs{policy_matchs}->{series}->{$policy}->{value} = 0;
|
|
| 148 |
} |
|
| 149 |
|
|
| 150 |
##### Check postfwd2 path |
|
| 151 |
if (!defined($ENV{path}) || !(-x $ENV{path})) {
|
|
| 152 |
foreach my $path (qw{/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin}) {
|
|
| 153 |
$ENV{path} = $path.'/postfwd2' if (!defined($ENV{path}) && -x $path.'/postfwd2');
|
|
| 154 |
last if (defined($ENV{path}));
|
|
| 155 |
} |
|
| 156 |
} |
|
| 157 |
munin_exit_fail() unless (defined($ENV{path}) && -x $ENV{path});
|
|
| 158 |
|
|
| 159 |
##### I have to parse the output BEFORE config, since policy matchs are dependant of the postfwd --dumpstats output |
|
| 160 |
open(DATA, $ENV{path}.' --dumpstats |') or munin_exit_fail();
|
|
| 161 |
my $total_requests; |
|
| 162 |
while(defined (my $data = <DATA>)) {
|
|
| 163 |
if ($data =~ m/^\[STATS\] postfwd2::cache .*: (\d+) queries since/) {
|
|
| 164 |
$graphs{cache_queries}->{series}->{cache_queries}->{value} = $1;
|
|
| 165 |
} |
|
| 166 |
if ($data =~ m/^\[STATS\] Hitrates: ([\.\d]+)% requests, ([\.\d]+)% dns, ([\.\d]+)% rates$/) {
|
|
| 167 |
$graphs{cache_stats}->{series}->{cache_requests}->{value} = $1;
|
|
| 168 |
$graphs{cache_stats}->{series}->{cache_dns}->{value} = $2;
|
|
| 169 |
$graphs{cache_stats}->{series}->{cache_rates}->{value} = $3;
|
|
| 170 |
} |
|
| 171 |
if ($data =~ m/^\[STATS\] postfwd2::policy .*: (\d+) requests since/) {
|
|
| 172 |
$graphs{policy_requests}->{series}->{policy_requests}->{value} = $1;
|
|
| 173 |
$total_requests = $1; |
|
| 174 |
} |
|
| 175 |
if ($data =~ m/^\[STATS\] Timeouts: .*% \((\d+) of \d+ dns queries\)$/) {
|
|
| 176 |
$graphs{policy_timeout}->{series}->{policy_timeout}->{value} = $1;
|
|
| 177 |
} |
|
| 178 |
if ($data =~ m/^\[STATS\] +(\d+) matches for id: (.*)$/) {
|
|
| 179 |
my ($value, $label) = ($1, $2); |
|
| 180 |
if ( ( !defined($exclude) ) || ( $label !~ m/$exclude/ || ( defined($include) && $label =~ m/$include/ ) ) ) {
|
|
| 181 |
if (!defined($policies{$label})) {
|
|
| 182 |
open (FILE, ">>", $CACHEFILE) or munin_exit_fail(); |
|
| 183 |
print FILE $label, "\n"; |
|
| 184 |
close(FILE); |
|
| 185 |
$graphs{policy_matchs}->{series}->{$label}->{type} = 'GAUGE';
|
|
| 186 |
$graphs{policy_matchs}->{series}->{$label}->{label} = $label;
|
|
| 187 |
} |
|
| 188 |
$graphs{policy_matchs}->{series}->{$label}->{value} = sprintf("%.2f", 100*$value/$total_requests);
|
|
| 189 |
} |
|
| 190 |
} |
|
| 191 |
} |
|
| 192 |
close(DATA); |
|
| 193 |
|
|
| 194 |
##### config |
|
| 195 |
if( (defined $ARGV[0]) && ($ARGV[0] eq 'config') ) {
|
|
| 196 |
foreach my $key (@keys) {
|
|
| 197 |
print 'multigraph postfwd2_', $key, "\n"; |
|
| 198 |
print 'graph_title Postfwd2 ', $graphs{$key}->{title}, "\n";
|
|
| 199 |
print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n";
|
|
| 200 |
my $args = ($key eq 'cache_stats') ? ' --upper-limit 100 --rigid' : ''; |
|
| 201 |
print 'graph_args --lower-limit 0', $args, "\n"; |
|
| 202 |
print 'graph_category mail', "\n"; |
|
| 203 |
if ($key eq 'policy_matchs') {
|
|
| 204 |
print 'graph_width 600', "\n"; |
|
| 205 |
my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}};
|
|
| 206 |
foreach my $label (@pol_keys) {
|
|
| 207 |
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
|
| 208 |
print $label, '.draw LINE', "\n"; |
|
| 209 |
print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n";
|
|
| 210 |
} |
|
| 211 |
foreach my $label (@pol_keys) {
|
|
| 212 |
print 'multigraph postfwd2_', $key, '.', $label, "\n"; |
|
| 213 |
print 'graph_title Postfwd2 ', $label, "\n"; |
|
| 214 |
print 'graph_vlabel ', $graphs{$key}->{vlabel}, "\n";
|
|
| 215 |
print 'graph_width 600', "\n"; |
|
| 216 |
print 'graph_args --lower-limit 0 ', $args, "\n"; |
|
| 217 |
print 'graph_category others', "\n"; |
|
| 218 |
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
|
| 219 |
print $label, '.draw LINE', "\n"; |
|
| 220 |
print $label, '.type GAUGE', "\n"; |
|
| 221 |
} |
|
| 222 |
} else {
|
|
| 223 |
foreach my $label (keys %{$graphs{$key}->{series}}) {
|
|
| 224 |
print $label, '.label ', $graphs{$key}->{series}->{$label}->{label}, "\n";
|
|
| 225 |
print $label, '.draw AREASTACK', "\n"; |
|
| 226 |
print $label, '.type ', $graphs{$key}->{series}->{$label}->{type}, "\n";
|
|
| 227 |
} |
|
| 228 |
} |
|
| 229 |
} |
|
| 230 |
munin_exit_done(); |
|
| 231 |
} |
|
| 232 |
|
|
| 233 |
##### fetch |
|
| 234 |
foreach my $key (@keys) {
|
|
| 235 |
print 'multigraph postfwd2_', $key, "\n"; |
|
| 236 |
if ($key eq 'policy_matchs') {
|
|
| 237 |
my @pol_keys = sort { $graphs{$key}->{series}->{$b}->{value} <=> $graphs{$key}->{series}->{$a}->{value} } keys %{$graphs{$key}->{series}};
|
|
| 238 |
foreach my $label (@pol_keys) {
|
|
| 239 |
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
|
| 240 |
} |
|
| 241 |
foreach my $label (@pol_keys) {
|
|
| 242 |
print 'multigraph postfwd2_', $key, '.', $label, "\n"; |
|
| 243 |
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
|
| 244 |
} |
|
| 245 |
} else {
|
|
| 246 |
foreach my $label (keys %{$graphs{$key}->{series}}) {
|
|
| 247 |
print $label, '.value ', $graphs{$key}->{series}->{$label}->{value}, "\n";
|
|
| 248 |
} |
|
| 249 |
} |
|
| 250 |
} |
|
| 251 |
munin_exit_done(); |
|
| 252 |
|
|
| 253 |
# |
|
| 254 |
## |
|
| 255 |
### INTERNALS FONCTIONS |
|
| 256 |
############################################################################### |
|
| 257 |
sub munin_exit_done {
|
|
| 258 |
munin_exit(0); |
|
| 259 |
} ## sub munin_exit_done |
|
| 260 |
|
|
| 261 |
sub munin_exit_fail {
|
|
| 262 |
munin_exit(1); |
|
| 263 |
} ## sub munin_exit_fail |
|
| 264 |
|
|
| 265 |
sub munin_exit {
|
|
| 266 |
my $exitcode = shift; |
|
| 267 |
exit($exitcode) if(defined $exitcode); |
|
| 268 |
exit(1); |
|
| 269 |
} ## sub munin_exit |
|
Formats disponibles : Unified diff