Edge-Origin Stats Collector (perl)

#!/usr/bin/perl
use strict;

# use module
use XML::Simple;
use Data::Dumper;
use LWP::UserAgent;
use Getopt::Std;
use RRDs;
use Scalar::Util 'reftype';

# Parse Commandline options:
# q: quiet
# r: write to RRD
# i: specify refresh interval (default 10s)

my $interval;

our($opt_r,$opt_q,$opt_i);
getopts('rqi:');

if (!$opt_i) { $interval = 10; } else { $interval = $opt_i; }

while (1) {     #establish forever loop

# Poll Origin server for list of active edge servers

my $lb_ua = new LWP::UserAgent;
my $lb_url = "http://wms.rezonline.org:1935/loadbalancer?serverInfoXML";
my $lb_req = new HTTP::Request GET => $lb_url;
my $lb_res = $lb_ua->request($lb_req);
my @lb_ip;

if($lb_res->is_success) {

my $lb_xml = new XML::Simple;
my $lb_data = $lb_xml->XMLin($lb_res->content);

# Dump raw XML (for debugging)
# print Dumper($lb_data);

# check reference type:
# if HASH, only single server is running, and XML returns without an array wrapping single element
# if ARRAY, multiple servers, each one inside an array element.

my $reference = reftype $lb_data->{LoadBalancerServer};        # Check to see how to handle this...

if ( $reference eq 'ARRAY' )
{
for my $lb_server (@{$lb_data->{LoadBalancerServer}})
{
if ($lb_server->{status} eq "RUNNING")
{
#print "ID: $lb_server->{serverId} at $lb_server->{redirect}n";
push @lb_ip, $lb_server->{redirect};
}
}
}

elsif ( $reference eq 'HASH' )
{
if ($lb_data->{LoadBalancerServer}->{status} eq "RUNNING")
{
push @lb_ip, $lb_data->{LoadBalancerServer}->{redirect};
}
}

else {
print "unknown reference type - abortingn";
}

}     # End is_success loop

my $arraysize = @lb_ip;

#print "Array size: $arraysize elements: n";

# Step through the returned array of edge IPs and gather stats

# Scope total variables
my %streamTotal = 0;

foreach (@lb_ip) {

# print "Gathering stats for edge server at $_n";
my $ua = new LWP::UserAgent;
$ua->timeout(10);

my $edgeurl = "http://$_:1935/connectioncounts.xml?flat";    # Make sure you use FLAT mode here, otherwise the XML is a pain to parse when there are multiple server applications
my $edgereq = new HTTP::Request GET => $edgeurl;
my $edgeres = $ua->request($edgereq);

# create object

my $cupertinosum = 0;     #Apple HLS
my $rtspsum = 0;    #RTSP
my $flashsum = 0;    #RTMP
my $sanjosesum = 0;    #Flash HTTP
my $smoothsum = 0;    #Silverlight Smooth Streaming

my $streamcount = 0;    #Total Streams
my %namecount = 0;    #Streams per published stream

if($edgeres->is_success) {
my $edgexml = new XML::Simple;
my $edgedata = $edgexml->XMLin($edgeres->content, ForceArray => 1);

my $loopindex = 0;
for my $stream (@{$edgedata->{Stream}})
{
# At some point we're going to want to filter out the publishing points and only look at the edge application
# in which case, check for applicationName and ignore based on that

$loopindex++;
$flashsum += $stream->{sessionsFlash};
$rtspsum += $stream->{sessionsRTSP};
$cupertinosum += $stream->{sessionsCupertino};
$sanjosesum += $stream->{sessionsSanJose};
$smoothsum += $stream->{sessionsSmooth};
$streamcount += $stream->{sessionsTotal};
$namecount{$stream->{streamName}} = $streamcount;

}    # End of FOR loop

} else {
print " X "; # Indicate that server poll was not successful
}     # End of if loop

my $rokusum = $namecount{'roku.smil'} + $namecount {'mobile.smil'};

#$start60 = $circbuf[-6];
#$start90 = $circbuf[-9];
#
#shift (@circbuf);
#
#push (@circbuf,$flashsum);
#$delta60=$flashsum-$start60;
#$delta90=$flashsum-$start90;

!$opt_q && print "$_ : $streamcount ";
!$opt_q && print "[ F: $flashsum: H $cupertinosum : R $rtspsum ]";
!$opt_q && print "[ Low: $namecount{'mobile-1'} High: $namecount{'mobile-2'} ]";
!$opt_q && print "[ iOS: $namecount{'ipad.smil'} Roku: $namecount{'roku.smil'},$namecount{'mobile.smil'} ]n";
#!$opt_q && print "[ StreamClass | High: $namecount{'playlist-high'} Low: $namecount{'playlist-low'} ]n";

$streamTotal{'Cupertino'} += $cupertinosum;
$streamTotal{'Flash'} += $flashsum;
$streamTotal{'SanJose'} += $sanjosesum;
$streamTotal{'Smooth'} += $smoothsum;
$streamTotal{'RTSP'} += $rtspsum;
$streamTotal{'Roku'} += $namecount{'roku.smil'};
$streamTotal{'iOS'} += $namecount{'ipad.smil'};
$streamTotal{'Total'} += $streamcount;

}    # End stats gathering loop per server

!$opt_q && print "Total: $streamTotal{'Total'} [F: $streamTotal{'Flash'} H: $streamTotal{'Cupertino'}(iOS: $streamTotal{'iOS'} Roku: $streamTotal{'Roku'}) SJ: $streamTotal{'SanJose'} SL: $streamTotal{'Smooth'}]";

$opt_r && RRDs::update("/var/rrd/streams-2011.rrd","N:$streamTotal{'Smooth'}:$streamTotal{'SanJose'}:$streamTotal{'Cupertino'}:$streamTotal{'RTSP'}:$streamTotal{'Flash'}:$streamTotal{'iOS'}:$streamTotal{'Roku'}");
if (!$opt_q) { $opt_r && print "[RRD] "; }

!$opt_q && print "n";

sleep($interval);
}    # End of Forever Loop