2009-11-11 23:33:12 +01:00
|
|
|
#!/usr/bin/env python2.5
|
|
|
|
"""
|
|
|
|
Plugin to monitor icecast2 streaming servers.
|
|
|
|
|
|
|
|
Author: Markus Lindenberg <markus.lindenberg@gmail.com>
|
2010-08-21 17:41:19 +02:00
|
|
|
COntributors: Julien 'Lta' BALLET <elthariel@gmail.com>
|
2009-11-11 23:33:12 +01:00
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
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.
|
2010-08-21 17:41:19 +02:00
|
|
|
- Optionally provide sources to exclude.
|
2009-11-11 23:33:12 +01:00
|
|
|
|
|
|
|
Possible TODOs:
|
|
|
|
- use autoconf
|
|
|
|
- use munin's configuration system
|
|
|
|
- documentation
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
# CONFIGURATION
|
|
|
|
|
2010-08-21 17:41:19 +02:00
|
|
|
server = "localhost:8000"
|
|
|
|
user = "admin"
|
|
|
|
pw = "yourpassword"
|
2009-11-11 23:33:12 +01:00
|
|
|
|
|
|
|
# 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 = ()
|
|
|
|
|
2014-12-05 00:37:42 +01:00
|
|
|
# Exclude these sources from calculation. This is useful to excluse special sources like
|
2010-08-21 17:41:19 +02:00
|
|
|
# fallback sources which doesn't expose the same informations and then break this script
|
2010-08-21 17:25:35 +02:00
|
|
|
# Ever add fallback sources to this list
|
|
|
|
#source_exclude = ["/fallback.mp3", "/fallback.ogg"]
|
|
|
|
source_exclude = ("/fallback.mp3", "/fallback.ogg")
|
|
|
|
|
2009-11-11 23:33:12 +01:00
|
|
|
# /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"):
|
2010-08-21 17:25:35 +02:00
|
|
|
if s.attrib["mount"] not in source_exclude:
|
|
|
|
sources.append({"mount": s.attrib["mount"],
|
|
|
|
"listeners": s.find("listeners").text,
|
|
|
|
"connected": s.find("Connected").text})
|
2009-11-11 23:33:12 +01:00
|
|
|
|
|
|
|
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"
|
2014-09-06 22:28:53 +02:00
|
|
|
print "graph_category streaming"
|
2009-11-11 23:33:12 +01:00
|
|
|
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"
|
2014-09-06 22:28:53 +02:00
|
|
|
print "graph_category streaming"
|
2009-11-11 23:33:12 +01:00
|
|
|
print "graph_vlabel hours"
|
|
|
|
for s in sources:
|
2010-08-21 17:25:35 +02:00
|
|
|
print "%s.label source %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), s["mount"])
|
2009-11-11 23:33:12 +01:00
|
|
|
elif plugin_name == "icecast_traffic":
|
|
|
|
print "graph_title Icecast outgoing traffic"
|
|
|
|
print "graph_args --base 1024 -l 0"
|
2014-09-06 22:28:53 +02:00
|
|
|
print "graph_category streaming"
|
2009-11-11 23:33:12 +01:00
|
|
|
print "graph_vlabel bytes / second"
|
|
|
|
is_first = True
|
|
|
|
for s in sources:
|
2010-08-21 17:25:35 +02:00
|
|
|
sname = s["mount"].strip("/").replace(".","_").replace("-","_")
|
2009-11-11 23:33:12 +01:00
|
|
|
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"
|
2014-09-06 22:28:53 +02:00
|
|
|
print "graph_category streaming"
|
2009-11-11 23:33:12 +01:00
|
|
|
print "graph_vlabel listeners"
|
|
|
|
is_first = True
|
|
|
|
for s in sources:
|
2010-08-21 17:25:35 +02:00
|
|
|
sname = s["mount"].strip("/").replace(".","_").replace("-","_")
|
2009-11-11 23:33:12 +01:00
|
|
|
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:
|
2010-08-21 17:25:35 +02:00
|
|
|
print "%s.value %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), int(s["connected"]) / 3600.)
|
2009-11-11 23:33:12 +01:00
|
|
|
|
|
|
|
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"):
|
2010-08-21 17:25:35 +02:00
|
|
|
print "%s.value %s" % (s.attrib["mount"].strip("/").replace(".","_").replace("-","_"), s.find("total_bytes_sent").text)
|
2009-11-11 23:33:12 +01:00
|
|
|
|
|
|
|
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:
|
2010-08-21 17:25:35 +02:00
|
|
|
print "%s.value %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), len(durations[s["mount"]]))
|
2009-11-11 23:33:12 +01:00
|
|
|
|