Our Sys. Admin team down in Melbourne, Australia uses collectd extensively and we've recently started using collection3 for graphing.

Part of our implementation of collection3 involved a few modifications and additions to it's code which we'd like provide back to the project for inclusion as it see's fit. The updates were to version 4.10.1 of the code.

This first submission is for a graphing module which allows the stacking of multiple type instances in the one graph. The module is a modification of another one that Florian octo Forster made.

As an example if it was used to graph the interfaces "if_octets" data, depending on your system, you'd end up with "lo", "eth1", "eth2", ... stacking on top of each other. You get one graph per data source. The data source(s) used are what get specified in it's definition (in collection.conf). In the below example we get two graphs for "if_octets", one for "rx" and the other for "tx".

<Type if_octets>
 Module TypeStacked
 DataSources rx tx
 DSName rx RX
 DSName tx TX
 RRDTitle "Interface Traffic ({hostname})"
 RRDVerticalLabel "Bytes per second"
 RRDFormat "%5.1lf%s"
 Color lo 000000
 Color sit0 333333
 Scale 8
</Type>


Best regards,
Neil McCoy

diff -purN collectd-4.10.1/contrib/collection3/lib/Collectd/Graph/Type/TypeStacked.pm collectd-4.10.1-mine/contrib/collection3/lib/Collectd/Graph/Type/TypeStacked.pm
--- collectd-4.10.1/contrib/collection3/lib/Collectd/Graph/Type/TypeStacked.pm	1970-01-01 10:00:00.000000000 +1000
+++ collectd-4.10.1-mine/contrib/collection3/lib/Collectd/Graph/Type/TypeStacked.pm	2010-09-13 17:10:45.000000000 +1000
@@ -0,0 +1,231 @@
+package Collectd::Graph::Type::TypeStacked;
+
+# Copyright (C) 2008,2009  Florian octo Forster <octo at verplant.org>
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; only version 2 of the License is applicable.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+use strict;
+use warnings;
+use base ('Collectd::Graph::Type');
+
+use Carp ('confess');
+
+use Collectd::Graph::Common (qw($ColorCanvas $ColorFullBlue $ColorHalfBlue
+  group_files_by_plugin_instance ident_to_filename sanitize_type_instance
+  get_faded_color sort_idents_by_type_instance));
+
+return (1);
+
+sub getGraphsNum
+{
+  my $obj = shift;
+  my $group = group_files_by_plugin_instance (@{$obj->{'files'}});
+  my $ds = $obj->getDataSources ();
+
+  return ( scalar (keys %$group) * @$ds );
+}
+
+sub getRRDArgs
+{
+  my $obj = shift;
+  my $index = shift;
+
+  my $group = group_files_by_plugin_instance (@{$obj->{'files'}});
+  my @group = sort (keys %$group);
+
+  my $rrd_opts = $obj->{'rrd_opts'} || [];
+  my $format = $obj->{'rrd_format'} || '%5.1lf';
+
+  my $idents = $group->{$group[$index % scalar (keys %$group)]};
+  my $ds_name_len = 0;
+
+  my $ds = $obj->getDataSources ();
+  if (!$ds)
+  {
+    confess ("obj->getDataSources failed.");
+  }
+  my $data_source = $ds->[ $index % @$ds ];
+
+  my $rrd_title = $obj->getTitle ($idents->[0]);
+
+  my $colors = $obj->{'rrd_colors'} || {};
+  my @colours = ("00F000", "0000F0", "E9E900", "E900E9", "00E9E9", "AA5555", "99FFFF", "009000", "000090", "F03030");
+  
+  my @ret = ('-t', $rrd_title, @$rrd_opts);
+
+  my $ignore_unknown = $obj->{'ignore_unknown'} || 0;
+  if ($ignore_unknown)
+  {
+    if ($ignore_unknown =~ m/^(1|yes|true|on)$/i)
+    {
+      $ignore_unknown = 1;
+    }
+    else
+    {
+      $ignore_unknown = 0;
+    }
+  }
+
+  my $stacking = $obj->{'stacking'};
+  if ($stacking)
+  {
+    if ($stacking =~ m/^(0|no|false|off|none)$/i)
+    {
+      $stacking = 0;
+    }
+    else
+    {
+      $stacking = 1;
+    }
+  }
+  else # if (!$stacking)
+  {
+    $stacking = 1;
+  }
+
+  if (defined $obj->{'rrd_vertical'})
+  {
+    push (@ret, '-v', $obj->{'rrd_vertical'} . " " . $data_source);
+  }
+
+  if ($obj->{'custom_order'})
+  {
+    sort_idents_by_type_instance ($idents, $obj->{'custom_order'});
+  }
+
+  if ($ignore_unknown)
+  {
+    my $new_idents = [];
+    for (@$idents)
+    {
+      if (exists ($obj->{'ds_names'}{$_->{'type_instance'}}))
+      {
+	push (@$new_idents, $_);
+      }
+    }
+
+    if (@$new_idents)
+    {
+      $idents = $new_idents;
+    }
+  }
+
+  $obj->{'ds_names'} ||= {};
+  my @names = map { $obj->{'ds_names'}{$_->{'type_instance'}} || $_->{'type_instance'} } (@$idents);
+
+  for (my $i = 0; $i < @$idents; $i++)
+  {
+    my $ident = $idents->[$i];
+    my $filename = ident_to_filename ($ident);
+
+    if ($ds_name_len < length ($names[$i]))
+    {
+      $ds_name_len = length ($names[$i]);
+    }
+
+    # Escape colons _after_ the length has been checked.
+    $names[$i] =~ s/:/\\:/g;
+
+    push (@ret,
+      "DEF:min${i}=${filename}:${data_source}:MIN",
+      "DEF:avg${i}=${filename}:${data_source}:AVERAGE",
+      "DEF:max${i}=${filename}:${data_source}:MAX");
+  }
+
+  if ($stacking)
+  {
+    for (my $i = @$idents - 1; $i >= 0; $i--)
+    {
+      if ($i == (@$idents - 1))
+      {
+        push (@ret,
+	  "CDEF:cdef${i}=avg${i},UN,0,avg${i},IF");
+      }
+      else
+      {
+        my $j = $i + 1;
+        push (@ret,
+          "CDEF:cdef${i}=avg${i},UN,0,avg${i},IF,cdef${j},+");
+      }
+    }
+
+    for (my $i = 0; $i < @$idents; $i++)
+    {
+      my $type_instance = $idents->[$i]{'type_instance'};
+      my $color = ${colours[$i % $#colours]};
+      if (exists $colors->{$type_instance})
+      {
+        $color = $colors->{$type_instance};
+      }
+
+      $color = get_faded_color ($color);
+
+      push (@ret,
+        "AREA:cdef${i}#${color}");
+    }
+  }
+  else # if (!$stacking)
+  {
+    for (my $i = @$idents - 1; $i >= 0; $i--)
+    {
+      push (@ret,
+        "CDEF:cdef${i}=avg${i}");
+    }
+  }
+
+  for (my $i = 0; $i < @$idents; $i++)
+  {
+    my $type_instance = $idents->[$i]{'type_instance'};
+    my $ds_name = sprintf ("%-*s", $ds_name_len, $names[$i]);
+    my $color = ${colours[$i % $#colours]};
+    if (exists $colors->{$type_instance})
+    {
+      $color = $colors->{$type_instance};
+    }
+    push (@ret,
+      "LINE1:cdef${i}#${color}:${ds_name}",
+      "GPRINT:min${i}:MIN:${format} Min,",
+      "GPRINT:avg${i}:AVERAGE:${format} Avg,",
+      "GPRINT:max${i}:MAX:${format} Max,",
+      "GPRINT:avg${i}:LAST:${format} Last\\l");
+  }
+
+  return (\...@ret);
+}
+
+sub getGraphArgs
+{
+  my $obj = shift;
+  my $index = shift;
+
+  my $group = group_files_by_plugin_instance (@{$obj->{'files'}});
+  my @group = sort (keys %$group);
+
+  my $idents = $group->{$group[$index % scalar (keys %$group)]};
+
+  my @args = ();
+  push (@args, "index" . '=' . $index);
+  for (qw(hostname plugin plugin_instance type))
+  {
+    if (defined ($idents->[0]{$_}))
+    {
+      push (@args, $_ . '=' . $idents->[0]{$_});
+    }
+  }
+
+  return (join (';', @args));
+} # getGraphArgs
+
+
+# vim: set shiftwidth=2 softtabstop=2 tabstop=8 :

_______________________________________________
collectd mailing list
[email protected]
http://mailman.verplant.org/listinfo/collectd

Reply via email to