oetiker / RrdGraphJS

An interactive graphing component for RRDtool
http://www.rrdtool.org
GNU General Public License v2.0
54 stars 7 forks source link

php-rrd example please #3

Open kaihendry opened 8 years ago

kaihendry commented 8 years ago

I noticed https://github.com/oetiker/RrdGraphJS/pull/2

I am new to rrdtool. The code in it's current state is missing an example backend to generate the graphs which is a shame. I hope you add an example soon so it's working from a clone. Thank you,

oetiker commented 8 years ago

yes, a php example would certainly be welcome :) please look at my comments for #2, the same would apply for a php example

mixu- commented 8 years ago

I second this. An example would be great!

pablos-here commented 2 years ago

Possibly too late but I should be able to provide a simple PHP example. At the moment, I have a PHP script serving a static image.

oetiker commented 2 years ago

bring it on :)

pablos-here commented 2 years ago

Hi!

There is something wonky with my development environment so I developed the code in production. :)

I added instrumentation to the code to see how long it'd take to run. To create a single graph, it's very light weight[1]. The code is only graphing barometric pressure. You can see it in action here - https://weather.hillsandlakes.com/dyna_rrd_eg.html

The server is a 1p Linode. Its CPU is rated at 4,000 bogomips. Very low end. Yet, the code is quite quick. Credit to you of course! :)

The final code will have five graphs. As an optimization, the code will return one image, with five stacked graphs. Similar to this page - https://weather.hillsandlakes.com/wxgraphs-24h.php

What I didn't want to do is create one PHP script per graph. I figured spawning five processes per redraw event might be too taxing for this little CPU. :)

References

1 - Timings

''' 0.0171s 0.0146s 0.0151s 0.0158s 0.0374s 0.0151s 0.0167s 0.0201s 0.0205s 0.0211s 0.0198s 0.0198s 0.0182s 0.0199s 0.0164s 0.0223s 0.0160s 0.0182s 0.0202s 0.0442s 0.0169s 0.0168s 0.0169s 0.0164s '''

pablos-here commented 2 years ago

dyna_rrd_eg.html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link href="rrdGraphCtrl.css" rel="stylesheet">
    <!-- the modules are implemented on top of the qxWeb library
         from www.qooxdoo.org. It provides excellent
         modularization and event normalization support out of
         the box and thus made implementation of these
         modules much simpler -->
    <script type="text/javascript" src="q-5.0.2.min.js"></script>
    <script type="text/javascript" src="moment.js"></script>
    <script type="text/javascript" src="moment-timezone-with-data.js"></script>
    <script type="text/javascript" src="rrdGraphPng.js"></script>
    <script type="text/javascript" src="rrdGraphCtrl.js"></script>
    <script type="text/javascript">
        q.ready(function(){

            // 'activate' the charts
            var graphs = [];
            q('.graph').forEach(function(item){
                graphs.push(
                    q(item).rrdGraphPng({
                        canvasPadding: 100,
                        initialStart: null,
                        autoUpdate: true
                    })
                ); 
            });

            // crate a control panel and attach it to the charts
            // Use `fr-CA' to get YYYY-MM-DD .... ahhhhh.
            q('#ctrl').rrdGraphCtrl(graphs,{
                initialTimeRange: 'Last 24 Hours',
                resetTimeOnDateChange: false,
                datePickerLocale: 'fr-CA'
            });

            // you can also remove all the magic again
            q('#rebinder').on('click',function(){
                // q('#ctrl').dispose();
                q('.graph').dispose();
                q('.graph').forEach(function(item){ 
                    graphs.push(
                        q(item).rrdGraphPng({
                        canvasPadding: 100,
                        initialStart: null,
                        autoUpdate: true
                        })
                    ); 
                });
                q('#ctrl').rebind(graphs);
            });
        });
    </script>
</head>
<body>
<!--    <button id="rebinder">Rebind</button> -->

    <div id="ctrl"></div>

<!-- temp        style="width:981px;height:290px" class="graph" -->

    <div><img
        style="width:981px;height:168px" class="graph"
        data-src-template="dyna_rrd_eg.php?uom=m&amp;width={{width}}&amp;height={{height}}&amp;start={{start}}&amp;end={{end}}&amp;zoom={{zoom}}&amp;rand={{random}}"
    /></div>

<!--
    <div><img
        style="width:695px;height:238px" class="graph"
        data-src-template="graphB?width={{width}}&amp;height={{height}}&amp;start={{start}}&amp;end={{end}}&amp;zoom={{zoom}}&amp;rand={{random}}"
    /></div>
-->

<!--
    <button id="remove">Remove it all!</button>
-->
</body>
</html>
pablos-here commented 2 years ago

dyna_rrd_eg.php

<?php

function log_start_time(&$start_time) {
  global $debug;

  if ($debug) {
    $start_time = microtime(true);
  }
}

function log_end_time($start_time, $msg) {
  global $debug;

  if ($debug) {
    $end_time = microtime(true);

    error_log($msg . ": " . number_format(($end_time - $start_time), 4) . "s");
  }
}

//
// Dump our HTML arguments to the Apache error log
//
function argument_dump() {
  global $debug;

  if ($debug) {
    ob_start();
    var_dump($_REQUEST);
    error_log(ob_get_clean());
  }
}

//
// Writes a message to the Apache error log if debug is enabled.
//
function debug_msg($msg) {
  global $debug;

  if ($debug) {
    error_log($msg);
  }
}

function cat_rm_image_stdout($image) {
  $fp = fopen($image, 'rb');

  //
  // Send the headers
  //
  header("Content-Type: image/png");
  header("Content-Length: " . filesize($image));

  //
  // Dump the picture ...
  //
  fpassthru($fp);

  //
  // and delete it.
  //
  unlink($image);
}

function graph_temperature() {
}

function graph_wind() {
}

function graph_rain() {
}

function graph_pressure($rrd, $image) {
  global $graph_errors;

  $options =
    array(
          "--start", $_REQUEST["start"],
          "--end", $_REQUEST["end"],
          "--imgformat=PNG",
          "--width=" . ($_REQUEST["width"] - 70),
          "--height=" . ($_REQUEST["height"] - 70),
          "--rigid",
          "--alt-y-grid",
          "--alt-autoscale-min",
          "--no-minor",
          "--units-exponent=0",
          "--pango-markup",
          "--tabwidth=40",
          "--color=MGRID#c1c1c1",
          "--color=ARROW#ff0000",
          "VRULE:1639803600#db7093",
          "DEF:barometer=$rrd:barometer:AVERAGE",
          );

  if ($_REQUEST["uom"] == "m") {
      array_push($options,
                 "--title=Barometric Pressure in Hectopascal (hPa)",
                 "CDEF:conv_barometer=barometer",
      );
      $precision = "0.1";
  }
  else { // imperial units
      array_push($options,
                 "--title=Barometric Pressure in Inches of Mercury",
                 "CDEF:conv_barometer=barometer,33.86388158,/",
                 "LINE1:conv_barometer#000066",
      );
      $precision = "0.2";
  }

  array_push($options,
             "VDEF:last_barometer=conv_barometer,LAST",
             "VDEF:max_barometer=conv_barometer,MAXIMUM",
             "VDEF:min_barometer=conv_barometer,MINIMUM",
             "LINE1:conv_barometer#000066",
             "GPRINT:max_barometer:Max\: %-" . $precision . "lf",
             "GPRINT:max_barometer:@ %R on %F:strftime",
             "GPRINT:min_barometer:\tMin\: %-" . $precision . "lf",
             "GPRINT:min_barometer:@ %R on %F:strftime",
             "GPRINT:last_barometer:\t  Last\: %-" . $precision . "lf\l",
  );

  $status = rrd_graph($image, $options);
  if (! $status) {
      error_log("graph_pressure(): " . rrd_error());
      $graph_errors++;
  }
}

function graph_humidity() {
}

//
// *** Configuration ***
//

//
// Set to non-zero to dump debug to the Apache error log
//
$debug = 0;

//
// Instrumentation - written to errorlog when $debug is non-zero.
//
$start_time = 0.0;

//
// RRD files relative to our script.
//
$rrd_dir = "rrd/";
$weather_pressure = $rrd_dir . "weather_pressure.rrd";

$graph_dir = "graphs/";
$pressure_graph = $graph_dir . "pressure_" . $_REQUEST["rand"] . ".png";

//
// Track graphing errors
//
$graph_errors = 0;

//
// *** Main ***
//
log_start_time($start_time);

graph_pressure($weather_pressure, $pressure_graph);

if ($graph_errors == 0) {
   cat_rm_image_stdout($pressure_graph);
}

log_end_time($start_time, "Done");

exit;
?>
pablos-here commented 2 years ago

Let me know if you prefer that I use git to submit the above ... blah, blah, blah.

Hats off to you .. the software you wrote is very whizzy! :)

oetiker commented 2 years ago

cool, could you turn this into a PR? then you would also get credited in the commitlog

pablos-here commented 2 years ago

Will do! In fact, I'll jazz it up a bit with some documentation.

I'll snarf the same copyright tombstone as your code.