diff --git a/plugins/other/shoutcast2_multi b/plugins/other/shoutcast2_multi new file mode 100755 index 00000000..e1202ad8 --- /dev/null +++ b/plugins/other/shoutcast2_multi @@ -0,0 +1,331 @@ +#!/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); + } +} +