diff --git a/plugins/postfix/postfix_mailqueue_ b/plugins/postfix/postfix_mailqueue_ new file mode 100755 index 00000000..5ee84556 --- /dev/null +++ b/plugins/postfix/postfix_mailqueue_ @@ -0,0 +1,138 @@ +#!/bin/sh +# -*- sh -*- + +: << =cut + +=head1 NAME + +postfix_mailqueue_ - Plugin to monitor postfix mail spools per running postfix + +=head1 ABOUT + +A guide to postfix mail queue manageent can be found at +L + +A summary: + +=over 4 + +=item maildrop + +Messages that have been submitted via the Postfix sendmail(1) command, +but not yet brought into the main Postfix queue by the pickup(8) +service. + +=item hold + +Messages placed in the "hold" queue stay there until the administrator +intervenes + +=item incoming + +Inbound mail from the network, or mail picked up by the local +pickup(8) daemon from the maildrop directory. + +=item active + +Messages that the queue manager has opened for delivery. Only a limited number +of messages is allowed to enter the active queue (leaky bucket strategy, for a +fixed delivery rate). + +=item deferred + +Mail that could not be delivered upon the first attempt. The queue manager +implements exponential backoff by doubling the time between delivery attempts. + +=item corrupt + +Unreadable or damaged queue files are moved here for inspection. + +=back + +=head1 CONFIGURATION + +Uses the last part of the symlink name to get the postfix queue directory for the config file. +It then extract the queue path from the configuration file and uses it as a spooldir. +A environment spooldir can be set as a fallback. + + [postfix_mailqueue] + env.spooldir /var/spool/postfix + +=head1 AUTHOR + +Unknown. + +Extended to multiple queue use by Clemens Schwaighofer (gullevek@gullevek.org) in 2010. + +=head1 LICENSE + +Unknown. + +=head1 MAGIC MARKERS + +=begin comment + +These magic markers are used by munin-node-configure when installing +munin-node. + +=end comment + + #%# family=auto + #%# capabilities=autoconf + +=cut + +# atempt to get spooldir via postconf, but environment overrides. + +# Remember that postconf is not available unless postfix is. +CONFIG=${0##*postfix_mailqueue_} +CONFIG="/etc/"$CONFIG"/" +POSTCONFSPOOL="$(postconf -c $CONFIG -h queue_directory 2>/dev/null || echo /var/spool/postfix)" +SPOOLDIR=${spooldir:-$POSTCONFSPOOL} + +. $MUNIN_LIBDIR/plugins/plugin.sh + +case $1 in + autoconf|detect) + if [ -d $SPOOLDIR ] ; then + echo yes + exit 0 + else + echo "no (spooldir not found)" + exit 0 + fi + ;; + config) + echo "graph_title Postfix Mailqueue $CONFIG"; + cat <<'EOF' +graph_vlabel Mails in queue +graph_category postfix +graph_total Total +active.label active +deferred.label deferred +maildrop.label maildrop +incoming.label incoming +corrupt.label corrupt +hold.label held +EOF + for field in active deferred maildrop incoming corrupt hold; do + print_warning $field + print_critical $field + done + exit 0 + ;; +esac + +cd $SPOOLDIR >/dev/null 2>/dev/null || { + echo "# Cannot cd to $SPOOLDIR" + exit 1 +} + +cat < =~ /^sum:(\d+)/) +# { +# $sum = $1; +# } +# while () +# { +# if (/^([0-9a-z.\-]+):(\d+)$/) +# { +# $status->{$1} = $2; +# } +# } +# close IN; +#} + +if (! -d $configdir) +{ + print "sum.value U\n"; + foreach my $i (@status_list) + { + print "r$i.value U\n"; + } + exit 0; +} + + +parseLogfile($configdir); + +if ($ARGV[0] and $ARGV[0] eq "config") +{ + # descriptions for the rrd file + my %descriptions = ( + 'crefused' => 'Connection refused', + 'ctimeout' => 'Connection timed out', + 'rtimeout' => 'Lost connection', + 'refusedtalk' => 'Host refused connection', + 'nohost' => 'Host not found', + 'msrefused' => 'Mail service refused', + 'noroute' => 'Route not found', + 'usernotfound' => 'User not found', + 'err450' => '450 mailbox not okay (REJECT)', + 'err452' => '452 mailbox is full', + 'err421' => '421 service not okay (REJECT)', + 'err421a' => '421 service not okay (REJECT, SB)', + 'err4' => 'General 4xx error', + 'lostc' => 'Lost connection', + 'active' => 'Active running', + 'other' => 'Other error' + ); + + + print "graph_title Postfix mailqueue log for $postfix\n"; + print "graph_args --base 1000 -l 0\n"; # numbers not bytes + print "graph_vlabel Mails in Queue log\n"; + print "graph_scale no\n"; # so we do not print "micro, milli, kilo, etc" +# print "graph_total Total\n"; + print "graph_category postfix\n"; + foreach my $i (@status_list) + { + if ($descriptions{$i}) + { + print "r$i.label ".$descriptions{$i}."\n"; + print "r$i.type GAUGE\n"; + print "r$i.draw ".(!$field ? 'AREA' : 'STACK')."\n"; + print "r$i.min 0\n"; + $field = 'AREA'; + } + } + print "sum.label Sum\n"; + print "sum.type GAUGE\n"; + print "sum.draw LINE2\n"; + print "sum.min 0\n"; + exit 0; +} + +print "sum.value $sum\n"; +foreach my $i (@status_list) +{ + print "r$i.value ".($status->{$i} ? $status->{$i} : 0)."\n"; +} + +#if(-l $statefile) { +# die("$statefile is a symbolic link, refusing to touch it."); +#} +#open (OUT, '>', $statefile) or die "Unable to open statefile: $!\n"; +#print OUT "sum:$sum\n"; +#foreach my $i (@status_list) +#{ +# print OUT "$i:".($status->{$i} ? $status->{$i} : 0)."\n"; +#} +#close OUT; + +sub parseLogfile +{ + my ($fname) = @_; + + # the search parts + %search = ( + 'crefused' => 'Connection refused', + 'ctimeout' => 'Connection timed out', + 'rtimeout' => 'read timeout', + 'refusedtalk' => 'refused to talk to me: 554', + 'nohost' => 'Host not found', + 'msrefused' => 'server refused mail service"', + 'noroute' => 'No route to host', + 'usernotfound' => 'address rejected', + 'err450' => ': 450 ', + 'err452' => ': 452 ', + 'err421' => ': 421 ', + 'err421a' => ': 421)', + 'err4' => 'said: 4', + 'lostc' => 'lost connection with', + ); + + my $command = "mailq -C $fname"; + + open(FILE, "$command|") || die ("Cannot open $command: $!"); + while () + { + if (/^\w{10,}\*\s/o) + { + $status->{'active'} ++; + } + elsif (/^\s*\(/o) + { + $set = 0; + foreach $i (@status_list) + { + if ($search{$i} && index($_, $search{$i}) >= 0 && !$set) + { + $status->{$i} ++; + $set = 1; + } + } + if (!$set) + { + $status->{'other'} ++; + } + } + } + close(FILE) || die ("Cannot close $command: $!"); + + foreach $i (keys %{$status}) + { + $sum += $status->{$i}; + } +} + +# vim:syntax=perl diff --git a/plugins/postfix/postfix_mailstats_ b/plugins/postfix/postfix_mailstats_ new file mode 100755 index 00000000..a77e73fc --- /dev/null +++ b/plugins/postfix/postfix_mailstats_ @@ -0,0 +1,208 @@ +#!/usr/bin/perl -w +# -*- perl -*- + +=head1 NAME + +postfix_mailstats_ - Plugin to monitor the number of mails delivered and +rejected by postfix + +=head1 CONFIGURATION + +Uses the last part of the symlink name for grepping the correct data from the +postfix log file. The name must be syslog_name from the postfix config. +The environment settings still applay to this plugin. + +Configuration parameters for /etc/munin/postfix_mailstats_, +if you need to override the defaults below: + + [postfix_mailstats] + env.logdir - Which logfile to use + env.logfile - What file to read in logdir + +=head2 DEFAULT CONFIGURATION + + [postfix_mailstats] + env.logdir /var/log + env.logfile mail.log + +=head1 AUTHOR + +Records show that the plugin was contributed by Nicolai Langfeldt in +2003. Nicolai can't find anything in his email about this and expects +the plugin is based on the corresponding exim plugin - to which it now +bears no resemblence. + +Extended for multiple queue use by Clemens Schwaighofer (gullevek@gullevek.org) in 2010. + +=head1 LICENSE + +GPLv2 + +=head1 MAGIC MARKERS + +=begin comment + +These magic markers are used by munin-node-configure when installing +munin-node. + +=end comment + + #%# family=manual + #%# capabilities=autoconf + +=head1 RANDOM COMMENTS + +Would be cool if someone ported this to Munin::Plugin for both state +file and log tailing. + +=cut + +# get the postfix queue number to look for +$0 =~ /postfix_mailstats_([\w\d]+)$/; +my $postfix = $1; +my $statefile = "$ENV{MUNIN_PLUGSTATE}/munin-plugin-".$postfix."_mailstats.state"; +my $pos; +my $delivered = 0; +my $rejects = {}; +my $LOGDIR = $ENV{'logdir'} || '/var/log'; +my $LOGFILE = $ENV{'logfile'} || 'mail.log'; + +my $logfile = "$LOGDIR/$LOGFILE"; + +if ($ARGV[0] and $ARGV[0] eq "autoconf") +{ + my $logfile; + if (-d $LOGDIR) + { + if (-f $logfile) + { + if (-r $logfile) + { + print "yes\n"; + exit 0; + } + else + { + print "no (logfile '$logfile' not readable)\n"; + } + } + else + { + print "no (logfile '$logfile' not found)\n"; + } + } + else + { + print "no (could not find logdir '$LOGDIR')\n"; + } + + exit 0; +} + + +if (-f $statefile) +{ + open (IN, '<', $statefile) or die "Unable to open state-file: $!\n"; + if ( =~ /^(\d+):(\d+)/) + { + ($pos, $delivered) = ($1, $2); + } + while () + { + if (/^([0-9a-z.\-]+):(\d+)$/) + { + $rejects->{$1} = $2; + } + } + close IN; +} + +if (! -f $logfile) +{ + print "delivered.value U\n"; + foreach my $i (sort keys %{$rejects}) + { + print "r$i.value U\n"; + } + exit 0; +} + +$startsize = (stat $logfile)[7]; + +if (!defined $pos) +{ + # Initial run. + $pos = $startsize; +} + +parseLogfile($logfile, $pos, $startsize); +$pos = $startsize; + +if ( $ARGV[0] and $ARGV[0] eq "config" ) +{ + print "graph_title Postfix message throughput for $postfix\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 postfix\n"; + print "delivered.label delivered\n"; + print "delivered.type DERIVE\n"; + print "delivered.draw AREA\n"; + print "delivered.min 0\n"; + foreach my $i (sort keys %{$rejects}) + { + print "r$i.label reject $i\n"; + print "r$i.type DERIVE\n"; + print "r$i.draw STACK\n"; + print "r$i.min 0\n"; + } + exit 0; +} + +print "delivered.value $delivered\n"; +foreach my $i (sort keys %{$rejects}) +{ + print "r$i.value ", $rejects->{$i}, "\n"; +} + +if (-l $statefile) +{ + die ("$statefile is a symbolic link, refusing to touch it."); +} +open (OUT, '>', $statefile) or die "Unable to open statefile: $!\n"; +print OUT "$pos:$delivered\n"; +foreach my $i (sort keys %{$rejects}) +{ + print OUT "$i:", $rejects->{$i}, "\n"; +} +close OUT; + +sub parseLogfile +{ + my ($fname, $start, $stop) = @_; + open (LOGFILE, $fname) + or die "Unable to open logfile $fname for reading: $!\n"; + seek (LOGFILE, $start, 0) + or die "Unable to seek to $start in $fname: $!\n"; + + while (tell (LOGFILE) < $stop) + { + my $line = ; + chomp ($line); + + if ($line =~ /qmgr.*from=.*size=[0-9]*/ || + $line =~ /$postfix\/smtp.* status=sent /) + { + $delivered++; + } + elsif ($line =~ /$postfix\/smtpd.*reject: \S+ \S+ \S+ (\S+)/ || + $line =~ /$postfix\/cleanup.* reject: (\S+)/) + { + $rejects->{$1}++; + } + } + close(LOGFILE) or warn "Error closing $fname: $!\n"; +} + +# vim:syntax=perl diff --git a/plugins/postfix/postfix_mailvolume_multi b/plugins/postfix/postfix_mailvolume_multi new file mode 100755 index 00000000..4054d4a6 --- /dev/null +++ b/plugins/postfix/postfix_mailvolume_multi @@ -0,0 +1,220 @@ +#!/usr/bin/perl -w +# -*- perl -*- + +=head1 NAME + +postfix_mailvolume - Plugin to monitor the volume of mails delivered + by multiple postfix and stores per postfix delivered data. + +=head1 APPLICABLE SYSTEMS + +Any postfix. + +=head1 CONFIGURATION + +The following shows the default configuration. + + [postfix*] + env.logdir /var/log + env.logfile syslog + +=head2 Needed additional configuration + +To correctly get all the postfix log data, the postfix system_log prefix names need to be defined with the env.postfix config setting. +If this is not set, the script tries to find all the postfix config folders in /etc/postfix* and get the syslog names from there + + env.postfix postfix10 postfix11 postfix12 + +=head1 INTERPRETATION + +The plugin shows the number of bytes of mail that has passed through +the postfix installation per postfix mailer running. + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf + +=head1 BUGS + +None known + +=head1 VERSION + + $Id: postfix_mailvolume.in 2314 2009-08-03 11:28:34Z ssm $ + +=head1 AUTHOR + +Copyright (C) 2011. + +Clemens Schwaighofer (gullevek@gullevek.org) + +=head1 LICENSE + +GPLv2 + +=cut + +use strict; +use Munin::Plugin; + +my $pos = undef; +my $syslog_name = ''; +my @postfix_syslog_name = (); +my %volume = (); +my @restore_state = (); +my $i = 1; +my $LOGDIR = $ENV{'logdir'} || '/var/log'; +my $LOGFILE = $ENV{'logfile'} || 'syslog'; +my $POSTFIX = $ENV{'postfix'} || ''; +# get the postfix syslog_name from the POSTFIX env var, if not set, find them in the /etc/postfix* type +if (!$POSTFIX) +{ + foreach my $dir (grep -d, glob "/etc/postfix*") + { + # remove the leading etc + $dir =~ s/\/etc\///g; + # add data to the postfix string + $POSTFIX .= ' ' if ($POSTFIX); + $POSTFIX .= $dir; + } +} +if ($POSTFIX) +{ + foreach my $config (split(/ /, $POSTFIX)) + { + # find the syslog name + $syslog_name = `postconf -c /etc/$config | grep "syslog_name"`; + # remove any pending whitespace or line breaks + chomp($syslog_name); + $syslog_name =~ s/syslog_name = //g; + # add this to the postfix syslog name array + push(@postfix_syslog_name, $syslog_name); + # also init set the syslog name 0 + $volume{$syslog_name} = 0; + } +} +else +{ + print "Cannot get any postfix syslog_name data\n"; + exit 1; +} + +sub parseLogfile +{ + my ($fname, $start) = @_; + + my ($LOGFILE, $rotated) = tail_open($fname, $start); + + my $line; + + while ($line =<$LOGFILE>) + { + chomp ($line); + # get the postfix syslog name and the size + if ($line =~ /\ (\w+)\/qmgr.*from=.*size=([0-9]+)/) + { + $volume{$1} += $2; + } + } + return tail_close($LOGFILE); +} + +if ($ARGV[0] and $ARGV[0] eq "autoconf") +{ + my $logfile; + `which postconf >/dev/null 2>/dev/null`; + if (!$?) + { + $logfile = "$LOGDIR/$LOGFILE"; + + if (-f $logfile) + { + if (-r "$logfile") + { + print "yes\n"; + exit 0; + } + else + { + print "no (logfile '$logfile' not readable)\n"; + } + } + else + { + print "no (logfile '$logfile' not found)\n"; + } + } + else + { + print "no (postfix not found)\n"; + } + exit 0; +} + +if ($ARGV[0] and $ARGV[0] eq "config") +{ + print "graph_title Postfix bytes throughput per postfix\n"; + print "graph_args --base 1000 -l 0\n"; + print "graph_vlabel bytes / \${graph_period}\n"; + print "graph_scale yes\n"; + print "graph_category postfix\n"; + print "graph_total Throughput sum\n"; + # loop through the postfix names and create per config an entry + foreach $syslog_name (@postfix_syslog_name) + { + print $syslog_name."_volume.label ".$syslog_name." throughput\n"; + print $syslog_name."_volume.type DERIVE\n"; + print $syslog_name."_volume.min 0\n"; + } + exit 0; +} + + +my $logfile = "$LOGDIR/$LOGFILE"; + +if (! -f $logfile) { + print "delivered.value U\n"; + exit 1; +} + +@restore_state = restore_state(); +# first is pos, rest is postfix entries +$pos = $restore_state[0]; +# per postfix values are store: postfix config,value +for ($i = 1; $i < @restore_state; $i ++) +{ + my ($key, $value) = split(/,/, $restore_state[$i]); + $volume{$key} = $value; +} + +if (!$pos) +{ + # No state file present. Avoid startup spike: Do not read log + # file up to now, but remember how large it is now, and next + # time read from there. + + $pos = (stat $logfile)[7]; # File size + foreach $syslog_name (@postfix_syslog_name) + { + $volume{$syslog_name} = 0; + } +} +else +{ + $pos = parseLogfile($logfile, $pos); +} + +@restore_state = ($pos); +foreach $syslog_name (sort keys %volume) +{ + print $syslog_name."_volume.value ".$volume{$syslog_name}."\n"; + push(@restore_state, $syslog_name.','.$volume{$syslog_name}); +} + +# save the current state +save_state(@restore_state); + +# vim:syntax=perl + +__END__ diff --git a/plugins/postgresql/pgbouncer_ b/plugins/postgresql/pgbouncer_ new file mode 100755 index 00000000..208d663e --- /dev/null +++ b/plugins/postgresql/pgbouncer_ @@ -0,0 +1,295 @@ +#!/usr/bin/perl -w + +# re-write of python version of pgbouncer stats +# data from stats, pools (cleint, server) + +use strict; +use Munin::Plugin; +use DBD::Pg; + +# check that multigraph is avaailable +need_multigraph(); +# get the script name +my $plugin_name = $Munin::Plugin::me; +# set the DB connection vars +my $db_user = $ENV{'pgbouncer_user'} || 'postgres'; +my $db_port = $ENV{'pgbouncer_port'} || '6432'; +my $db_host = $ENV{'pgbouncer_host'} || 'localhost'; +my $db_pass = $ENV{'pgbouncer_pass'} || ''; +my $db_name = 'pgbouncer'; +my @data = (); +# get the DB (pool) name we want to fetch +$plugin_name =~ /pgbouncer_(.*)$/; +my $pool_name = $1; +# bail if no name +if (!$pool_name) +{ + print "Cannot get pool name\n"; + exit 1; +} + +# command line arguments for autconf and config +if (defined($ARGV[0])) +{ + # autoconf, nothing to do + if ($ARGV[0] eq 'autoconf') + { + my $dbh = DBI->connect("DBI:Pg:dbname=$db_name;host=$db_host;port=$db_port", $db_user, $db_pass); + if (!$dbh) + { + print "no\n"; + exit 1; + } + else + { + print "yes\n"; + exit 0; + } + $dbh->disconnect(); + } + + if ($ARGV[0] eq 'config') + { + # create the basic RRD + # stats: average connections + print "multigraph ".$plugin_name."_stats_avg_req\n"; + print "graph_title PgBouncer $pool_name average connections\n"; + print "graph_args --base 1000\n"; # numbers not bytes + print "graph_vlabel Average connections\n"; + print "graph_scale no\n"; # so we do not print "micro, milli, kilo, etc" + print "graph_category pgbouncer\n"; + print $pool_name."_avg_req.type GAUGE\n"; + print $pool_name."_avg_req.label Avg Req\n"; + print $pool_name."_avg_req.min 0\n"; + print $pool_name."_avg_req.draw LINE2\n"; + # stats: average time for query + print "multigraph ".$plugin_name."_stats_avg_query\n"; + print "graph_title PgBouncer $pool_name average query time\n"; + print "graph_args --base 1000\n"; # numbers not bytes + print "graph_vlabel Average time per query (microseconds)\n"; + print "graph_category pgbouncer\n"; + print $pool_name."_avg_query.type GAUGE\n"; + print $pool_name."_avg_query.label Avg Time\n"; + print $pool_name."_avg_query.min 0\n"; + print $pool_name."_avg_query.draw LINE2\n"; + # stats: in/out bytes + print "multigraph ".$plugin_name."_stats_bytesinout\n"; + print "graph_title PgBouncer $pool_name average bytes received/sent\n"; + print "graph_args --base 1024\n"; # numbers in bytes + print "graph_vlabel Average bytes received (-)/sent (+)\n"; + print "graph_category pgbouncer\n"; + # bytes received + print $pool_name."_avg_recv.type GAUGE\n"; + print $pool_name."_avg_recv.label Avg received\n"; + print $pool_name."_avg_recv.min 0\n"; + print $pool_name."_avg_recv.draw LINE1\n"; + print $pool_name."_avg_recv.graph no\n"; + # bytes sent + print $pool_name."_avg_sent.type GAUGE\n"; + print $pool_name."_avg_sent.label Avg rcvd/sent\n"; + print $pool_name."_avg_sent.min 0\n"; + print $pool_name."_avg_sent.draw LINE1\n"; + print $pool_name."_avg_sent.negative ".$pool_name."_avg_recv\n"; + # pools: server (sv_) + print "multigraph ".$plugin_name."_pools_server\n"; + print "graph_title PgBouncer $pool_name servers\n"; + print "graph_category pgbouncer\n"; + print "graph_args --base 1000\n"; # numbers not bytes + print "graph_vlabel Server connections\n"; + print "graph_scale no\n"; + # active connections + print $pool_name."_server_active.label active\n"; + print $pool_name."_server_active.min 0\n"; + print $pool_name."_server_active.type GAUGE\n"; + print $pool_name."_server_active.draw AREA\n"; + # idle connections + print $pool_name."_server_idle.label idle\n"; + print $pool_name."_server_idle.min 0\n"; + print $pool_name."_server_idle.type GAUGE\n"; + print $pool_name."_server_idle.draw STACK\n"; + # used connections + print $pool_name."_server_used.label used\n"; + print $pool_name."_server_used.min 0\n"; + print $pool_name."_server_used.type GAUGE\n"; + print $pool_name."_server_used.draw STACK\n"; + # tested connections + print $pool_name."_server_tested.label tested\n"; + print $pool_name."_server_tested.min 0\n"; + print $pool_name."_server_tested.type GAUGE\n"; + print $pool_name."_server_tested.draw STACK\n"; + # logged in connections + print $pool_name."_server_login.label login\n"; + print $pool_name."_server_login.min 0\n"; + print $pool_name."_server_login.type GAUGE\n"; + print $pool_name."_server_login.draw STACK\n"; + # pools: client (cl_) + print "multigraph ".$plugin_name."_pools_client\n"; + print "graph_title PgBouncer $pool_name clients\n"; + print "graph_category pgbouncer\n"; + print "graph_args --base 1000\n"; # numbers not bytes + print "graph_vlabel Client connections\n"; + print "graph_scale no\n"; + # active client connections + print $pool_name."_client_active.label active\n"; + print $pool_name."_client_active.min 0\n"; + print $pool_name."_client_active.type GAUGE\n"; + print $pool_name."_client_active.draw AREA\n"; + # waiting client connections + print $pool_name."_client_waiting.label waiting\n"; + print $pool_name."_client_waiting.min 0\n"; + print $pool_name."_client_waiting.type GAUGE\n"; + print $pool_name."_client_waiting.draw STACK\n"; + # pools: maxwait (longest waiting connection, should be 0) + print "multigraph ".$plugin_name."_pools_maxwait\n"; + print "graph_title PgBouncer $pool_name maximum waiting time\n"; + print "graph_args --base 1000\n"; # numbers not bytes + print "graph_vlabel Maximum wait time (seconds)\n"; + print "graph_category pgbouncer\n"; + print $pool_name."_maxwait.type GAUGE\n"; + print $pool_name."_maxwait.label Wait Time\n"; + print $pool_name."_maxwait.min 0\n"; + print $pool_name."_maxwait.draw LINE2\n"; + print $pool_name."_maxwait.warning 1\n"; # warn if not 0 + print $pool_name."_maxwait.critical 10\n"; # go critical if 10 seconds waiting + # END graph + exit 0; + } +} + +# connect to data +my $dbh = DBI->connect("DBI:Pg:dbname=$db_name;host=$db_host;port=$db_port", $db_user, $db_pass); +# go trough each set and get the data +foreach my $get ('pools', 'stats') +{ + # prep and execute the show query + my $pre = $dbh->prepare("SHOW $get"); + $pre->execute(); + while (@data = $pre->fetchrow) + { + # first defines the pool + if ($data[0] eq $pool_name) + { + # print values for the stats: average reqeust, average query time, bytes in/out + if ($get eq 'stats') + { + print "multigraph ".$plugin_name."_".$get."_avg_req\n"; + print $pool_name."_avg_req.value ".$data[5]."\n"; + print "multigraph ".$plugin_name."_".$get."_avg_query\n"; + print $pool_name."_avg_query.value ".$data[8]."\n"; + print "multigraph ".$plugin_name."_".$get."_bytesinout\n"; + print $pool_name."_avg_recv.value ".$data[6]."\n"; + print $pool_name."_avg_sent.value ".$data[7]."\n"; + } + # print data for the pools: server, client + if ($get eq 'pools') + { + print "multigraph ".$plugin_name."_".$get."_server\n"; + print $pool_name."_server_active.value ".$data[4]."\n"; + print $pool_name."_server_idle.value ".$data[5]."\n"; + print $pool_name."_server_used.value ".$data[6]."\n"; + print $pool_name."_server_tested.value ".$data[7]."\n"; + print $pool_name."_server_login.value ".$data[8]."\n"; + print "multigraph ".$plugin_name."_".$get."_client\n"; + print $pool_name."_client_active.value ".$data[2]."\n"; + print $pool_name."_client_waiting.value ".$data[3]."\n"; + print "multigraph ".$plugin_name."_".$get."_maxwait\n"; + print $pool_name."_maxwait.value ".$data[9]."\n"; + } + } + } +} +# close connection +$dbh->disconnect(); + +exit 0; + +__END__ + +=head1 NAME + +pgbouncer_ is a plugin to get the pool and stat values for a single pgbouncer pool name + +=head1 APPLICATION + +perl and DBD::Pg is required, and pgbounce must been installed with a correct setup access for a stat account + +=head1 CONFIGURATION + +the plugin that will be run needs to have the pool name after the plguin base name. + +=head2 plugin configuration + +eg: pgbouncer_foo will run for the pool named foo. + +see SHOW POOLS database list for the pool name + +=head2 munin plugin config file + +in the plugin config file under the [pgbouncer] name the access information ca be set. + +eg: + [pgbouncer*] + env.pgbouncer_pass barfoo + +more extended would be: + [pgbouncer*] + env.pgbouncer_pass barfoo + env.pgbouncer_user bar + env.pgbouncer_port 6542 + env.pgbouncer_host localhost + +The database name is always pgbouncer + +=head1 OUTPUT + +The plugin will output 5 graphs in the group pgbouncer + +=head2 Average bytes received/sent + +This graph will show the average bytes sent and received by the pgbouncer for this pool + +=head2 Avaerage connections + +This graph will show the average amount of connections to the pgbouncer for this pool + +=head2 Average query time + +This graph shows the average query time as processed by the pgbouncer for this pool in microseconds. The data will be shorted by standard SI. eg, m = milli, k = kilo. + +So 4.61K is 4610 milliseconds + +=head2 Client connections + +This graph shows the active and waiting client connections to pgbouncer for this pool + +=head2 Server connections + +This graph shows the server connections to pgbouncer for this pool. The following data sets are shown: active, idle, used, tested, login + +=head2 Max wait + +how long the oldest cllient the queue has waited, should be always 0 + +=head1 ACKNOWLEDGEMENTS + +Original idea derived from a simple python script by Dimitri Fontaine + +=head1 SEE ALSO + +See further info on stats and pools on the pgbouncer homepage: + http://pgbouncer.projects.postgresql.org/doc/usage.html#_show_commands + +=head1 VERSION + +1.0 + +=head1 AUTHOR + +Clemens Schwaighofer + +=head1 LICENSE + +GPLv2 + + +=cut