Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / other / icecast_ @ ac7a7ccf

Historique | Voir | Annoter | Télécharger (5,43 ko)

1
#!/usr/bin/env python2.5
2
"""
3
Plugin to monitor icecast2 streaming servers.
4

    
5
Author: Markus Lindenberg <markus.lindenberg@gmail.com>
6
Version: 2009111101
7

    
8
This program is free software: you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation, either version 3 of the License, or
11
(at your option) any later version.
12

    
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17

    
18
You should have received a copy of the GNU General Public License
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.
20

    
21
Usage:
22
	- Link or copy to /etc/munin/plugins
23
	- To enable listening duration, traffic and uptime stats,
24
	also link to icecast_duration, icecast_traffic and
25
	icecast_uptime respectively.
26

    
27
Configuration:
28
	- Enter your server, user and pw below
29
	  (The plugin does not need to run on
30
	  the same host as your icecast2 server)
31
	- Optionally provide hosts to exclude.
32

    
33
Possible TODOs:
34
	- use autoconf
35
	- use munin's configuration system
36
	- documentation
37

    
38
"""
39

    
40
# CONFIGURATION
41

    
42
server = "radio.schlag.fr:2342"
43
user = "lta-admin"
44
pw = "suckm3g00dyaoldbitch"
45

    
46
# Exclude these hosts when calculating listening duration / listeners count
47
# (we use this to prevent our aircheck recording system from appearing in the stats)
48
#exclude = ("123.123.123.123",)
49
exclude = ()
50

    
51
# Exclude these sources from calcultation
52
# Ever add fallback sources to this list
53
#source_exclude = ["/fallback.mp3", "/fallback.ogg"]
54
source_exclude = ("/fallback.mp3", "/fallback.ogg")
55

    
56
# /CONFIGURATION
57

    
58
from sys import argv, exit, stderr
59
import urllib
60
from xml.etree.ElementTree import ElementTree
61
from os.path import basename
62

    
63
class IcecastURLopener(urllib.FancyURLopener):
64
	def prompt_user_passwd(self, host, realm):
65
		return (user, pw)
66

    
67
opener = IcecastURLopener()
68
f = opener.open("http://%s/admin/listmounts" % server)
69

    
70
tree = ElementTree()
71
tree.parse(f)
72
f.close()
73

    
74
sources = []
75
for s in tree.getiterator("source"):
76
	if s.attrib["mount"] not in source_exclude:
77
		sources.append({"mount": s.attrib["mount"],
78
				"listeners": s.find("listeners").text,
79
				"connected": s.find("Connected").text})
80

    
81
plugin_name = basename(argv[0])
82

    
83
try:
84
	if argv[1] == "config":
85
		if plugin_name == "icecast_duration":
86
			print "graph_title Icecast client listening duration"
87
			print "graph_args --base 1000 -l 0"
88
			print "graph_scale no"
89
			print "graph_category Icecast"
90
			print "graph_vlabel minutes"
91
			print "avg.label average listening duration"
92
			print "mdn.label median listening duration"
93
		elif plugin_name == "icecast_uptime":
94
			print "graph_title Icecast source uptime"
95
			print "graph_args --base 1000 -l 0"
96
			print "graph_scale no"
97
			print "graph_category Icecast"
98
			print "graph_vlabel hours"
99
			for s in sources:
100
				print "%s.label source %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), s["mount"])
101
		elif plugin_name == "icecast_traffic":
102
			print "graph_title Icecast outgoing traffic"
103
			print "graph_args --base 1024 -l 0"
104
			print "graph_category Icecast"
105
			print "graph_vlabel bytes / second"
106
			is_first = True
107
			for s in sources:
108
				sname = s["mount"].strip("/").replace(".","_").replace("-","_")
109
				print "%s.label source %s" % (sname, s["mount"])
110
				print "%s.type DERIVE" % sname
111
				print "%s.min 0" % sname
112
				if is_first:
113
					print "%s.draw AREA" % sname
114
					is_first = False
115
				else:
116
					print "%s.draw STACK" % sname
117
		else:
118
			print "graph_title Icecast listeners count"
119
			print "graph_args --base 1000 -l 0"
120
			print "graph_scale no"
121
			print "graph_category Icecast"
122
			print "graph_vlabel listeners"
123
			is_first = True
124
			for s in sources:
125
				sname = s["mount"].strip("/").replace(".","_").replace("-","_")
126
				print "%s.label source %s" % (sname, s["mount"])
127
				if is_first:
128
					print "%s.draw AREA" % sname
129
					is_first = False
130
				else:
131
					print "%s.draw STACK" % sname
132

    
133
		exit(0)
134

    
135
except IndexError:
136
	pass
137

    
138
if plugin_name == "icecast_uptime":
139
	for s in sources:
140
		print "%s.value %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), int(s["connected"]) / 3600.)
141
		
142
elif plugin_name == "icecast_traffic":
143
	f = opener.open("http://%s/admin/stats.xml" % server)
144
	tree = ElementTree()
145
	tree.parse(f)
146
	f.close()
147
	for s in tree.getiterator("source"):
148
		print "%s.value %s" % (s.attrib["mount"].strip("/").replace(".","_").replace("-","_"), s.find("total_bytes_sent").text)
149

    
150
else:
151
	durations = {}
152
	for s in sources:
153
		durations[s["mount"]] = []
154
		f = opener.open("http://%s/admin/listclients?mount=%s" % (server, s["mount"]))
155
		tree = ElementTree()
156
		tree.parse(f)
157
		f.close()
158
		for l in tree.getiterator("listener"):
159
			if l.find("IP").text not in exclude:
160
				durations[s["mount"]].append(int(l.find("Connected").text))
161

    
162
	if plugin_name == "icecast_duration":
163
		if not durations:
164
			exit(0)
165
		alldurations = reduce(lambda x, y: x+y, durations.values())
166
		alldurations.sort()
167
		print "avg.value %s" % (sum(alldurations) / float(len(alldurations)) / 60.,)
168
		if len(alldurations) % 2:
169
			median = alldurations[len(alldurations) / 2] / 60.
170
		elif len(alldurations):
171
			median = (alldurations[len(alldurations) / 2 - 1] + alldurations[len(alldurations) / 2]) / 2. / 60.
172
		else:
173
			median = 0
174
		print "mdn.value %s" % median
175
	else:
176
		for s in sources:
177
			print "%s.value %s" % (s["mount"].strip("/").replace(".","_").replace("-","_"), len(durations[s["mount"]]))
178