1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-21 18:41:03 +00:00

amavis_multi: multigraph plugin to monitor amavisd mail filter

This commit is contained in:
Kim B. Heino 2021-04-06 15:53:17 +03:00
parent 2c9121708a
commit dd749a26c0

189
plugins/amavis/amavis_multi Executable file
View file

@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""Munin plugin to monitor amavisd mail filter status.
=head1 NAME
amavis_multi - monitor amavisd mail filter status
=head1 CONFIGURATION
Following config is needed:
[amavis_multi]
user amavis
=head1 AUTHOR
Kim Heino <b@bbbs.net>
=head1 LICENSE
GPLv2
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=cut
"""
import os
import subprocess
import sys
def run_binary(arg):
"""Run binary and return output."""
try:
return subprocess.run(arg, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, check=False,
encoding='utf-8', errors='ignore').stdout
except FileNotFoundError:
return ''
def get_values():
"""Get status from nanny and agent. They are part of amavisd."""
ret = {
'nanny': {
'total': 0,
'busy': 0,
},
'agent': {},
}
agent = run_binary(['amavisd-agent', '-c', '1'])
nanny = run_binary(['amavisd-nanny', '-c', '1'])
if not agent or not nanny:
return ret
# Busy count from nanny
for line in nanny.splitlines():
if not line.startswith('PID ') or ':' not in line:
continue
ret['nanny']['total'] += 1
if ': ' not in line:
ret['nanny']['busy'] += 1
# Mail counts and processing times from agent
for line in agent.splitlines():
items = line.split()
if len(items) > 1 and items[1].isnumeric():
ret['agent'][items[0]] = items[1:]
return ret
def print_status(config):
"""Print config or values."""
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
both = os.environ.get('MUNIN_CAP_DIRTYCONFIG') == '1'
values = get_values()
# Busy childs. Use average of last three runs so that single "bad timing"
# doesn't trigger warning.
print('multigraph amavis_childs')
if config or both:
print('graph_title Amavisd mail filter busy childs')
print('graph_vlabel % busy')
print('graph_args --base 1000 --lower-limit 0 --upper-limit 100')
print('graph_category spamfilter')
print('busy.label Percent of busy childs')
print('busy.warning 80')
print('busy.critical 95')
if not config or both:
if not values['nanny']['total']:
print('busy.value U')
else:
statename = os.path.join(os.getenv('MUNIN_PLUGSTATE'),
'amavis_multi.state')
try:
with open(statename, 'rt') as statef:
count1 = int(statef.readline())
count2 = int(statef.readline())
except (FileNotFoundError, TypeError, ValueError):
count1 = count2 = 0
with open(statename, 'wt') as statef:
print(values['nanny']['busy'], file=statef)
print(count1, file=statef)
print('busy.value {}'.format(
(values['nanny']['busy'] + count1 + count2) * 100 / 3 /
values['nanny']['total']))
# Mail counts
print('multigraph amavis_mails')
if config or both:
print('graph_title Amavisd mail filter mail counts')
print('graph_period minute')
print('graph_vlabel mails per ${graph_period}')
print('graph_args --base 1000 --lower-limit 0')
print('graph_category spamfilter')
print('contentcleanmsgs.label Clean mails')
print('contentcleanmsgs.type DERIVE')
print('contentcleanmsgs.min 0')
print('contentbadhdrmsgs.label Bad header mails')
print('contentbadhdrmsgs.type DERIVE')
print('contentbadhdrmsgs.min 0')
print('contentspammymsgs.label Spammy mails')
print('contentspammymsgs.type DERIVE')
print('contentspammymsgs.min 0')
print('contentspammsgs.label Spam mails')
print('contentspammsgs.type DERIVE')
print('contentspammsgs.min 0')
print('contentvirusmsgs.label Virus mails')
print('contentvirusmsgs.type DERIVE')
print('contentvirusmsgs.min 0')
print('inmsgs.label Total mails')
print('inmsgs.type DERIVE')
print('inmsgs.min 0')
if not config or both:
for key in ('ContentCleanMsgs',
'ContentBadHdrMsgs',
'ContentSpammyMsgs',
'ContentSpamMsgs',
'ContentVirusMsgs',
'InMsgs'):
if key in values['agent']:
print('{}.value {}'.format(key.lower(),
values['agent'][key][0]))
else:
# Key is missing if no such mail yet, so 0, not U.
print('{}.value 0'.format(key.lower()))
# Elapsed times
print('multigraph amavis_times')
if config or both:
print('graph_title Amavisd mail filter elapsed times')
print('graph_vlabel seconds per mail')
print('graph_args --base 1000 --lower-limit 0')
print('graph_category spamfilter')
print('timeelapsedreceiving.label Receiving')
print('timeelapseddecoding.label Decoding')
print('timeelapsedspamcheck.label Spam check')
print('timeelapsedviruscheck.label Virus check')
print('timeelapsedsending.label Sending')
print('timeelapsedtotal.label Total')
if not config or both:
for key in ('TimeElapsedReceiving',
'TimeElapsedDecoding',
'TimeElapsedSpamCheck',
'TimeElapsedVirusCheck',
'TimeElapsedSending',
'TimeElapsedTotal'):
if key in values['agent']:
print('{}.value {}'.format(key.lower(),
values['agent'][key][2]))
else:
# Key is missing if feature is not used, so 0, not U.
print('{}.value 0'.format(key.lower()))
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
print('yes' if get_values()['agent'] else
'no (amavisd is not running)')
elif len(sys.argv) > 1 and sys.argv[1] == 'config':
print_status(True)
else:
print_status(False)