Projet

Général

Profil

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

root / plugins / streaming / shoutcast2_multi @ e5ce7492

Historique | Voir | Annoter | Télécharger (13,7 ko)

1
#!/usr/bin/perl
2
#
3
=head1 Shoutcast 2.0.x Plugin
4

    
5
 A Plugin for monitoring a Shoutcast 2.0.x Server (Multigraph)
6

    
7
=head1 Munin Configuration
8

    
9
 [shoutcast2_multi]
10
  env.host 127.0.0.1			*default*
11
  env.port 8000					*default*
12
  env.pass changeme				*default*
13

    
14
=head2 Munin Configuration Explanation
15

    
16
 host = host we are attempting to connection to, can be ip, or hostname
17
 port = port we need to connect to in order to get to admin.cgi
18
 pass = password to use to authenticate as admin user
19

    
20
=head1 AUTHOR
21

    
22
 Matt West < https://github.com/mhwest13 >
23

    
24
=head1 License
25

    
26
 GPLv2
27

    
28
=head1 Magic Markers
29

    
30
#%# family=auto
31
#%# capabilities=autoconf
32

    
33
=cut
34

    
35
use strict;
36
use warnings;
37
use LWP::UserAgent;
38
use XML::Simple;
39
use Munin::Plugin;
40

    
41
need_multigraph();
42

    
43
=head1 Variable Declarations
44

    
45
 This section is mainly for importing / declaring our environment variables.
46
 This is were we will import the data from our plugin-conf.d file so we can
47
 override the default settings which will only work for Shoutcast test configs.
48

    
49
=cut
50

    
51
my $host = $ENV{host} || '127.0.0.1';
52
my $port = $ENV{port} || 8000;
53
my $pass = $ENV{pass} || 'changeme';
54

    
55
# Initialize hashref for storing results information...
56
my $dataRef;
57

    
58
# Create a hashref for our graph information that we will call up later...
59
my $graphsRef;
60

    
61
my $ua = LWP::UserAgent->new();
62
$ua->agent('Munin Shoutcast Plugin/0.1');
63
$ua->timeout(5);
64
$ua->credentials($host.':'.$port, 'Shoutcast Server', 'admin'=>$pass);
65

    
66
=head1 Graphs Declarations
67

    
68
 The following section of code contains our graph information. This is the data
69
 provided to Munin, so that it may properly draw our graphs based on the values
70
 the plugin returns.
71

    
72
 While you are free to change colors or labels changing the type, min, or max
73
 could cause unfortunate problems with your graphs.
74

    
75
=cut
76

    
77
$graphsRef->{active} = {
78
	config => {
79
		args => '--base 1000 --lower-limit 0',
80
		vlabel => 'Is a DJ Actively Connected?',
81
		category => 'shoutcast2',
82
		title => 'Active States',
83
		info => 'This graph shows us the active state or not, depending on if a DJ is connected',
84
	},
85
	datasrc => [
86
		{ name => 'active', draw => 'AREA', min => '0', max => '1', label => 'On or Off', type => 'GAUGE' },
87
	],
88
};
89

    
90
$graphsRef->{listeners} = {
91
	config => {
92
		args => '--base 1000 --lower-limit 0',
93
		vlabel => 'Listener Count',
94
		category => 'shoutcast2',
95
		title => 'Listeners',
96
		info => 'This graph shows us the various counts for listener states we are tracking',
97
	},
98
	datasrc => [
99
		{ name => 'maxlisteners', draw => 'AREA', min => '0', label => 'Max Listeners', type => 'GAUGE' },
100
		{ name => 'currlisteners', draw => 'STACK', min => '0', label => 'Current Listeners', type => 'GAUGE' },
101
	],
102
};
103

    
104
$graphsRef->{sid_active} = {
105
	config => {
106
		args => '--base 1000 --lower-limit 0',
107
		vlabel => 'Is a DJ Actively Connected?',
108
		title => 'Active State',
109
		info => 'This graph shows us the active state or not, depending on if a DJ is connected',
110
	},
111
	datasrc => [
112
		{ name => 'active', draw => 'AREA', min => '0', max => '1', label => 'On or Off', type => 'GAUGE', xmlkey => 'STREAMSTATUS' },
113
	],
114
};
115

    
116
$graphsRef->{sid_listeners} = {
117
	config => {
118
		args => '--base 1000 --lower-limit 0',
119
		vlabel => 'Listener Count',
120
		title => 'Listeners',
121
		info => 'This graph shows us the various counts for listener states we are tracking',
122
	},
123
	datasrc => [
124
		{ name => 'maxlisteners', draw => 'AREA', min => '0', label => 'Max Listeners', type => 'GAUGE', xmlkey => 'MAXLISTENERS' },
125
		{ name => 'currlisteners', draw => 'STACK', min => '0', label => 'Current Listeners', type => 'GAUGE', xmlkey => 'CURRENTLISTENERS' },
126
		{ name => 'peaklisteners', draw => 'LINE2', min => '0', label => 'Peak Listeners', type => 'GAUGE', xmlkey => 'PEAKLISTENERS' },
127
		{ name => 'uniqlisteners', draw => 'LINE2', min => '0', label => 'Unique Listeners', type => 'GAUGE', xmlkey => 'UNIQUELISTENERS' },
128
	],
129
};
130

    
131
if (defined($ARGV[0]) && ($ARGV[0] eq 'config')) {
132
	config();
133
	exit;
134
}
135

    
136
if (defined($ARGV[0]) && (($ARGV[0] eq 'autoconf') || ($ARGV[0] eq 'suggest'))) {
137
	check_autoconf();
138
	exit;
139
}
140

    
141
# I guess we are collecting stats to return, execute main subroutine.
142
main();
143

    
144
exit;
145

    
146
=head1 Subroutines
147

    
148
 The following is a description of what each subroutine is for and does
149

    
150
=head2 main
151

    
152
 This subroutine is our main routine should we not be calling up autoconf
153
 or config. Ultimately this routine will print out the values for each graph
154
 and graph data point we are tracking.
155

    
156
=cut
157

    
158
sub main {
159
	my ($returnBit,$adminRef) = fetch_admin_data();
160
	if ($returnBit == 0) {
161
		exit;
162
	}
163
	my $streamConfigRef = $adminRef->{STREAMCONFIGS}->{STREAMCONFIG};
164
	my $sidDataRef;
165
	if ($adminRef->{STREAMCONFIGS}->{TOTALCONFIGS} == 1) {
166
		my $sid = $streamConfigRef->{id};
167
		my ($return,$tmpSidRef) = fetch_sid_data($sid);
168
		if ($return == 0) {
169
			# Only one stream, and we didn't get a good response.
170
			exit;
171
		}
172
		$sidDataRef->{$sid} = $tmpSidRef;
173
	} else {
174
		foreach my $sid (keys %{$streamConfigRef}) {
175
			my ($return,$tmpSidRef) = fetch_sid_data($sid);
176
			if ($return == 0) {
177
				next;
178
			}
179
			$sidDataRef->{$sid} = $tmpSidRef;
180
		}
181
	}
182
	print_active_data($sidDataRef);
183
	print_listener_data($adminRef->{STREAMCONFIGS}->{SERVERMAXLISTENERS}, $sidDataRef);
184
	return;
185
}
186

    
187
=head2 print_active_data
188

    
189
 Thie subroutine prints out the active graph values for each stream and ultimately for
190
 the entire shoutcast service. Should 1 Stream be active, but 5 streams available,
191
 the global graph should show the state as active for the service, but clicking into
192
 that graph, should give you a stream level view of which stream was in use during
193
 what time periods.
194

    
195
=cut
196

    
197
sub print_active_data {
198
	my ($sidDataRef) = (@_);
199
	my $globalActive = 0;
200
	foreach my $sid (sort keys %{$sidDataRef}) {
201
		print "multigraph shoutcast2_active.active_sid_$sid\n";
202
		foreach my $dsrc (@{$graphsRef->{sid_active}->{datasrc}}) {
203
			print "$dsrc->{name}.value $sidDataRef->{$sid}->{$dsrc->{xmlkey}}\n";	
204
			if ($sidDataRef->{$sid}->{$dsrc->{xmlkey}} == 1) {
205
				$globalActive = 1;
206
			}
207
		}
208
	}
209
	print "multigraph shoutcast2_active\n";
210
	foreach my $dsrc (@{$graphsRef->{active}->{datasrc}}) {
211
		print "$dsrc->{name}.value $globalActive\n";
212
	}
213
	return;
214
}
215

    
216
=head2 print_listener_data
217

    
218
 This subroutine prints out the listener graph values for each stream and ultimately
219
 adds all of the current users together to show that against the maxserver count in 
220
 the global graph. Clicking on the global graph will reveal a bit more information
221
 about the users on a stream by stream basis.
222

    
223
=cut
224

    
225
sub print_listener_data {
226
	my ($maxListeners,$sidDataRef) = (@_);
227
	my $globalListeners = 0;
228
	foreach my $sid (sort keys %{$sidDataRef}) {
229
		print "multigraph shoutcast2_listeners.listeners_sid_$sid\n";
230
		foreach my $dsrc (@{$graphsRef->{sid_listeners}->{datasrc}}) {
231
			print "$dsrc->{name}.value $sidDataRef->{$sid}->{$dsrc->{xmlkey}}\n";	
232
			if ($dsrc->{name} eq 'currlisteners') {
233
				$globalListeners += $sidDataRef->{$sid}->{$dsrc->{xmlkey}};
234
			}
235
		}
236
	}
237
	print "multigraph shoutcast2_listeners\n";
238
	foreach my $dsrc (@{$graphsRef->{listeners}->{datasrc}}) {
239
		if ($dsrc->{name} eq 'maxlisteners') {
240
			print "$dsrc->{name}.value $maxListeners\n";
241
		} else {
242
			print "$dsrc->{name}.value $globalListeners\n";
243
		}
244
	}
245
	return;
246
}
247

    
248
=head2 config
249

    
250
 The config subroutine can be seen as the main config routine, which
251
 will call up to your shoutcast server to figure out how many streams
252
 you have running, and then print out the appropriate multigraph info.
253
 Ultimately this subroutine will call two more routines to print out
254
 the graph args / configuration information.
255

    
256
=cut
257

    
258
sub config {
259
	my ($returnBit,$adminRef) = fetch_admin_data();
260
	if ($returnBit == 0) {
261
		# $adminRef returned a string, we'll just print it out.
262
		print "no (error response: $adminRef)\n";
263
		exit;
264
	}
265
	my $streamConfigRef = $adminRef->{STREAMCONFIGS}->{STREAMCONFIG};
266
	my $sidDataRef;
267
	if ($adminRef->{STREAMCONFIGS}->{TOTALCONFIGS} == 1) {
268
		my $sid = $streamConfigRef->{id};
269
		my ($return,$tmpSidRef) = fetch_sid_data($sid);
270
		if ($return == 0) {
271
			# Only one stream, and we didn't get a good response.
272
			exit;
273
		}
274
		$sidDataRef->{$sid} = $tmpSidRef;
275
	} else {
276
		foreach my $sid (keys %{$streamConfigRef}) {
277
			my ($return,$tmpSidRef) = fetch_sid_data($sid);
278
			if ($return == 0) {
279
				next;
280
			}
281
			$sidDataRef->{$sid} = $tmpSidRef;
282
		}
283
	}
284
	print_active_config($sidDataRef);
285
	print_listener_config($sidDataRef);
286
	return;	
287
}
288

    
289
=head2 print_active_config
290

    
291
 This subroutine prints out the graph information for our active graphs.
292
 It prints the sub-multigraphs first based on stream id, and finally the
293
 root active graph. Its not suggested that you mess with this routine
294
 unless you fully understand what its doing and how munin graph_args work.
295

    
296
=cut
297

    
298
sub print_active_config {
299
	my ($sidDataRef) = (@_);
300
	foreach my $sid (sort keys %{$sidDataRef}) {
301
		# Print the Config Info First
302
		print "multigraph shoutcast2_active.active\_sid\_$sid\n";
303
		print "graph_title ".$graphsRef->{sid_active}->{config}->{title}." for StreamID: $sid\n";
304
		print "graph_args ".$graphsRef->{sid_active}->{config}->{args}."\n";
305
		print "graph_vlabel ".$graphsRef->{sid_active}->{config}->{vlabel}."\n";
306
		print "graph_category streamid_$sid\n";
307
		print "graph_info ".$graphsRef->{sid_active}->{config}->{info}."\n";
308
		# Print the Data Value Info
309
		foreach my $dsrc (@{$graphsRef->{sid_active}->{datasrc}}) {
310
			while ( my ($key, $value) = each (%{$dsrc})) {
311
				next if ($key eq 'name');
312
				next if ($key eq 'xmlkey');
313
				print "$dsrc->{name}.$key $value\n";
314
			}
315
		}
316
	}
317
	print "multigraph shoutcast2_active\n";
318
	print "graph_title ".$graphsRef->{active}->{config}->{title}."\n";
319
	print "graph_args ".$graphsRef->{active}->{config}->{args}."\n";
320
	print "graph_vlabel ".$graphsRef->{active}->{config}->{vlabel}."\n";
321
	print "graph_category ".$graphsRef->{active}->{config}->{category}."\n";
322
	print "graph_info ".$graphsRef->{active}->{config}->{info}."\n";
323
	# Print the Data Value Info
324
	foreach my $dsrc (@{$graphsRef->{active}->{datasrc}}) {
325
		while ( my ($key, $value) = each (%{$dsrc})) {
326
			next if ($key eq 'name');
327
			print "$dsrc->{name}.$key $value\n";
328
		}
329
	}
330
	return;
331
}
332

    
333
=head2 print_listener_config
334

    
335
 This subroutine prints out the graph information for our listeners graphs.
336
 It prints the sub-multigraphs first based on stream id, and finally the
337
 root listeners graph. Its not suggested that you mess with this routine
338
 unless you fully understand what its doing and how munin graph_args work.
339

    
340
=cut
341

    
342
sub print_listener_config {
343
	my ($sidDataRef) = (@_);
344
	foreach my $sid (sort keys %{$sidDataRef}) {
345
		# Print the Config Info First
346
		print "multigraph shoutcast2_listeners.listeners\_sid\_$sid\n";
347
		print "graph_title ".$graphsRef->{sid_listeners}->{config}->{title}." for StreamID: $sid\n";
348
		print "graph_args ".$graphsRef->{sid_listeners}->{config}->{args}."\n";
349
		print "graph_vlabel ".$graphsRef->{sid_listeners}->{config}->{vlabel}."\n";
350
		print "graph_category streamid_$sid\n";
351
		print "graph_info ".$graphsRef->{sid_listeners}->{config}->{info}."\n";
352
		# Print the Data Value Info
353
		foreach my $dsrc (@{$graphsRef->{sid_listeners}->{datasrc}}) {
354
			while ( my ($key, $value) = each (%{$dsrc})) {
355
				next if ($key eq 'name');
356
				next if ($key eq 'xmlkey');
357
				print "$dsrc->{name}.$key $value\n";
358
			}
359
		}
360
	}
361
	print "multigraph shoutcast2_listeners\n";
362
	print "graph_title ".$graphsRef->{listeners}->{config}->{title}."\n";
363
	print "graph_args ".$graphsRef->{listeners}->{config}->{args}."\n";
364
	print "graph_vlabel ".$graphsRef->{listeners}->{config}->{vlabel}."\n";
365
	print "graph_category ".$graphsRef->{listeners}->{config}->{category}."\n";
366
	print "graph_info ".$graphsRef->{listeners}->{config}->{info}."\n";
367
	# Print the Data Value Info
368
	foreach my $dsrc (@{$graphsRef->{listeners}->{datasrc}}) {
369
		while ( my ($key, $value) = each (%{$dsrc})) {
370
			next if ($key eq 'name');
371
			print "$dsrc->{name}.$key $value\n";
372
		}
373
	}
374
	return;
375
}
376

    
377
=head2 check_autoconf
378

    
379
 This subroutine is called up when we intercept autoconf specified in ARGV[0]
380
 If we are able to connect to the shoutcast service as admin and fetch the main
381
 admin stats page, we will return ok, otherwise we will return no and the error
382
 response we got from LWP::UserAgent.
383

    
384
=cut
385

    
386
sub check_autoconf {
387
	my ($returnBit,$adminRef) = fetch_admin_data();
388
	if ($returnBit == 0) {
389
		# $adminRef returned a string, we'll just print it out.
390
		print "no (error response: $adminRef)\n";
391
	} else {
392
		print "yes\n";
393
	}
394
	return;
395
}
396

    
397
=head2 fetch_sid_data
398

    
399
 This subroutine is called up to fetch information on a per stream mentality.
400
 If we are able to connect to the shoutcast service and get the stats we will
401
 return 1 and a hashref of the de-coded xml information, otherwise we return 0
402
 so that we know that we have failed and can handle it gracefully.
403

    
404
=cut
405

    
406
sub fetch_sid_data {
407
	my ($sid) = (@_);
408
	my $url = 'http://'.$host.':'.$port.'/stats?sid='.$sid;
409
	my $response = $ua->get($url);
410
	if ($response->is_success) {
411
		my $returnRef = XMLin($response->decoded_content);
412
		return (1, $returnRef);	
413
	} else {
414
		return (0, $response->status_line);
415
	}
416
}
417

    
418
=head2 fetch_admin_data
419

    
420
 This subroutine is called up to fetch information from the admin page to get stream ids.
421
 This subroutine is also used to test that we can connect to the shoutcast service
422
 and if not we can fail gracefully. If we are able to connect to the shoutcast service
423
 and get the stats we will return 1 and a hashref of the de-coded xml information,
424
 otherwise we return 0 so that we know that we have failed and can handle it gracefully.
425

    
426
=cut
427

    
428
sub fetch_admin_data {
429
	my $url = 'http://'.$host.':'.$port.'/admin.cgi?sid=1&mode=viewxml&page=6';
430
	my $response = $ua->get($url);
431
	if ($response->is_success) {
432
		my $returnRef = XMLin($response->decoded_content);
433
		if (($returnRef->{STREAMCONFIGS}->{TOTALCONFIGS} > 0) && (defined($returnRef->{STREAMCONFIGS}->{STREAMCONFIG}))) {
434
			return (1, $returnRef);	
435
		} else {
436
			return (0, 'Unable to Detect any Stream Configurations');
437
		}
438
	} else {
439
		return (0, $response->status_line);
440
	}
441
}
442