diff --git a/plugins/other/icecast_ b/plugins/other/icecast_ new file mode 100755 index 00000000..17857b6a --- /dev/null +++ b/plugins/other/icecast_ @@ -0,0 +1,172 @@ +#!/usr/bin/env python2.5 +""" +Plugin to monitor icecast2 streaming servers. + +Author: Markus Lindenberg +Version: 2009111101 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Usage: + - Link or copy to /etc/munin/plugins + - To enable listening duration, traffic and uptime stats, + also link to icecast_duration, icecast_traffic and + icecast_uptime respectively. + +Configuration: + - Enter your server, user and pw below + (The plugin does not need to run on + the same host as your icecast2 server) + - Optionally provide hosts to exclude. + +Possible TODOs: + - use autoconf + - use munin's configuration system + - documentation + +""" + +# CONFIGURATION + +server = "127.0.0.1:8000" +user = "admin" +pw = "your_icecast_admin_password" + +# Exclude these hosts when calculating listening duration / listeners count +# (we use this to prevent our aircheck recording system from appearing in the stats) +#exclude = ("123.123.123.123",) +exclude = () + +# /CONFIGURATION + +from sys import argv, exit, stderr +import urllib +from xml.etree.ElementTree import ElementTree +from os.path import basename + +class IcecastURLopener(urllib.FancyURLopener): + def prompt_user_passwd(self, host, realm): + return (user, pw) + +opener = IcecastURLopener() +f = opener.open("http://%s/admin/listmounts" % server) + +tree = ElementTree() +tree.parse(f) +f.close() + +sources = [] +for s in tree.getiterator("source"): + sources.append({"mount": s.attrib["mount"], + "listeners": s.find("listeners").text, + "connected": s.find("Connected").text}) + +plugin_name = basename(argv[0]) + +try: + if argv[1] == "config": + if plugin_name == "icecast_duration": + print "graph_title Icecast client listening duration" + print "graph_args --base 1000 -l 0" + print "graph_scale no" + print "graph_category Icecast" + print "graph_vlabel minutes" + print "avg.label average listening duration" + print "mdn.label median listening duration" + elif plugin_name == "icecast_uptime": + print "graph_title Icecast source uptime" + print "graph_args --base 1000 -l 0" + print "graph_scale no" + print "graph_category Icecast" + print "graph_vlabel hours" + for s in sources: + print "%s.label source %s" % (s["mount"].strip("/").replace(".","_"), s["mount"]) + elif plugin_name == "icecast_traffic": + print "graph_title Icecast outgoing traffic" + print "graph_args --base 1024 -l 0" + print "graph_category Icecast" + print "graph_vlabel bytes / second" + is_first = True + for s in sources: + sname = s["mount"].strip("/").replace(".","_") + print "%s.label source %s" % (sname, s["mount"]) + print "%s.type DERIVE" % sname + print "%s.min 0" % sname + if is_first: + print "%s.draw AREA" % sname + is_first = False + else: + print "%s.draw STACK" % sname + else: + print "graph_title Icecast listeners count" + print "graph_args --base 1000 -l 0" + print "graph_scale no" + print "graph_category Icecast" + print "graph_vlabel listeners" + is_first = True + for s in sources: + sname = s["mount"].strip("/").replace(".","_") + print "%s.label source %s" % (sname, s["mount"]) + if is_first: + print "%s.draw AREA" % sname + is_first = False + else: + print "%s.draw STACK" % sname + + exit(0) + +except IndexError: + pass + +if plugin_name == "icecast_uptime": + for s in sources: + print "%s.value %s" % (s["mount"].strip("/").replace(".","_"), int(s["connected"]) / 3600.) + +elif plugin_name == "icecast_traffic": + f = opener.open("http://%s/admin/stats.xml" % server) + tree = ElementTree() + tree.parse(f) + f.close() + for s in tree.getiterator("source"): + print "%s.value %s" % (s.attrib["mount"].strip("/").replace(".","_"), s.find("total_bytes_sent").text) + +else: + durations = {} + for s in sources: + durations[s["mount"]] = [] + f = opener.open("http://%s/admin/listclients?mount=%s" % (server, s["mount"])) + tree = ElementTree() + tree.parse(f) + f.close() + for l in tree.getiterator("listener"): + if l.find("IP").text not in exclude: + durations[s["mount"]].append(int(l.find("Connected").text)) + + if plugin_name == "icecast_duration": + if not durations: + exit(0) + alldurations = reduce(lambda x, y: x+y, durations.values()) + alldurations.sort() + print "avg.value %s" % (sum(alldurations) / float(len(alldurations)) / 60.,) + if len(alldurations) % 2: + median = alldurations[len(alldurations) / 2] / 60. + elif len(alldurations): + median = (alldurations[len(alldurations) / 2 - 1] + alldurations[len(alldurations) / 2]) / 2. / 60. + else: + median = 0 + print "mdn.value %s" % median + else: + for s in sources: + print "%s.value %s" % (s["mount"].strip("/").replace(".","_"), len(durations[s["mount"]])) +