From ce26420aee83466cb54bcf07283a8e43af9f775f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 26 Feb 2018 14:47:49 +0100 Subject: Rename stats_dabmux_multi to stats_dabmux_munin --- doc/README.md | 2 +- doc/stats_dabmux_multi.py | 264 ---------------------------------------------- doc/stats_dabmux_munin.py | 264 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 265 deletions(-) delete mode 100755 doc/stats_dabmux_multi.py create mode 100755 doc/stats_dabmux_munin.py diff --git a/doc/README.md b/doc/README.md index 45669f4..ea02670 100644 --- a/doc/README.md +++ b/doc/README.md @@ -49,7 +49,7 @@ An explanation on how to use the remote control is in *remote_control.txt*, and *zmq_remote.py* illustrates how to control ODR-DabMux using the ZMQ remote control interface. -Two scripts are used for monitoring systems: *stats_dabmux_multi.py* for Munin, +Two scripts are used for monitoring systems: *stats_dabmux_munin.py* for Munin, and *retodrs.pl* for Xymon. You can use *show_dabmux_stats.py* to print the statistics to console. diff --git a/doc/stats_dabmux_multi.py b/doc/stats_dabmux_multi.py deleted file mode 100755 index e374e07..0000000 --- a/doc/stats_dabmux_multi.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/env python2 -# -# present statistics from dabmux Stats Server and ZeroMQ RC -# to munin. Expects Stats server on port 12720 and ZeroMQ RC -# on port 12722. -# -# Copy this to /etc/munin/plugins/stats_dabmux_multi -# and make it executable (chmod +x) - -import sys -import json -import zmq -import os -import re - -config_top = """ -multigraph clocktai_expiry -graph_title Time to expiry for TAI bulletin -graph_order expiry -graph_args --base 1000 -graph_vlabel Number of seconds until expiry -graph_category dabmux -graph_info This graph shows the number of remaining seconds this bulletin is valid - -expiry.info Seconds until expiry -expiry.label Seconds until expiry -expiry.min 0 -expiry.warning {onemonth}: -""".format(onemonth=3600*24*30) - -#default data type is GAUGE - -config_template = """ -multigraph buffers_{ident} -graph_title Contribution {ident} buffer -graph_order high low -graph_args --base 1000 -graph_vlabel max/min buffer size bytes during last ${{graph_period}} -graph_category dabmux -graph_info This graph shows the high and low buffer sizes for the {ident} ZMQ input - -high.info Max buffer size -high.label Max Buffer Bytes -high.min 0 -high.warning 1: -low.info Min buffer size -low.label Min Buffer Bytes -low.min 0 -low.warning 1: - -multigraph over_underruns_{ident} -graph_title Contribution {ident} over/underruns -graph_order underruns overruns -graph_args --base 1000 --logarithmic -graph_vlabel number of underruns/overruns during last ${{graph_period}} -graph_category dabmux -graph_info This graph shows the number of under/overruns for the {ident} ZMQ input - -underruns.info Number of underruns -underruns.label Number of underruns -underruns.min 0 -underruns.warning 0:0 -underruns.type COUNTER -overruns.info Number of overruns -overruns.label Number of overruns -overruns.min 0 -overruns.warning 0:0 -overruns.type COUNTER - -multigraph audio_levels_{ident} -graph_title Contribution {ident} audio level (peak) -graph_order left right -graph_args --base 1000 -graph_vlabel peak audio level during last ${{graph_period}} -graph_category encoders -graph_info This graph shows the audio level of both channels of the {ident} ZMQ input - -left.info Left channel audio level -left.label Left channel audio level -left.min -90 -left.max 0 -left.warning -40:0 -left.critical -80:0 -right.info Right channel audio level -right.label Right channel audio level -right.min -90 -right.max 0 -right.warning -40:0 -right.critical -80:0 - -multigraph state_{ident} -graph_title State of contribution {ident} -graph_order state -graph_args --base 1000 --lower-limit 0 --upper-limit 5 -graph_vlabel Current state of the input -graph_category dabmux -graph_info This graph shows the state for the {ident} ZMQ input - -state.info Input state -state.label 0 Unknown, 1 NoData, 2 Unstable, 3 Silent, 4 Streaming -state.warning 4:4 -state.critical 2:4 -""" - -ctx = zmq.Context() - -class RCException(Exception): - pass - -if not os.environ.get("MUNIN_CAP_MULTIGRAPH"): - sys.stderr.write("This needs munin version 1.4 at least\n") - sys.exit(1) - -def do_transaction(command, sock): - """To a send + receive transaction, quit whole program on timeout""" - sock.send(command) - - poller = zmq.Poller() - poller.register(sock, zmq.POLLIN) - - socks = dict(poller.poll(1000)) - if socks: - if socks.get(sock) == zmq.POLLIN: - return sock.recv() - - sys.stderr.write("Could not receive data for command '{}'\n".format(command)) - sys.exit(1) - -def do_multipart_transaction(message_parts, sock): - """To a send + receive transaction, quit whole program on timeout""" - if isinstance(message_parts, str): - sys.stderr.write("do_transaction expects a list!\n"); - sys.exit(1) - - for i, part in enumerate(message_parts): - if i == len(message_parts) - 1: - f = 0 - else: - f = zmq.SNDMORE - sock.send(part, flags=f) - - poller = zmq.Poller() - poller.register(sock, zmq.POLLIN) - - socks = dict(poller.poll(1000)) - if socks: - if socks.get(sock) == zmq.POLLIN: - rxpackets = sock.recv_multipart() - return rxpackets - - raise RCException("Could not receive data for command '{}'\n".format( - message_parts)) - -def get_rc_value(module, name, sock): - try: - parts = do_multipart_transaction([b"get", module.encode(), name.encode()], - sock) - if len(parts) != 1: - sys.stderr.write("Received unexpected multipart message {}\n".format( - parts)) - sys.exit(1) - return parts[0].decode() - except RCException as e: - print("get {} {} fail: {}".format(module, name, e)) - return "" - -def connect_to_stats(): - """Create a connection to the dabmux stats server - - returns: the socket""" - - sock = zmq.Socket(ctx, zmq.REQ) - sock.set(zmq.LINGER, 5) - sock.connect("tcp://localhost:12720") - - version = json.loads(do_transaction("info", sock)) - - if not version['service'].startswith("ODR-DabMux"): - sys.stderr.write("Wrong version\n") - sys.exit(1) - - return sock - -def connect_to_rc(): - """Create a connection to the dabmux RC - - returns: the socket""" - - sock = zmq.Socket(ctx, zmq.REQ) - sock.set(zmq.LINGER, 5) - sock.connect("tcp://localhost:12722") - - try: - ping_answer = do_multipart_transaction([b"ping"], sock) - - if not ping_answer == [b"ok"]: - sys.stderr.write("Wrong answer to ping\n") - sys.exit(1) - except RCException as e: - print("connect failed because: {}".format(e)) - sys.exit(1) - - return sock - -def handle_re(graph_name, re, rc_value, group_number=1): - match = re.search(rc_value) - if match: - return "{}.value {}\n".format(graph_name, match.group(group_number)) - else: - return "{}.value U\n".format(graph_name) - -if len(sys.argv) == 1: - munin_values = "" - - sock_rc = connect_to_rc() - clocktai_expiry = get_rc_value("clocktai", "expiry", sock_rc) - re_clocktai_expiry = re.compile(r"(\d+)", re.X) - munin_values += "multigraph clocktai_expiry\n" - munin_values += handle_re("expiry", re_clocktai_expiry, clocktai_expiry) - - sock_stats = connect_to_stats() - values = json.loads(do_transaction("values", sock_stats))['values'] - - for ident in values: - v = values[ident]['inputstat'] - - ident_ = ident.replace('-', '_') - munin_values += "multigraph buffers_{ident}\n".format(ident=ident_) - munin_values += "high.value {}\n".format(v['max_fill']) - munin_values += "low.value {}\n".format(v['min_fill']) - munin_values += "multigraph over_underruns_{ident}\n".format(ident=ident_) - munin_values += "underruns.value {}\n".format(v['num_underruns']) - munin_values += "overruns.value {}\n".format(v['num_overruns']) - munin_values += "multigraph audio_levels_{ident}\n".format(ident=ident_) - munin_values += "left.value {}\n".format(v['peak_left']) - munin_values += "right.value {}\n".format(v['peak_right']) - - if 'state' in v: - # If ODR-DabMux is v1.3.1-3 or older, it doesn't export state - re_state = re.compile(r"\w+ \((\d+)\)") - match = re_state.match(v['state']) - if match: - munin_values += "multigraph state_{ident}\n".format(ident=ident_) - munin_values += "state.value {}\n".format(match.group(1)) - else: - sys.stderr.write("Cannot parse state '{}'\n".format(v['state'])) - - print(munin_values) - -elif len(sys.argv) == 2 and sys.argv[1] == "config": - sock_stats = connect_to_stats() - - config = json.loads(do_transaction("config", sock_stats)) - - munin_config = config_top - - for conf in config['config']: - munin_config += config_template.format(ident=conf.replace('-', '_')) - - print(munin_config) -else: - sys.stderr.write("Invalid command line arguments") - sys.exit(1) - diff --git a/doc/stats_dabmux_munin.py b/doc/stats_dabmux_munin.py new file mode 100755 index 0000000..7a134ef --- /dev/null +++ b/doc/stats_dabmux_munin.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python2 +# +# present statistics from dabmux Stats Server and ZeroMQ RC +# to munin. Expects Stats server on port 12720 and ZeroMQ RC +# on port 12722. +# +# Copy this to /etc/munin/plugins/stats_dabmux_munin +# and make it executable (chmod +x) + +import sys +import json +import zmq +import os +import re + +config_top = """ +multigraph clocktai_expiry +graph_title Time to expiry for TAI bulletin +graph_order expiry +graph_args --base 1000 +graph_vlabel Number of seconds until expiry +graph_category dabmux +graph_info This graph shows the number of remaining seconds this bulletin is valid + +expiry.info Seconds until expiry +expiry.label Seconds until expiry +expiry.min 0 +expiry.warning {onemonth}: +""".format(onemonth=3600*24*30) + +#default data type is GAUGE + +config_template = """ +multigraph buffers_{ident} +graph_title Contribution {ident} buffer +graph_order high low +graph_args --base 1000 +graph_vlabel max/min buffer size bytes during last ${{graph_period}} +graph_category dabmux +graph_info This graph shows the high and low buffer sizes for the {ident} ZMQ input + +high.info Max buffer size +high.label Max Buffer Bytes +high.min 0 +high.warning 1: +low.info Min buffer size +low.label Min Buffer Bytes +low.min 0 +low.warning 1: + +multigraph over_underruns_{ident} +graph_title Contribution {ident} over/underruns +graph_order underruns overruns +graph_args --base 1000 --logarithmic +graph_vlabel number of underruns/overruns during last ${{graph_period}} +graph_category dabmux +graph_info This graph shows the number of under/overruns for the {ident} ZMQ input + +underruns.info Number of underruns +underruns.label Number of underruns +underruns.min 0 +underruns.warning 0:0 +underruns.type COUNTER +overruns.info Number of overruns +overruns.label Number of overruns +overruns.min 0 +overruns.warning 0:0 +overruns.type COUNTER + +multigraph audio_levels_{ident} +graph_title Contribution {ident} audio level (peak) +graph_order left right +graph_args --base 1000 +graph_vlabel peak audio level during last ${{graph_period}} +graph_category encoders +graph_info This graph shows the audio level of both channels of the {ident} ZMQ input + +left.info Left channel audio level +left.label Left channel audio level +left.min -90 +left.max 0 +left.warning -40:0 +left.critical -80:0 +right.info Right channel audio level +right.label Right channel audio level +right.min -90 +right.max 0 +right.warning -40:0 +right.critical -80:0 + +multigraph state_{ident} +graph_title State of contribution {ident} +graph_order state +graph_args --base 1000 --lower-limit 0 --upper-limit 5 +graph_vlabel Current state of the input +graph_category dabmux +graph_info This graph shows the state for the {ident} ZMQ input + +state.info Input state +state.label 0 Unknown, 1 NoData, 2 Unstable, 3 Silent, 4 Streaming +state.warning 4:4 +state.critical 2:4 +""" + +ctx = zmq.Context() + +class RCException(Exception): + pass + +if not os.environ.get("MUNIN_CAP_MULTIGRAPH"): + sys.stderr.write("This needs munin version 1.4 at least\n") + sys.exit(1) + +def do_transaction(command, sock): + """To a send + receive transaction, quit whole program on timeout""" + sock.send(command) + + poller = zmq.Poller() + poller.register(sock, zmq.POLLIN) + + socks = dict(poller.poll(1000)) + if socks: + if socks.get(sock) == zmq.POLLIN: + return sock.recv() + + sys.stderr.write("Could not receive data for command '{}'\n".format(command)) + sys.exit(1) + +def do_multipart_transaction(message_parts, sock): + """To a send + receive transaction, quit whole program on timeout""" + if isinstance(message_parts, str): + sys.stderr.write("do_transaction expects a list!\n"); + sys.exit(1) + + for i, part in enumerate(message_parts): + if i == len(message_parts) - 1: + f = 0 + else: + f = zmq.SNDMORE + sock.send(part, flags=f) + + poller = zmq.Poller() + poller.register(sock, zmq.POLLIN) + + socks = dict(poller.poll(1000)) + if socks: + if socks.get(sock) == zmq.POLLIN: + rxpackets = sock.recv_multipart() + return rxpackets + + raise RCException("Could not receive data for command '{}'\n".format( + message_parts)) + +def get_rc_value(module, name, sock): + try: + parts = do_multipart_transaction([b"get", module.encode(), name.encode()], + sock) + if len(parts) != 1: + sys.stderr.write("Received unexpected multipart message {}\n".format( + parts)) + sys.exit(1) + return parts[0].decode() + except RCException as e: + print("get {} {} fail: {}".format(module, name, e)) + return "" + +def connect_to_stats(): + """Create a connection to the dabmux stats server + + returns: the socket""" + + sock = zmq.Socket(ctx, zmq.REQ) + sock.set(zmq.LINGER, 5) + sock.connect("tcp://localhost:12720") + + version = json.loads(do_transaction("info", sock)) + + if not version['service'].startswith("ODR-DabMux"): + sys.stderr.write("Wrong version\n") + sys.exit(1) + + return sock + +def connect_to_rc(): + """Create a connection to the dabmux RC + + returns: the socket""" + + sock = zmq.Socket(ctx, zmq.REQ) + sock.set(zmq.LINGER, 5) + sock.connect("tcp://localhost:12722") + + try: + ping_answer = do_multipart_transaction([b"ping"], sock) + + if not ping_answer == [b"ok"]: + sys.stderr.write("Wrong answer to ping\n") + sys.exit(1) + except RCException as e: + print("connect failed because: {}".format(e)) + sys.exit(1) + + return sock + +def handle_re(graph_name, re, rc_value, group_number=1): + match = re.search(rc_value) + if match: + return "{}.value {}\n".format(graph_name, match.group(group_number)) + else: + return "{}.value U\n".format(graph_name) + +if len(sys.argv) == 1: + munin_values = "" + + sock_rc = connect_to_rc() + clocktai_expiry = get_rc_value("clocktai", "expiry", sock_rc) + re_clocktai_expiry = re.compile(r"(\d+)", re.X) + munin_values += "multigraph clocktai_expiry\n" + munin_values += handle_re("expiry", re_clocktai_expiry, clocktai_expiry) + + sock_stats = connect_to_stats() + values = json.loads(do_transaction("values", sock_stats))['values'] + + for ident in values: + v = values[ident]['inputstat'] + + ident_ = ident.replace('-', '_') + munin_values += "multigraph buffers_{ident}\n".format(ident=ident_) + munin_values += "high.value {}\n".format(v['max_fill']) + munin_values += "low.value {}\n".format(v['min_fill']) + munin_values += "multigraph over_underruns_{ident}\n".format(ident=ident_) + munin_values += "underruns.value {}\n".format(v['num_underruns']) + munin_values += "overruns.value {}\n".format(v['num_overruns']) + munin_values += "multigraph audio_levels_{ident}\n".format(ident=ident_) + munin_values += "left.value {}\n".format(v['peak_left']) + munin_values += "right.value {}\n".format(v['peak_right']) + + if 'state' in v: + # If ODR-DabMux is v1.3.1-3 or older, it doesn't export state + re_state = re.compile(r"\w+ \((\d+)\)") + match = re_state.match(v['state']) + if match: + munin_values += "multigraph state_{ident}\n".format(ident=ident_) + munin_values += "state.value {}\n".format(match.group(1)) + else: + sys.stderr.write("Cannot parse state '{}'\n".format(v['state'])) + + print(munin_values) + +elif len(sys.argv) == 2 and sys.argv[1] == "config": + sock_stats = connect_to_stats() + + config = json.loads(do_transaction("config", sock_stats)) + + munin_config = config_top + + for conf in config['config']: + munin_config += config_template.format(ident=conf.replace('-', '_')) + + print(munin_config) +else: + sys.stderr.write("Invalid command line arguments") + sys.exit(1) + -- cgit v1.2.3