#!/usr/bin/perl # =head1 Shoutcast 2.0.x Plugin A Plugin for monitoring a Shoutcast 2.0.x Server (Multigraph) =head1 Munin Configuration [shoutcast2_multi] env.host 127.0.0.1 *default* env.port 8000 *default* env.pass changeme *default* =head2 Munin Configuration Explanation host = host we are attempting to connection to, can be ip, or hostname port = port we need to connect to in order to get to admin.cgi pass = password to use to authenticate as admin user =head1 License GPLv2 =head1 Magic Markers #%# family=auto #%# capabilities=autoconf =cut use strict; use warnings; use LWP::UserAgent; use XML::Simple; use Munin::Plugin; need_multigraph(); =head1 Variable Declarations This section is mainly for importing / declaring our environment variables. This is were we will import the data from our plugin-conf.d file so we can override the default settings which will only work for Shoutcast test configs. =cut my $host = $ENV{host} || '127.0.0.1'; my $port = $ENV{port} || 8000; my $pass = $ENV{pass} || 'changeme'; # Initialize hashref for storing results information... my $dataRef; # Create a hashref for our graph information that we will call up later... my $graphsRef; my $ua = LWP::UserAgent->new(); $ua->agent('Munin Shoutcast Plugin/0.1'); $ua->timeout(5); $ua->credentials($host.':'.$port, 'Shoutcast Server', 'admin'=>$pass); =head1 Graphs Declarations The following section of code contains our graph information. This is the data provided to Munin, so that it may properly draw our graphs based on the values the plugin returns. While you are free to change colors or labels changing the type, min, or max could cause unfortunate problems with your graphs. =cut $graphsRef->{active} = { config => { args => '--base 1000 --lower-limit 0', vlabel => 'Is a DJ Actively Connected?', category => 'shoutcast2', title => 'Active States', info => 'This graph shows us the active state or not, depending on if a DJ is connected', }, datasrc => [ { name => 'active', draw => 'AREA', min => '0', max => '1', label => 'On or Off', type => 'GAUGE' }, ], }; $graphsRef->{listeners} = { config => { args => '--base 1000 --lower-limit 0', vlabel => 'Listener Count', category => 'shoutcast2', title => 'Listeners', info => 'This graph shows us the various counts for listener states we are tracking', }, datasrc => [ { name => 'maxlisteners', draw => 'STACK', min => '0', label => 'Max Listeners', type => 'GAUGE' }, { name => 'currlisteners', draw => 'AREA', min => '0', label => 'Current Listeners', type => 'GAUGE' }, ], }; $graphsRef->{sid_active} = { config => { args => '--base 1000 --lower-limit 0', vlabel => 'Is a DJ Actively Connected?', title => 'Active State', info => 'This graph shows us the active state or not, depending on if a DJ is connected', }, datasrc => [ { name => 'active', draw => 'AREA', min => '0', max => '1', label => 'On or Off', type => 'GAUGE', xmlkey => 'STREAMSTATUS' }, ], }; $graphsRef->{sid_listeners} = { config => { args => '--base 1000 --lower-limit 0', vlabel => 'Listener Count', title => 'Listeners', info => 'This graph shows us the various counts for listener states we are tracking', }, datasrc => [ { name => 'maxlisteners', draw => 'STACK', min => '0', label => 'Max Listeners', type => 'GAUGE', xmlkey => 'MAXLISTENERS' }, { name => 'currlisteners', draw => 'AREA', min => '0', label => 'Current Listeners', type => 'GAUGE', xmlkey => 'CURRENTLISTENERS' }, { name => 'peaklisteners', draw => 'LINE2', min => '0', label => 'Peak Listeners', type => 'GAUGE', xmlkey => 'PEAKLISTENERS' }, { name => 'uniqlisteners', draw => 'LINE2', min => '0', label => 'Unique Listeners', type => 'GAUGE', xmlkey => 'UNIQUELISTENERS' }, ], }; if (defined($ARGV[0]) && ($ARGV[0] eq 'config')) { config(); exit; } if (defined($ARGV[0]) && ($ARGV[0] eq 'autoconf')) { check_autoconf(); exit; } # I guess we are collecting stats to return, execute main subroutine. main(); exit; sub main { my ($returnBit,$adminRef) = fetch_admin_data($ua,$host,$port); if ($returnBit == 0) { exit; } my $streamConfigRef = $adminRef->{STREAMCONFIGS}->{STREAMCONFIG}; my $sidDataRef; foreach my $sid (keys %{$streamConfigRef}) { my ($return,$tmpSidRef) = fetch_sid_data($sid); if ($return == 0) { next; } $sidDataRef->{$sid} = $tmpSidRef; } print_active_data($sidDataRef); print_listener_data($adminRef->{STREAMCONFIGS}->{SERVERMAXLISTENERS}, $sidDataRef); return; } sub print_active_data { my ($sidDataRef) = (@_); my $globalActive = 0; foreach my $sid (sort keys %{$sidDataRef}) { print "multigraph shoutcast2_active.active_sid_$sid\n"; foreach my $dsrc (@{$graphsRef->{sid_active}->{datasrc}}) { print "$dsrc->{name}.value $sidDataRef->{$sid}->{$dsrc->{xmlkey}}\n"; if ($sidDataRef->{$sid}->{$dsrc->{xmlkey}} == 1) { $globalActive = 1; } } } print "multigraph shoutcast2_active\n"; foreach my $dsrc (@{$graphsRef->{active}->{datasrc}}) { print "$dsrc->{name}.value $globalActive\n"; } return; } sub print_listener_data { my ($maxListeners,$sidDataRef) = (@_); my $globalListeners = 0; foreach my $sid (sort keys %{$sidDataRef}) { print "multigraph shoutcast2_listeners.listeners_sid_$sid\n"; foreach my $dsrc (@{$graphsRef->{sid_listeners}->{datasrc}}) { print "$dsrc->{name}.value $sidDataRef->{$sid}->{$dsrc->{xmlkey}}\n"; if ($dsrc->{name} eq 'currlisteners') { $globalListeners += $sidDataRef->{$sid}->{$dsrc->{xmlkey}}; } } } print "multigraph shoutcast2_active\n"; foreach my $dsrc (@{$graphsRef->{listeners}->{datasrc}}) { if ($dsrc->{name} eq 'maxlisteners') { print "$dsrc->{name}.value $maxListeners\n"; } else { print "$dsrc->{name}.value $globalListeners\n"; } } return; } sub config { my ($returnBit,$adminRef) = fetch_admin_data($ua,$host,$port); if ($returnBit == 0) { # $adminRef returned a string, we'll just print it out. print "no (error response: $adminRef)\n"; exit; } my $streamConfigRef = $adminRef->{STREAMCONFIGS}->{STREAMCONFIG}; my $sidDataRef; foreach my $sid (keys %{$streamConfigRef}) { my ($return,$tmpSidRef) = fetch_sid_data($sid); if ($return == 0) { next; } $sidDataRef->{$sid} = $tmpSidRef; } print_active_config($sidDataRef); print_listener_config($sidDataRef); return; } sub print_active_config { my ($sidDataRef) = (@_); foreach my $sid (sort keys %{$sidDataRef}) { # Print the Config Info First print "multigraph shoutcast2_active.active\_sid\_$sid\n"; print "graph_title ".$graphsRef->{sid_active}->{config}->{title}." for StreamID: $sid\n"; print "graph_args ".$graphsRef->{sid_active}->{config}->{args}."\n"; print "graph_vlabel ".$graphsRef->{sid_active}->{config}->{vlabel}."\n"; print "graph_category streamid_$sid\n"; print "graph_info ".$graphsRef->{sid_active}->{config}->{info}."\n"; # Print the Data Value Info foreach my $dsrc (@{$graphsRef->{sid_active}->{datasrc}}) { while ( my ($key, $value) = each (%{$dsrc})) { next if ($key eq 'name'); next if ($key eq 'xmlkey'); print "$dsrc->{name}.$key $value\n"; } } } print "multigraph shoutcast2_active\n"; print "graph_title ".$graphsRef->{active}->{config}->{title}."\n"; print "graph_args ".$graphsRef->{active}->{config}->{args}."\n"; print "graph_vlabel ".$graphsRef->{active}->{config}->{vlabel}."\n"; print "graph_category".$graphsRef->{active}->{config}->{category}."\n"; print "graph_info ".$graphsRef->{active}->{config}->{info}."\n"; # Print the Data Value Info foreach my $dsrc (@{$graphsRef->{active}->{datasrc}}) { while ( my ($key, $value) = each (%{$dsrc})) { next if ($key eq 'name'); print "$dsrc->{name}.$key $value\n"; } } return; } sub print_listener_config { my ($sidDataRef) = (@_); foreach my $sid (sort keys %{$sidDataRef}) { # Print the Config Info First print "multigraph shoutcast2_listeners.listeners\_sid\_$sid\n"; print "graph_title ".$graphsRef->{sid_listeners}->{config}->{title}." for StreamID: $sid\n"; print "graph_args ".$graphsRef->{sid_listeners}->{config}->{args}."\n"; print "graph_vlabel ".$graphsRef->{sid_listeners}->{config}->{vlabel}."\n"; print "graph_category streamid_$sid\n"; print "graph_info ".$graphsRef->{sid_listeners}->{config}->{info}."\n"; # Print the Data Value Info foreach my $dsrc (@{$graphsRef->{sid_listeners}->{datasrc}}) { while ( my ($key, $value) = each (%{$dsrc})) { next if ($key eq 'name'); next if ($key eq 'xmlkey'); print "$dsrc->{name}.$key $value\n"; } } } print "multigraph shoutcast2_listeners\n"; print "graph_title ".$graphsRef->{listeners}->{config}->{title}."\n"; print "graph_args ".$graphsRef->{listeners}->{config}->{args}."\n"; print "graph_vlabel ".$graphsRef->{listeners}->{config}->{vlabel}."\n"; print "graph_category".$graphsRef->{listeners}->{config}->{category}."\n"; print "graph_info ".$graphsRef->{listeners}->{config}->{info}."\n"; # Print the Data Value Info foreach my $dsrc (@{$graphsRef->{listeners}->{datasrc}}) { while ( my ($key, $value) = each (%{$dsrc})) { next if ($key eq 'name'); print "$dsrc->{name}.$key $value\n"; } } return; } sub check_autoconf { my ($returnBit,$adminRef) = fetch_admin_data($ua,$host,$port); if ($returnBit == 0) { # $adminRef returned a string, we'll just print it out. print "no (error response: $adminRef)\n"; } else { print "yes\n"; } return; } sub fetch_sid_data { my ($sid) = (@_); my $url = 'http://'.$host.':'.$port.'/stats?sid='.$sid; my $response = $ua->get($url); if ($response->is_success) { my $returnRef = XMLin($response->decoded_content); return (1, $returnRef); } else { return (0, $response->status_line); } } sub fetch_admin_data { my $url = 'http://'.$host.':'.$port.'/admin.cgi?sid=1&mode=viewxml&page=6'; my $response = $ua->get($url); if ($response->is_success) { my $returnRef = XMLin($response->decoded_content); if (($returnRef->{STREAMCONFIGS}->{TOTALCONFIGS} > 0) && (defined($returnRef->{STREAMCONFIGS}->{STREAMCONFIG}))) { return (1, $returnRef); } else { return (0, 'Unable to Detect any Stream Configurations'); } } else { return (0, $response->status_line); } }