mirror of
https://github.com/munin-monitoring/contrib.git
synced 2018-11-08 00:59:34 +01:00
b8f1b6c879
Previously monit seems to have output memory usage in kilobytes without a unit. Somewhen this seemed to have changed to an (optional?) suffix (e.g. MB). Thus the new scaling may differ from the previous scaling, which was probably broken for most users. Additionally the units of the resulting values are clarified.
127 lines
3.4 KiB
Python
Executable File
127 lines
3.4 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
"""
|
|
=head1 NAME
|
|
|
|
monit_parser - Monit status parser plugin for munin.
|
|
|
|
|
|
=head1 APPLICABLE SYSTEMS
|
|
|
|
Any system running monit.
|
|
|
|
Monit needs to be configured with the httpd port enabled, e.g.:
|
|
|
|
set httpd port 2812
|
|
|
|
The configured port is not important, since this plugin uses "monit status"
|
|
for retrieving data. Thus the monit configuration is parsed implicitly.
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
This plugin requires read access for the monit configuration.
|
|
Thus it needs to run as root:
|
|
|
|
[monit_parser]
|
|
user root
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
Todd Troxell <ttroxell@debian.org>
|
|
Lars Kruse <devel@sumpfralle.de>
|
|
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
family=auto
|
|
capabilities=autoconf
|
|
|
|
=cut
|
|
"""
|
|
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def sanitize(s):
|
|
OK_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789"
|
|
return "".join([char for char in s if char in OK_CHARS])
|
|
|
|
|
|
def get_monit_status_lines():
|
|
# retrieve output
|
|
try:
|
|
output = subprocess.check_output(["monit", "status"])
|
|
error_message = None
|
|
except (OSError, subprocess.CalledProcessError) as exc:
|
|
error_message = "Error running monit status command: %s" % str(exc)
|
|
if error_message is not None:
|
|
raise OSError(error_message)
|
|
# python3: the result of command execution is bytes and needs to be converted
|
|
if not isinstance(output, str):
|
|
output = output.decode("ascii", "ignore")
|
|
return output.splitlines()
|
|
|
|
|
|
def parse_processes():
|
|
cur_proc = None
|
|
procs = {}
|
|
for line in get_monit_status_lines():
|
|
m = re.match("^Process '(.*)'.*$", line)
|
|
if m:
|
|
cur_proc = sanitize(m.group(1))
|
|
try:
|
|
procs[cur_proc]
|
|
except KeyError:
|
|
procs[cur_proc] = {}
|
|
continue
|
|
m = re.match(" memory kilobytes total\s+([0-9.]+)(.*)$", line)
|
|
if m:
|
|
size, suffix = m.groups()
|
|
# we store memory consumption as megabytes
|
|
factor = {
|
|
"": 1024 ** -1,
|
|
"KB": 1024 ** -1,
|
|
"MB": 1024 ** 0,
|
|
"GB": 1024 ** 1,
|
|
"TB": 1024 ** 2,
|
|
}[suffix.strip().upper()]
|
|
try:
|
|
procs[cur_proc]["total_memory"] = float(size) * factor
|
|
except ValueError:
|
|
procs[cur_proc]["total_memory"] = "U"
|
|
continue
|
|
m = re.match(" cpu percent total\s+([.0-9]+)%.*$", line)
|
|
if m:
|
|
procs[cur_proc]["total_cpu"] = m.group(1)
|
|
continue
|
|
return procs
|
|
|
|
|
|
action = sys.argv[1] if (len(sys.argv) > 1) else None
|
|
|
|
if action == 'autoconf':
|
|
try:
|
|
get_monit_status_lines()
|
|
print("yes")
|
|
except OSError:
|
|
print("no (failed to request monit status)")
|
|
elif action == 'config':
|
|
procs = parse_processes()
|
|
print('graph_title Per process stats from Monit')
|
|
print('graph_vlabel usage of memory [MB] or cpu [%]')
|
|
print('graph_category monit')
|
|
for process in procs:
|
|
for stat in procs[process]:
|
|
print("monit_%s_%s.label %s.%s" % (process, stat, process, stat))
|
|
if stat == 'total_memory':
|
|
# the allocated memory may never be zero
|
|
print("monit_%s_%s.warning 1:" % (process, stat))
|
|
else:
|
|
for process, stats in parse_processes().items():
|
|
for stat_key, stat_value in stats.items():
|
|
print("monit_%s_%s.value %s" % (process, stat_key, stat_value))
|