The Developer’s Cry

Yet another blog by a hobbyist programmer

Graphing DSL network connectivity with Google Charts API

I’m suffering from poor DSL internet stability (first world problems), meaning a couple of outages per day. The breaks are short, but any established connections will drop and it’s pretty annoying when that happens while in the middle of something. Since I’m not sure if it’s getting worse, I decided to start monitoring connectivity. First I had a look at some existing tools to do network monitoring. They are mostly focused on throughput, and it’s not what I’m interested in, so why not script something together and let the raspberry pi handle it.

For testing connectivity we can use the venerable ping command. Sending out one ping message every 10 seconds is good enough for me.

$ ping -i 10 8.8.4.4
PING 8.8.4.4 (8.8.4.4): 56 data bytes
64 bytes from 8.8.4.4: icmp_seq=0 ttl=49 time=11.398 ms
^C

The IP address shown here is only an example. In reality I use an address at the ISP.
Parse the output to determine whether the line was up or down. Store the result in a time-series database and we’re almost done. What I don’t want however, is having to run a heavy software stack on the raspi.
Note that since the link state only changes up/down and down/up, I only store state changes and not each and every measurement. This saves space and doing lots of IOs for no reason. Rather than using a database, I simply write to a log:

2016-04-03 00:00:00 up
2016-04-03 02:23:57 down
2016-04-03 02:25:27 up
2016-04-03 11:33:29 down
2016-04-03 11:35:09 up

Parsing ping output isn’t very hard. Now to graph the collected data in a chart. For this I chose to use Google Charts. It’s a JavaScript library for graphing data. It can draw many kinds of charts, but for our connectivity data the timeline chart is ideal.

Google’s examples show HTML snippets with hard-coded JavaScript code with hard-coded data table rows, which is fine as an example, but let’s make it a little more dynamic. We can have the automatic pinger write out a JSON data file and load it into the google chart. The expected JSON is made up of a definition of columns (what fields are there, and what are their types) and a number of data rows. The rows have “c” and “v” fields to define values. The timeline chart expects a start and end time for every bar. There is a fishy thing about this that needs mentioning; google charts JSON uses a date format that is different from JavaScript’s Date.toJSON() method. The upside is that it looks more intuitive as a JavaScript Date object, but the downside is that you can’t mix it easily with real JavaScript Date objects because it isn’t one. Confusing? Yup.
You can set the date to zeroes and only pass the timestamp, as shown:

{
"cols": [{"type": "string", "id": "date"},
         {"type": "string", "id": "state"},
         {"type": "date", "id": "start"},
         {"type": "date", "id": "end"}],
"rows": [{"c":[{"v": "2016-04-03 up"},{"v": "up"},
               {"v": "Date(0, 0, 0, 0, 0, 0)"},
               {"v": "Date(0, 0, 0, 2, 23, 57)"}]},
         {"c":[{"v": "2016-04-03 down"},{"v": "down"},
               {"v": "Date(0, 0, 0, 2, 23, 57)"},
               {"v": "Date(0, 0, 0, 2, 25, 27)"}]},
...

OK, now that we’ve gotten the right JSON format (mind ye, JSON does not permit a trailing comma after the last row), let’s load it up into the page. It uses jQuery, so remember to include a <script> tag for jquery.min.js in the top of the HTML page.

google.charts.load('current', {'packages':['timeline'], callback: drawChart});

function drawChart() {
    var jsonData = $.ajax({
        url: 'pinger.json',
        dataType: 'json',
        async: false
    }).responseText;

    var data = new google.visualization.DataTable(jsonData);
    var chart = new google.visualization.Timeline(document.getElementById('chart_div'));
    chart.draw(data);
}

Note that this code is outside $(document).ready().
I added some options to change the colors and some small code to add the current time as a final data row—otherwise the timeline would end at the last state change, rather than at what is ‘now’. Anyway, the result looks pretty nice. You can also plot ‘up’ and ‘down’ in the same bar, but I decided to have the ‘link down’ moments stand out more:

As happy as I am with how this project turned out, the bad connectivity is a bit of a downer. I tried fiddling with modem settings, but the situation only got much worse. I live far away from the telco equipment and there is no option for cable or fiber here, so that’s just the way it is for now.