PHP RRDTool tutorial

On a number of occasions I've used RRDTool to graph network traffic and the like. A few years ago when I started using cacti I started wondering how to make the graphs myself. Creating the graphs on the command line isn't that hard once you know how to set things up and it turns out doing the same in PHP is just as easy.

For this tutorial I'm going to assume you understand how to get RRDTool installed and working from the command line. If not you should take a look at this tutorial (if you are in a hurry look at the "A Real World Example" section) or any of the tutorials on this page.

Setup and introduction

You need to have PHP compiled with RRDTool support to run the following PHP examples. If you compile PHP by hand then see: how to build the php rrdtool extension by hand. If you are using a distribution's pre-compiled PHP binary you should be able to install a second package with RRDTool support. You can verify that your PHP install is ready to go by running this:

<?php
phpinfo(INFO_MODULES);
?>

Then search for "rrdtool" in the output and make sure that "rrdtool support" is enabled.

While going through each of the following steps you will notice that each call takes a couple of parameters and then one parameter that is just a string of options. The string of options is exactly how it is for generating/updating/graphing RRDs from the command line. This makes for a consistent interface for the different languages that have RRDTool support.

Creating a RRD

We first need to create a database for our data. For these examples I will be creating a database that could be used for generating network graphs. This database is created for updates every 5 minutes (300 seconds), has input and output counters that store data for the average and max counts and stores enough samples for hourly, daily, monthly and yearly graphs of both average and max.

<?php

  $fname = "net.rrd";

  $opts = array( "--step", "300", "--start", 0,
           "DS:input:COUNTER:600:U:U",
           "DS:output:COUNTER:600:U:U",
           "RRA:AVERAGE:0.5:1:600",
           "RRA:AVERAGE:0.5:6:700",
           "RRA:AVERAGE:0.5:24:775",
           "RRA:AVERAGE:0.5:288:797",
           "RRA:MAX:0.5:1:600",
           "RRA:MAX:0.5:6:700",
           "RRA:MAX:0.5:24:775",
           "RRA:MAX:0.5:288:797"
        );

  $ret = rrd_create($fname, $opts, count($opts));

  if( $ret == 0 )
  {
    $err = rrd_error();
    echo "Create error: $err\n";
  }
?>

After running you will have a file called net.rrd in the current directory. This is your RRD and will contain all the samples for your graphs.

For more information on the options to rrd_create see: rrdcreate

Updating a RRD

The next step is to update your RRD on the frequency you set when you created it. In the case above the frequency was set to 5 minutes (300 seconds). The following script generates random input and output values as input to the update function, sleeps for 300 seconds and then loops.

<?php

  $fname = "net.rrd";

  $total_input_traffic = 0;
  $total_output_traffic = 0;

  while(true)
  {
    $total_input_traffic += rand(10000, 15000);
    $total_output_traffic += rand(10000, 30000);

    echo time() . ": " . $total_input_traffic . " and " . $total_output_traffic . "\n";

    $ret = rrd_update($fname, "N:$total_input_traffic:$total_output_traffic");

    if( $ret == 0 )
    {
      $err = rrd_error();
      echo "ERROR occurred: $err\n";
    }

    sleep(300);
  }
?>

Your input and output values could be pulled from anywhere here, I just wanted to have a source that would work for anyone who wanted to try the script.

After letting this script run for a few hours you can run the following shell script to see what type of data you have collected so far:

For more information on the options to rrd_update here: rrdupdate

#!/bin/sh
END=`date +%s`
START=`echo $END-3600|bc` # over the hour
rrdtool fetch net.rrd AVERAGE --start $START --end $END

That should display the average sample values for the last hour.

Displaying RRD data as a graph

Now that you have data in your RRD you will want to graph it. The following code will graph the average input and output for 1 day as well as the max for that day.

<?php

  $opts = array( "--start", "-1d", "--vertical-label=B/s",
                 "DEF:inoctets=net.rrd:input:AVERAGE",
                 "DEF:outoctets=net.rrd:output:AVERAGE",
                 "AREA:inoctets#00FF00:In traffic",
                 "LINE1:outoctets#0000FF:Out traffic\\r",
                 "CDEF:inbits=inoctets,8,*",
                 "CDEF:outbits=outoctets,8,*",
                 "COMMENT:\\n",
                 "GPRINT:inbits:AVERAGE:Avg In traffic\: %6.2lf %Sbps",
                 "COMMENT:  ",
                 "GPRINT:inbits:MAX:Max In traffic\: %6.2lf %Sbps\\r",
                 "GPRINT:outbits:AVERAGE:Avg Out traffic\: %6.2lf %Sbps",
                 "COMMENT: ",
                 "GPRINT:outbits:MAX:Max Out traffic\: %6.2lf %Sbps\\r"
               );

  $ret = rrd_graph("net_1d.gif", $opts, count($opts));

  if( !is_array($ret) )
  {
    $err = rrd_error();
    echo "rrd_graph() ERROR: $err\n";
  }
?>

You should end up with a file named net_1d.gif in your working directory that looks something like:

You can also do weekly and monthly graphs by changing the start parameter to -1w or -1m:

For the impatient you can download my net.rrd file and try the graphs for yourself.

See the other tutorials for more information on the options you have for graphing.

For more information on the options to rrd_graph see: rrdgraph

Tags: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *