HTTP-Retrievable Bandwidth Stats (in XML)

March 30, 2004 8:48 pm

EFudd (and others) have suggested a method to poll bandwidth usage without having to log into the LPM. So, I’ve whipped up a little script you can hit via http, that outputs your bandwidth stats in XML.

[code]http://www.linode.com/members/bw/?user=[linodeUsername][/code]
The http request must come from one of the IPs of [linodeUsername]. There is no access control other than this. If that’s an issue, let me know.

Example Output:
[code]<?xml version=”1.0″ encoding=”ISO-8859-1″ ?>
<linData>
<bwdata>
<year>2004</year>
<month>3</month>
<max_avail>39728447488</max_avail>
<rx_bytes>99687847</rx_bytes>
<tx_bytes>155865515</tx_bytes>
<total_bytes>255553362</total_bytes>
</bwdata>
</linData>
[/code]
I’d appreciate it if you don’t hook this into mrtg or the like. That kind of thing is better done locally, anyway 🙂 (I may place a max request/time restriction on this if it becomes an issue.)

Enjoy!
-Chris

5 Responses

  1. Output looks like this:
    [code]
    As of Wed Jan 24 04:45:59 2007 you are currently UNDER your set limit (80%).
    Input Bytes Xfer: 0.84 GiBs Host: host29.linode.com
    Output Bytes Xfer: 2.62 GiBs Load: IDLE
    ————————
    Total Bytes Xfer: 3.46 GiBs of 200.00 available.
    [/code]

    Recommended Installation Method:

    Add this to your $HOME/.bash_profile

    [code][ -f $HOME/bin/bw.pl ] && $HOME/bin/bw.pl[/code]

    Code:

    [code]
    #!/usr/bin/perl
    # $Id: bw.pl,v 1.11 2007/01/24 04:40:51 jason Exp $
    ########################################################################
    # bw.pl – Linode Bandwidth Utilization^W^H^Winfo Monitor via shell
    #
    # Revision History:
    # 1.7 – First Public Release
    # 1.8 – some lame fixes, such as 0byte $myLastState
    # 1.11 – updated URL to /info/, added host level info
    #
    # To setup, modify $username to match your LPM login (Web Login)
    #
    # NOTES: Please do not modify $userAgent or $maxTime as this is used
    # on linode server to monitor usage.
    #
    # If you desire to graph your bandwidth usage, use your your
    # local interface stats.
    ########################################################################

    # Installation Tips:
    # gentoo: emerge XML-LibXML ….
    # debian: install gentoo OR apt-get install libxml-libxml-perl
    # redhat: install windows
    # slackware: rock on!

    use XML::LibXML;
    use LWP::UserAgent;
    use IO::File;
    use strict;

    # Config
    my $username = "someuser";
    my $warning_pct = 80;
    my $userAgent = "BandWidth Snarf v1.11/" . $username;
    my $myLastState = $ENV{HOME} . "/.bw_state";
    my $maxTime = 43200;
    my $xmlState;

    my $kilobyte = 1024;
    my $megabyte = $kilobyte * 1024;
    my $gigabyte = $megabyte * 1024;

    if ((time()-(stat($myLastState))[9] > $maxTime) || ((our ($f)=(stat($myLastState))[6]) && $f==0) ) {
    # Use LWP to GET the data without any error checking.
    my $ua = LWP::UserAgent->new(keep_alive => 0, timeout => 10, agent => $userAgent);
    my $req = "http://www.linode.com/members/info/?user=" . $username;
    my $res = $ua->get($req) || die "uh oh: $!\n";

    my $fh = new IO::File($myLastState, ‘w’) || die "Ack $!";
    print $fh $res->content;
    $fh->close;
    $xmlState = $res->content;
    } else {
    my $fh = new IO::File($myLastState, ‘r’) || die "Ack $!";
    local $/;
    $xmlState = <$fh>;
    $fh->close;
    }

    # Instantiate a new parser object then utilize the crap out of it
    my $parser = new XML::LibXML;
    my $doc = $parser->parse_string($xmlState);

    # Leeto like a burrito parse da shanizzle out!
    my $year = $doc->findvalue(’/linData/bwdata/year/text()’);
    my $month = $doc->findvalue(’/linData/bwdata/month/text()’);
    my $max_bytes = $doc->findvalue(’/linData/bwdata/max_avail/text()’);
    my $rx_bytes = $doc->findvalue(’/linData/bwdata/rx_bytes/text()’);
    my $tx_bytes = $doc->findvalue(’/linData/bwdata/tx_bytes/text()’);
    my $total_bytes = $doc->findvalue(’/linData/bwdata/total_bytes/text()’);
    # new, v1.11 +
    my $parentHost = $doc->findvalue(’/linData/host/host/text()’);
    my $hostLoad = $doc->findvalue(’/linData/host/hostLoad/text()’);
    my $pendingJobs = $doc->findvalue(’/linData/host/pendingJobs/text()’);

    # Create some potentially useful variables based on the datum above
    my $timestamp = $month . "/" . $year;

    if ( ( $rx_bytes + $tx_bytes ) != $total_bytes ) {
    print "Hmmm. My tx+rx count != caker’s total_bytes count!\n";
    print "Additionally, you shouldn’t ever see this message.";
    }

    printf("As of %s you are currently %s your set limit (%d%%).\n",
    scalar(gmtime((stat($myLastState))[9])),
    ((($total_bytes / $max_bytes) * 100) > $warning_pct) ? "OVER" : "UNDER",
    $warning_pct);
    printf("\tInput Bytes Xfer: %02.2f GiBs\tHost: %s\n", $rx_bytes / $gigabyte, $parentHost);
    printf("\tOutput Bytes Xfer: %02.2f GiBs\tLoad: %s\n", $tx_bytes / $gigabyte,uc($hostLoad));
    printf("\t————————\n");
    printf("\tTotal Bytes Xfer: %02.2f GiBs of %02.2f available.\n",
    $total_bytes / $gigabyte, $max_bytes / $gigabyte);

    [/code]

    You can download this from

    [code]http://forever.broked.net/~jason/bw.pl.txt[/code]

    Please report any bugs to bw@broked.net or find me on IRC.

    You will need to edit a couple of things in the script as defined inside it for this to work. You will also need the perl modules used… i’ve listed installation instructions for these modules for each distribution as best I can inside the script.

    LASTLY – Please *LEAVE* it at 7200 seconds and do not modify the $useragent variable.

    [b]Not modifying them makes you a very good community member and mikegrb will give you cookies.[/b]

    -NOTE-
    There are a couple of minor bugs in this that only show up with -w and strict on first run due to uninitialized variables. It is a one-time error.

    ALSO – If you fail to properly set your $username, you will have to manually remove $HOME/.bw_state and try again.

    Lastly – the time displayed is in UTC instead of localtime.

    [b]-EDIT-[/b]
    Thu Feb 17 18:42:28 EST 2005 – jasonl
    Found a bug in ‘Output’. Really. I apparently typo’d ‘Otput’.

    Fri Jun 17 22:52:45 EDT 2005 -jasonl
    Fixed long standing issue with a 0 byte state file.

    Tue Jan 23 23:47:04 EST 2007 -jasonl
    Updated for /info vs. /bw URL, fixed bug in useragent, added hostload information

    -efudd

  2. I changed efudd’s script to also dispay a percentage at the bottom. It is green if less than 50%, yellow if less than 90%, and red is it’s >=90%.

    Output looks like:
    [code]As of Wed Apr 7 21:46:02 2004 you are currently UNDER your set limit (80%).
    Input Bytes Xfer: 0.16 GiBs
    Otput Bytes Xfer: 0.89 GiBs
    ————————
    Total Bytes Xfer: 1.04 GiBs of 25.00 available.
    Percent Usage: 4.18 %
    [/code]

    Download from
    [code]http://parazoid.net/bw.pl
    [/code]

  3. Here’s a fairly non-fancy bash version. Minimal dependencies (bash, grep, and sed) though. Could easily be expanded to be fancier. Have fun.

    [code]
    #!/bin/bash

    # fetch linode bandwidth stats from the xml interface

    USERNAME="iggy"

    wget -q -O – http://www.linode.com/members/bw/?user=${USERNAME} |
    while read -s line ; do
    if `echo $line | grep -q max_avail` ; then
    maxavail="`echo $line | grep -o \>.*\< | sed -e ‘s:^.::’ -e ‘s:.$::’`"
    maxavailmb="$((maxavail/1048576))"
    echo "Available bandwidth: $maxavail (${maxavailmb}M)"
    fi
    if `echo $line | grep -q rx_bytes` ; then
    rxbytes="`echo $line | grep -o \>.*\< | sed -e ‘s:^.::’ -e ‘s:.$::’`"
    rxbytesmb="`expr ${rxbytes} / 1048576`"
    echo "Received: $rxbytes (${rxbytesmb}M)"
    fi
    if `echo $line | grep -q tx_bytes` ; then
    txbytes="`echo $line | grep -o \>.*\< | sed -e ‘s:^.::’ -e ‘s:.$::’`"
    txbytesmb="`expr ${txbytes} / 1048576`"
    echo "Transmitted: $txbytes (${txbytesmb}M)"
    fi
    if `echo $line | grep -q total_bytes ` ; then
    totalbytes="`echo $line | grep -o \>.*\< | sed -e ‘s:^.::’ -e ‘s:.$::’`"
    totalbytesmb="`expr ${totalbytes} / 1048576`"
    echo "Total Used: $totalbytes (${totalbytesmb}M)"
    fi
    if [ -n "$maxavail" -a -n "$totalbytes" ] ; then
    remainbw="$(($maxavail-$totalbytes))"
    remainbwmb=`expr ${maxavailmb} – ${totalbytesmb}`
    echo "Remaining Bandwidth for the month: $remainbw (${remainbwmb}M)"
    break
    fi
    done
    [/code]

  4. [quote:26d24b6abe=”iggy”]Here’s a fairly non-fancy bash version. Minimal dependencies (bash, grep, and sed) though. [/quote]

    In this thread ( http://www.linode.com/forums/viewtopic.php?t=983 ) I wrote a simple bash script to do similar. You might be interested in the ${ } variable expansion abilities of bash to avoid the use of sed and grep.

Leave a Reply