Merge remote-tracking branch 'origin/pr/1346'
[collectd.git] / contrib / collection3 / lib / Collectd / Graph / Common.pm
index 6f26fd8..31c530f 100644 (file)
@@ -1,13 +1,36 @@
 package Collectd::Graph::Common;
 
+# Copyright (C) 2008-2011  Florian Forster
+# Copyright (C) 2011       noris network AG
+#
+# 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.
+#
+# Authors:
+#   Florian "octo" Forster <octo at collectd.org>
+
 use strict;
 use warnings;
 
 use vars (qw($ColorCanvas $ColorFullBlue $ColorHalfBlue));
 
+use Collectd::Unixsock ();
 use Carp (qw(confess cluck));
 use CGI (':cgi');
 use Exporter;
+use Collectd::Graph::Config (qw(gc_get_scalar));
+
+our $Cache = {};
 
 $ColorCanvas   = 'FFFFFF';
 $ColorFullBlue = '0000FF';
@@ -34,6 +57,7 @@ $ColorHalfBlue = 'B7B7F7';
   get_timespan_selection
   get_host_selection
   get_plugin_selection
+  get_random_color
   get_faded_color
   sort_idents_by_type_instance
   type_to_module_name
@@ -41,7 +65,7 @@ $ColorHalfBlue = 'B7B7F7';
   flush_files
 ));
 
-our $DataDir = '/var/lib/collectd/rrd';
+our $DefaultDataDir = '/var/lib/collectd/rrd';
 
 return (1);
 
@@ -103,7 +127,9 @@ sub group_files_by_plugin_instance
   for (my $i = 0; $i < @files; $i++)
   {
     my $file = $files[$i];
-    my $key = $file->{'plugin_instance'} || '';
+    my $key1 = $file->{'hostname'} || '';
+    my $key2 = $file->{'plugin_instance'} || '';
+    my $key = "$key1-$key2";
 
     $data->{$key} ||= [];
     push (@{$data->{$key}}, $file);
@@ -144,6 +170,7 @@ sub filename_to_ident
 sub ident_to_filename
 {
   my $ident = shift;
+  my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
 
   my $ret = '';
 
@@ -153,7 +180,7 @@ sub ident_to_filename
   }
   else
   {
-    $ret .= "$DataDir/";
+    $ret .= "$data_dir/";
   }
 
   if (!$ident->{'hostname'})
@@ -185,22 +212,48 @@ sub ident_to_filename
   return ($ret);
 } # ident_to_filename
 
+sub _part_to_string
+{
+  my $part = shift;
+
+  if (!defined ($part))
+  {
+    return ("(UNDEF)");
+  }
+  if (ref ($part) eq 'ARRAY')
+  {
+    if (1 == @$part)
+    {
+      return ($part->[0]);
+    }
+    else
+    {
+      return ('(' . join (',', @$part) . ')');
+    }
+  }
+  else
+  {
+    return ($part);
+  }
+} # _part_to_string
+
 sub ident_to_string
 {
   my $ident = shift;
 
   my $ret = '';
 
-  $ret .= $ident->{'hostname'} . '/' . $ident->{'plugin'};
+  $ret .= _part_to_string ($ident->{'hostname'})
+  . '/' . _part_to_string ($ident->{'plugin'});
   if (defined ($ident->{'plugin_instance'}))
   {
-    $ret .= '-' . $ident->{'plugin_instance'};
+    $ret .= '-' . _part_to_string ($ident->{'plugin_instance'});
   }
 
-  $ret .= '/' . $ident->{'type'};
+  $ret .= '/' . _part_to_string ($ident->{'type'});
   if (defined ($ident->{'type_instance'}))
   {
-    $ret .= '-' . $ident->{'type_instance'};
+    $ret .= '-' . _part_to_string ($ident->{'type_instance'});
   }
 
   return ($ret);
@@ -212,6 +265,7 @@ sub get_files_from_directory
   my $recursive = @_ ? shift : 0;
   my $dh;
   my @directories = ();
+  my @files = ();
   my $ret = [];
 
   opendir ($dh, $dir) or die ("opendir ($dir): $!");
@@ -227,15 +281,13 @@ sub get_files_from_directory
     }
     elsif (-f $entry)
     {
-      my $ident = filename_to_ident ($entry);
-      if ($ident)
-      {
-       push (@$ret, $ident);
-      }
+      push (@files, $entry);
     }
   }
   closedir ($dh);
 
+  push (@$ret, map { filename_to_ident ($_) } sort (@files));
+
   if ($recursive > 0)
   {
     for (@directories)
@@ -243,7 +295,7 @@ sub get_files_from_directory
       my $temp = get_files_from_directory ($_, $recursive - 1);
       if ($temp && @$temp)
       {
-       push (@$ret, @$temp);
+        push (@$ret, @$temp);
       }
     }
   }
@@ -253,25 +305,36 @@ sub get_files_from_directory
 
 sub get_all_hosts
 {
-  my $dh;
-  my @ret = ();
+  my $ret = [];
 
-  opendir ($dh, "$DataDir") or confess ("opendir ($DataDir): $!");
-  while (my $entry = readdir ($dh))
+  if (defined ($Cache->{'get_all_hosts'}))
   {
-    next if ($entry =~ m/^\./);
-    next if (!-d "$DataDir/$entry");
-    push (@ret, sanitize_hostname ($entry));
+    $ret = $Cache->{'get_all_hosts'};
+  }
+  else
+  {
+    my $dh;
+    my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
+
+    opendir ($dh, "$data_dir") or confess ("opendir ($data_dir): $!");
+    while (my $entry = readdir ($dh))
+    {
+      next if ($entry =~ m/^\./);
+      next if (!-d "$data_dir/$entry");
+      push (@$ret, sanitize_hostname ($entry));
+    }
+    closedir ($dh);
+
+    $Cache->{'get_all_hosts'} = $ret;
   }
-  closedir ($dh);
 
   if (wantarray ())
   {
-    return (@ret);
+    return (@$ret);
   }
-  elsif (@ret)
+  elsif (@$ret)
   {
-    return (\@ret);
+    return ($ret);
   }
   else
   {
@@ -284,23 +347,44 @@ sub get_all_plugins
   my @hosts = @_;
   my $ret = {};
   my $dh;
+  my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
+  my $cache_key;
 
-  if (!@hosts)
+  if (@hosts)
+  {
+    $cache_key = join (';', @hosts);
+  }
+  else
   {
+    $cache_key = "/*/";
     @hosts = get_all_hosts ();
   }
 
+  if (defined ($Cache->{'get_all_plugins'}{$cache_key}))
+  {
+    $ret = $Cache->{'get_all_plugins'}{$cache_key};
+
+    if (wantarray ())
+    {
+      return (sort (keys %$ret));
+    }
+    else
+    {
+      return ($ret);
+    }
+  }
+
   for (@hosts)
   {
     my $host = $_;
-    opendir ($dh, "$DataDir/$host") or next;
+    opendir ($dh, "$data_dir/$host") or next;
     while (my $entry = readdir ($dh))
     {
       my $plugin;
       my $plugin_instance = '';
 
       next if ($entry =~ m/^\./);
-      next if (!-d "$DataDir/$host/$entry");
+      next if (!-d "$data_dir/$host/$entry");
 
       if ($entry =~ m#^([^-]+)-(.+)$#)
       {
@@ -323,6 +407,7 @@ sub get_all_plugins
     closedir ($dh);
   } # for (@hosts)
 
+  $Cache->{'get_all_plugins'}{$cache_key} = $ret;
   if (wantarray ())
   {
     return (sort (keys %$ret));
@@ -336,7 +421,8 @@ sub get_all_plugins
 sub get_files_for_host
 {
   my $host = sanitize_hostname (shift);
-  return (get_files_from_directory ("$DataDir/$host", 2));
+  my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
+  return (get_files_from_directory ("$data_dir/$host", 2));
 } # get_files_for_host
 
 sub _filter_ident
@@ -377,23 +463,59 @@ sub _filter_ident
   return (0);
 } # _filter_ident
 
+sub _get_all_files
+{
+  my $ret;
+
+  if (defined ($Cache->{'_get_all_files'}))
+  {
+    $ret = $Cache->{'_get_all_files'};
+  }
+  else
+  {
+    my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
+
+    $ret = get_files_from_directory ($data_dir, 3);
+    $Cache->{'_get_all_files'} = $ret;
+  }
+
+  return ($ret);
+} # _get_all_files
+
 sub get_files_by_ident
 {
   my $ident = shift;
   my $all_files;
   my @ret = ();
+  my $temp;
+  my $hosts;
 
-  #if ($ident->{'hostname'})
-  #{
-  #$all_files = get_files_for_host ($ident->{'hostname'});
-  #}
-  #else
-  #{
-    $all_files = get_files_from_directory ($DataDir, 3);
-    #}
+  my $cache_key = ident_to_string ($ident);
+  if (defined ($Cache->{'get_files_by_ident'}{$cache_key}))
+  {
+    my $ret = $Cache->{'get_files_by_ident'}{$cache_key};
+
+    return ($ret)
+  }
+
+  if ($ident->{'hostname'})
+  {
+    $all_files = [];
+    $hosts = $ident->{'hostname'};
+    foreach (@$hosts)
+    {
+      $temp = get_files_for_host ($_);
+      push (@$all_files, @$temp);
+    }
+  }
+  else
+  {
+    $all_files = _get_all_files ();
+  }
 
   @ret = grep { _filter_ident ($ident, $_) == 0 } (@$all_files);
 
+  $Cache->{'get_files_by_ident'}{$cache_key} = \@ret;
   return (\@ret);
 } # get_files_by_ident
 
@@ -509,6 +631,26 @@ sub _color_to_string
   return (sprintf ('%02hx%02hx%02hx', map { int (255.0 * $_) } @{$_[0]}));
 } # _color_to_string
 
+sub get_random_color
+{
+  my ($r, $g, $b) = (rand (), rand ());
+  my $min = 0.0;
+  my $max = 1.0;
+
+  if (($r + $g) < 1.0)
+  {
+    $min = 1.0 - ($r + $g);
+  }
+  else
+  {
+    $max = 2.0 - ($r + $g);
+  }
+
+  $b = $min + (rand () * ($max - $min));
+
+  return (_color_to_string ([$r, $g, $b]));
+} # get_random_color
+
 sub get_faded_color
 {
   my $fg = shift;