2009-01-14 17:04:37 +01:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
#
|
|
|
|
# Plugin to monitor amavisd-new statistics. Values are retrieved by querying
|
|
|
|
# the BerkeleyDB database 'snmp.db', in which amavisd-new stores its
|
|
|
|
# statistics.
|
|
|
|
#
|
|
|
|
# The plugin requires the Perl module BerkeleyDB.
|
|
|
|
#
|
|
|
|
# To use, setup /etc/munin/plugin-conf.d/amavis e.g. as follows:
|
|
|
|
#
|
|
|
|
# [amavis_*]
|
|
|
|
# env.amavis_db_home /var/lib/amavis/db
|
|
|
|
# user amavis
|
|
|
|
#
|
|
|
|
# Where env.amavis_db_home is the path to the amavisd-new BerkeleyDB files
|
|
|
|
# (/var/amavis/db by default).
|
|
|
|
#
|
|
|
|
# Then create symlinks in the Munin plugin directory named "amavis_time",
|
|
|
|
# "amavis_cache" and "amavis_content", or use munin-node-configure.
|
|
|
|
#
|
|
|
|
# Parameters:
|
|
|
|
#
|
|
|
|
# config
|
|
|
|
# autoconf
|
|
|
|
# suggest
|
|
|
|
#
|
|
|
|
# Config variables:
|
|
|
|
#
|
|
|
|
# amavis_db_home - where the amavisd-new berkeley db files are located
|
|
|
|
#
|
|
|
|
# Magic markers
|
|
|
|
#%# family=auto
|
|
|
|
#%# capabilities=autoconf
|
|
|
|
#%# capabilities=suggest
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
no warnings 'uninitialized';
|
|
|
|
|
|
|
|
use BerkeleyDB;
|
|
|
|
|
|
|
|
my($dbfile) = 'snmp.db';
|
|
|
|
my($db_home) = # DB databases directory
|
|
|
|
defined $ENV{'amavis_db_home'} ? $ENV{'amavis_db_home'} : '/var/amavis/db';
|
|
|
|
|
|
|
|
if ($ARGV[0] and $ARGV[0] eq "autoconf") {
|
|
|
|
if (-x "/usr/sbin/amavisd-agent") {
|
|
|
|
print "yes\n";
|
|
|
|
exit 0;
|
|
|
|
} else {
|
|
|
|
print "no (/usr/sbin/amavisd-agent not found or not executable)\n";
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
} elsif ($ARGV[0] and $ARGV[0] eq "suggest") {
|
|
|
|
print "time\n";
|
|
|
|
print "cache\n";
|
|
|
|
print "content\n";
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $stats_type = "";
|
|
|
|
if ($0 =~ /^(?:|.*\/)amavis_(cache|content|time)$/) {
|
|
|
|
$stats_type = $1;
|
|
|
|
} else {
|
|
|
|
print "You need to create a symlink to this plugin called either amavis_cache, amavis_time or amavis_content to be able to use it.\n";
|
|
|
|
exit 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ARGV[0] and $ARGV[0] eq "config") {
|
|
|
|
if ($stats_type eq "cache") {
|
|
|
|
print "graph_title Amavis cache hit / miss ratio\n";
|
|
|
|
print "graph_args --lower-limit 0 --upper-limit 100 --rigid\n";
|
2017-02-20 18:32:37 +01:00
|
|
|
print "graph_category antivirus\n";
|
2009-01-14 17:04:37 +01:00
|
|
|
print "graph_info The ratio of cache hits and misses for AMaViSd-new.\n";
|
|
|
|
print "graph_order hits misses\n";
|
|
|
|
print "graph_scale no\n";
|
|
|
|
print "graph_vlabel %\n";
|
|
|
|
print "hits.label Cache hits\n";
|
|
|
|
print "hits.draw AREA\n";
|
|
|
|
print "hits.max 100\n";
|
|
|
|
print "hits.min 0\n";
|
|
|
|
print "misses.label Cache misses\n";
|
|
|
|
print "misses.draw STACK\n";
|
|
|
|
print "misses.max 100\n";
|
|
|
|
print "misses.min 0\n";
|
|
|
|
} elsif ($stats_type eq "content") {
|
|
|
|
print "graph_title Amavis scanned mails\n";
|
2017-02-20 18:32:37 +01:00
|
|
|
print "graph_category antivirus\n";
|
2009-01-14 17:04:37 +01:00
|
|
|
print "graph_period minute\n";
|
|
|
|
print "graph_vlabel msgs / \${graph_period}\n";
|
|
|
|
foreach my $type (qw(total clean spam spammy virus)) {
|
|
|
|
print "$type.label " . ucfirst($type) . " mails \n";
|
|
|
|
print "$type.type DERIVE\n";
|
|
|
|
print "$type.min 0\n";
|
|
|
|
}
|
|
|
|
print "clean.info Legitimate mail.\n";
|
|
|
|
print "spammy.info Mails with a spam score above the tag2 level.\n";
|
|
|
|
print "spam.info Mails with a spam score above the kill level for spam.\n";
|
|
|
|
print "virus.info Mails with a virus.\n";
|
|
|
|
print "total.info Total number of scanned mails.\n";
|
|
|
|
} elsif ($stats_type eq "time") {
|
|
|
|
print "graph_title Amavis average scan time\n";
|
|
|
|
print "graph_info Average time spent in each phase of the mail scanning process, per mail.\n";
|
2017-02-20 18:32:37 +01:00
|
|
|
print "graph_category antivirus\n";
|
2009-01-14 17:04:37 +01:00
|
|
|
print "graph_vlabel sec / mail\n";
|
|
|
|
print "graph_scale no\n";
|
|
|
|
|
|
|
|
print "msgs.label Total number of messages\n";
|
|
|
|
print "msgs.graph no\n";
|
|
|
|
print "msgs.type DERIVE\n";
|
|
|
|
print "msgs.min 0\n";
|
|
|
|
|
|
|
|
foreach my $type (qw(decoding receiving sending spamcheck viruscheck total)) {
|
|
|
|
print "${type}.label " . ucfirst($type) . "\n";
|
|
|
|
print "${type}.type DERIVE\n";
|
|
|
|
print "${type}.min 0\n";
|
|
|
|
print "${type}.cdef ${type},1000,/,msgs,/\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my ($env, $db, @dbstat, $cursor);
|
|
|
|
|
|
|
|
@dbstat = stat("$db_home/$dbfile");
|
|
|
|
my $errn = @dbstat ? 0 : 0+$!;
|
|
|
|
$errn == 0 or die "stat $db_home/$dbfile: $!";
|
|
|
|
|
|
|
|
$env = BerkeleyDB::Env->new(
|
|
|
|
-Home => $db_home,
|
|
|
|
-Flags => DB_INIT_CDB | DB_INIT_MPOOL,
|
|
|
|
-ErrFile => \*STDOUT,
|
|
|
|
-Verbose => 1,
|
|
|
|
);
|
|
|
|
defined $env or die "BDB no env: $BerkeleyDB::Error $!";
|
|
|
|
|
|
|
|
$db = BerkeleyDB::Hash->new(-Filename => $dbfile, -Env => $env);
|
|
|
|
defined $db or die "BDB no db: $BerkeleyDB::Error $!";
|
|
|
|
|
|
|
|
my %values = ();
|
|
|
|
my ($eval_stat, $stat, $key, $val);
|
|
|
|
|
|
|
|
$cursor = $db->db_cursor; # obtain read lock
|
|
|
|
defined $cursor or die "db_cursor error: $BerkeleyDB::Error";
|
|
|
|
|
|
|
|
while (($stat = $cursor->c_get($key, $val, DB_NEXT)) == 0) {
|
|
|
|
$values{$key} = $val;
|
|
|
|
}
|
|
|
|
|
|
|
|
$stat == DB_NOTFOUND or die "c_get: $BerkeleyDB::Error $!";
|
|
|
|
$cursor->c_close == 0 or die "c_close error: $BerkeleyDB::Error";
|
|
|
|
$cursor = undef;
|
|
|
|
|
|
|
|
$eval_stat = $@;
|
|
|
|
|
|
|
|
if ($eval_stat ne '') { chomp($eval_stat); die "BDB $eval_stat\n"; }
|
|
|
|
|
|
|
|
for my $k (sort keys %values) {
|
|
|
|
if ($values{$k} =~ /^(?:C32|C64) (.*)\z/) {
|
|
|
|
$values{$k} = $1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($stats_type eq "cache") {
|
|
|
|
my $hits = $values{'CacheHits'};
|
|
|
|
my $misses = $values{'CacheMisses'};
|
|
|
|
my $misses_ratio = $misses * 100.00 / ($hits + $misses);
|
|
|
|
my $hits_ratio = $hits * 100.00 / ($hits + $misses);
|
|
|
|
|
|
|
|
printf("hits.value %.1f\n", $hits_ratio);
|
|
|
|
printf("misses.value %.1f\n", $misses_ratio);
|
|
|
|
} elsif ($stats_type eq "content") {
|
|
|
|
printf("total.value %d\n", $values{'InMsgs'});
|
|
|
|
my $clean = $values{'ContentCleanMsgs'};
|
|
|
|
if (defined($values{'ContentCleanTagMsgs'})) {
|
|
|
|
$clean += $values{'ContentCleanTagMsgs'};
|
|
|
|
}
|
|
|
|
printf("clean.value %d\n", $clean);
|
|
|
|
printf("spam.value %d\n", $values{'ContentSpamMsgs'});
|
|
|
|
printf("spammy.value %d\n", $values{'ContentSpammyMsgs'});
|
|
|
|
printf("virus.value %d\n", $values{'ContentVirusMsgs'});
|
|
|
|
} elsif ($stats_type eq "time") {
|
|
|
|
printf("decoding.value %d\n", $values{'TimeElapsedDecoding'});
|
|
|
|
printf("receiving.value %d\n", $values{'TimeElapsedReceiving'});
|
|
|
|
printf("sending.value %d\n", $values{'TimeElapsedSending'});
|
|
|
|
printf("spamcheck.value %d\n", $values{'TimeElapsedSpamCheck'});
|
|
|
|
printf("viruscheck.value %d\n", $values{'TimeElapsedVirusCheck'});
|
|
|
|
printf("total.value %d\n", $values{'TimeElapsedTotal'});
|
|
|
|
printf("msgs.value %d\n", $values{'InMsgs'});
|
|
|
|
}
|
|
|
|
|
|
|
|
$db->db_close == 0 or die "BDB db_close error: $BerkeleyDB::Error $!";
|