mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-26 02:48:28 +00:00
[monit_parser] change input format to XML; retrieve via URL (Closes: #558)
This commit is contained in:
parent
f69a442779
commit
ef6cedf7a9
1 changed files with 39 additions and 57 deletions
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
@ -8,23 +8,22 @@ monit_parser - Monit status parser plugin for munin.
|
||||||
|
|
||||||
=head1 APPLICABLE SYSTEMS
|
=head1 APPLICABLE SYSTEMS
|
||||||
|
|
||||||
Any system running monit.
|
Any system being able to query monit servers via http.
|
||||||
|
|
||||||
Monit needs to be configured with the httpd port enabled, e.g.:
|
Monit needs to be configured with the httpd port enabled, e.g.:
|
||||||
|
|
||||||
set httpd port 2812
|
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
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
This plugin requires read access for the monit configuration.
|
By default the monit instance at localhost is queried:
|
||||||
Thus it needs to run as root:
|
|
||||||
|
|
||||||
[monit_parser]
|
[monit_parser]
|
||||||
user root
|
env.port 2812
|
||||||
|
env.host localhost
|
||||||
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
@ -41,9 +40,14 @@ Thus it needs to run as root:
|
||||||
=cut
|
=cut
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import xml.dom.minidom
|
||||||
import subprocess
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
MONIT_XML_URL = ("http://{host}:{port}/_status?format=xml"
|
||||||
|
.format(host=os.getenv("host", "localhost"),
|
||||||
|
port=os.getenv("port", "2812")))
|
||||||
|
|
||||||
|
|
||||||
def sanitize(s):
|
def sanitize(s):
|
||||||
|
@ -51,53 +55,31 @@ def sanitize(s):
|
||||||
return "".join([char for char in s if char in OK_CHARS])
|
return "".join([char for char in s if char in OK_CHARS])
|
||||||
|
|
||||||
|
|
||||||
def get_monit_status_lines():
|
def get_monit_status_xml():
|
||||||
# retrieve output
|
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(["monit", "status"])
|
conn = urllib.request.urlopen(MONIT_XML_URL)
|
||||||
error_message = None
|
except urllib.error.URLError as exc:
|
||||||
except (OSError, subprocess.CalledProcessError) as exc:
|
conn = None
|
||||||
error_message = "Error running monit status command: %s" % str(exc)
|
if conn is None:
|
||||||
if error_message is not None:
|
raise RuntimeError("Failed to open monit status URL: {}".format(MONIT_XML_URL))
|
||||||
raise OSError(error_message)
|
else:
|
||||||
# python3: the result of command execution is bytes and needs to be converted
|
return xml.dom.minidom.parse(conn)
|
||||||
if not isinstance(output, str):
|
|
||||||
output = output.decode("ascii", "ignore")
|
|
||||||
return output.splitlines()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_processes():
|
def parse_processes():
|
||||||
cur_proc = None
|
dom = get_monit_status_xml()
|
||||||
procs = {}
|
procs = {}
|
||||||
for line in get_monit_status_lines():
|
for item in dom.getElementsByTagName("service"):
|
||||||
m = re.match("^Process '(.*)'.*$", line)
|
if item.getAttribute("type") == "3":
|
||||||
if m:
|
# daemon with memory usage and CPU
|
||||||
cur_proc = sanitize(m.group(1))
|
name = item.getElementsByTagName("name")[0].childNodes[0].data
|
||||||
try:
|
memory_usage = item.getElementsByTagName("memory")[0].getElementsByTagName(
|
||||||
procs[cur_proc]
|
"kilobytetotal")[0].childNodes[0].data
|
||||||
except KeyError:
|
cpu_usage = item.getElementsByTagName("cpu")[0].getElementsByTagName(
|
||||||
procs[cur_proc] = {}
|
"percenttotal")[0].childNodes[0].data
|
||||||
continue
|
procs[name] = {}
|
||||||
m = re.match(" memory kilobytes total\s+([0-9.]+)(.*)$", line)
|
procs[name]["total_memory"] = memory_usage
|
||||||
if m:
|
procs[name]["total_cpu"] = cpu_usage
|
||||||
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
|
return procs
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,22 +87,22 @@ action = sys.argv[1] if (len(sys.argv) > 1) else None
|
||||||
|
|
||||||
if action == 'autoconf':
|
if action == 'autoconf':
|
||||||
try:
|
try:
|
||||||
get_monit_status_lines()
|
get_monit_status_xml()
|
||||||
print("yes")
|
print("yes")
|
||||||
except OSError:
|
except RuntimeError:
|
||||||
print("no (failed to request monit status)")
|
print("no (failed to request monit status)")
|
||||||
elif action == 'config':
|
elif action == 'config':
|
||||||
procs = parse_processes()
|
procs = parse_processes()
|
||||||
print('graph_title Per process stats from Monit')
|
print('graph_title Per process stats from Monit')
|
||||||
print('graph_vlabel usage of memory [MB] or cpu [%]')
|
print('graph_vlabel usage of memory [kB] or cpu [%]')
|
||||||
print('graph_category monit')
|
print('graph_category monit')
|
||||||
for process in procs:
|
for process in procs:
|
||||||
for stat in procs[process]:
|
for stat in procs[process]:
|
||||||
print("monit_%s_%s.label %s.%s" % (process, stat, process, stat))
|
print("monit_%s_%s.label %s.%s" % (sanitize(process), stat, process, stat))
|
||||||
if stat == 'total_memory':
|
if stat == 'total_memory':
|
||||||
# the allocated memory may never be zero
|
# the allocated memory may never be zero
|
||||||
print("monit_%s_%s.warning 1:" % (process, stat))
|
print("monit_%s_%s.warning 1:" % (sanitize(process), stat))
|
||||||
else:
|
else:
|
||||||
for process, stats in parse_processes().items():
|
for process, stats in parse_processes().items():
|
||||||
for stat_key, stat_value in stats.items():
|
for stat_key, stat_value in stats.items():
|
||||||
print("monit_%s_%s.value %s" % (process, stat_key, stat_value))
|
print("monit_%s_%s.value %s" % (sanitize(process), stat_key, stat_value))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue