Listener stats
From RFB Wiki
Collecting listener stats from Icecast (our public-facing streaming software) isn't easy.
All we have to go on is the number reported in the web area: http://radiofreebrighton.org.uk:8000/
This number however, is an instantaneous snapshot. To build up a useful picture over time, we must regularly poll it and store it's response. To do that, we use RRDtool - a Round-Robin Database. RRDs are great because they are a fixed size. When they get full, they start overwriting old data. In other words, the point at which data is written moves Round like the hand of a clock, which is perfect when you care about a fixed period of time.
In our case, we use the following RRDs:
- 1 hour, with a resolution of 5 minutes.
- 1 day, with a resolution of an hour.
- 6.2 days, with a resolution of 4.8 hours (don't ask).
Scripts
In order to link the RRDs to Icecast, we use the following script:
listeners=$(curl -G -s -u admin:PASSWORD http://radiofreebrighton.org.uk:8000/admin/stats.xml | xmlstarlet sel -t -m "/icestats/listeners" -v ".") rrdtool update /home/tom/rrd/radio.rrd N:$listeners logger -p user.info -t STATS Listeners: $listeners
Naturally, this requires RRDtool to be installed and for there to be a database file located at /home/tom/rrd/radio.rrd. It also relies on CURL for the http request and XMLstarlet for the XML parsing. This script is then triggered every minute using Cron.
Drawing graphs is accomplished by a second script. This script is long because of it's flexibility.
#!/bin/bash # Standard error handling stuff (http://stackoverflow.com/questions/64786/error-handling-in-bash) set -e # Don't persevere after an error PROGNAME=$(basename $0) # save the program name function error_exit { # Error handling function if [[ $4 == "debug" ]]; then echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 fi exit 1 } # Draws a graph based on the listeners count # Expects the size of the interval as arg1 and the number of intervals as arg2 # Can take a third option "max", which adds a line for max listeners. # Check the number of variables if [[ $# < 2 ]]; then error_exit "Too few arguments. Please supply an interval and a multiple." else RRDFILE=/usr/share/rfb-scripts/radio.rrd # Sets the location of the RRD OUTFILE=/home/tom/www/reports/listeners_$1x$2.png # And the output file endtime=$(rrdtool last $RRDFILE) # Get the time of the last update # Start needs to be end minus an integer multiple of the interval if starttime=$(($endtime-($1*$2))); then if [[ $3 == "max" ]]; then rrdtool graph $OUTFILE \ --start $starttime --end $endtime \ DEF:max_listeners=$RRDFILE:listeners:MAX \ AREA:max_listeners#66FF66 \ LINE1:max_listeners#00FF00:'Maximum listeners' \ TEXTALIGN:left \ > /dev/null elif [[ $3 == "avg" ]]; then rrdtool graph $OUTFILE \ --start $starttime --end $endtime \ DEF:avg_listeners=$RRDFILE:listeners:AVERAGE \ AREA:avg_listeners#FF6666 \ LINE2:avg_listeners#FF0000:'Average listeners' \ > /dev/null else rrdtool graph $OUTFILE \ --start $starttime --end $endtime \ DEF:avg_listeners=$RRDFILE:listeners:AVERAGE \ AREA:avg_listeners#FF6666 \ LINE1:avg_listeners#FF0000:'Average listeners' \ DEF:max_listeners=$RRDFILE:listeners:MAX \ LINE2:max_listeners#00FF00:'Maximum listeners' \ TEXTALIGN:left \ > /dev/null fi if [[ $4 == "debug" ]]; then if [[ $? == 0 ]]; then echo "Success!" else echo "Failure." fi fi else error_exit "One or both of the required arguments are invalid. They must be numeric." fi fi
Again, this requires that RRDtool be installed and that radio.rrd exists at the specified location, but it does not require any further libraries. The first argument is expected to be the interval size and the second is expected to be the multiple of intervals. The third argument is optional and allows for just a "max" or an "average" graph to be drawn (default is both).
In our set up, these are displayed on a PHP page, which checks the age of the file and determines whether it is necessary to generate a new one. The PHP is as follows:
function get_graph($interval, $multiples) { $graph_dir_int = '/home/tom/www/reports/'; $graph_dir_ex = '/reports/'; $graph_file = sprintf('listeners_%dx%d.png', $interval, $multiples); if (!(file_exists($graph_dir_int . $graph_file) && time() - $interval < filemtime($graph_dir_int . $graph_file))) { shell_exec("/usr/share/rfb-scripts/rrdtool-drawgraph.sh $interval $multiples - debug 2>&1;"); } return ($graph_dir_ex . $graph_file); }
Placing a call to this function in the "src" attribute of an image tag will ensure that the image is updated automatically.