summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 6194ec7)
raw | patch | inline | side by side (parent: 6194ec7)
author | Florian Forster <octo@noris.net> | |
Tue, 8 Feb 2011 10:14:19 +0000 (11:14 +0100) | ||
committer | Florian Forster <octo@noris.net> | |
Tue, 8 Feb 2011 10:14:19 +0000 (11:14 +0100) |
Some data is cached between requests, which may increase
performance, especially if different timespans of the same
graph are requested.
performance, especially if different timespans of the same
graph are requested.
contrib/collection3/bin/graph.cgi | patch | blob | history | |
contrib/collection3/bin/index.cgi | patch | blob | history | |
contrib/collection3/lib/Collectd/Graph/Common.pm | patch | blob | history |
index 8a5bf85a17de71a3b978f55bab662d3cccc2197a..40408fd5551e703cb81fd2bfb13bbe50cc474065 100755 (executable)
#!/usr/bin/perl
+# 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 lib ('../lib');
use utf8;
+use vars (qw($BASE_DIR));
+
+BEGIN
+{
+ if (defined $ENV{'SCRIPT_FILENAME'})
+ {
+ if ($ENV{'SCRIPT_FILENAME'} =~ m{^(/.+)/bin/[^/]+$})
+ {
+ $BASE_DIR = $1;
+ unshift (@INC, "$BASE_DIR/lib");
+ }
+ }
+}
-use FindBin ('$RealBin');
use Carp (qw(confess cluck));
use CGI (':cgi');
use RRDs ();
+use File::Temp (':POSIX');
use Collectd::Graph::Config (qw(gc_read_config gc_get_scalar));
use Collectd::Graph::TypeLoader (qw(tl_load_type));
epoch_to_rfc1123 flush_files));
use Collectd::Graph::Type ();
-our $Debug = param ('debug');
-our $Begin = param ('begin');
-our $End = param ('end');
-our $GraphWidth = param ('width');
-our $GraphHeight = param ('height');
-our $Index = param ('index') || 0;
-our $OutputFormat = 'PNG';
-our $ContentType = 'image/png';
+$::MODPERL = 1;
-if (param ('format'))
+my $have_init = 0;
+sub init
{
- my $temp = param ('format') || '';
- $temp = uc ($temp);
-
- if ($temp =~ m/^(PNG|SVG|EPS|PDF)$/)
+ if ($have_init)
{
- $OutputFormat = $temp;
-
- if ($OutputFormat eq 'SVG') { $ContentType = 'image/svg+xml'; }
- elsif ($OutputFormat eq 'EPS') { $ContentType = 'image/eps'; }
- elsif ($OutputFormat eq 'PDF') { $ContentType = 'application/pdf'; }
+ return;
}
-}
-if ($Debug)
-{
- print <<HTTP;
-Content-Type: text/plain
+ #gc_read_config ("$RealBin/../etc/collection.conf");
+ gc_read_config ("$BASE_DIR/etc/collection.conf");
-HTTP
+ $have_init = 1;
}
-gc_read_config ("$RealBin/../etc/collection.conf");
-
-if ($GraphWidth)
+sub main
{
- $GraphWidth =~ s/\D//g;
-}
+ my $Begin = param ('begin');
+ my $End = param ('end');
+ my $GraphWidth = param ('width');
+ my $GraphHeight = param ('height');
+ my $Index = param ('index') || 0;
+ my $OutputFormat = 'PNG';
+ my $ContentType = 'image/png';
+
+ if (param ('format'))
+ {
+ my $temp = param ('format') || '';
+ $temp = uc ($temp);
-if (!$GraphWidth)
-{
- $GraphWidth = gc_get_scalar ('GraphWidth', 400);
-}
+ if ($temp =~ m/^(PNG|SVG|EPS|PDF)$/)
+ {
+ $OutputFormat = $temp;
-if ($GraphHeight)
-{
- $GraphHeight =~ s/\D//g;
-}
+ if ($OutputFormat eq 'SVG') { $ContentType = 'image/svg+xml'; }
+ elsif ($OutputFormat eq 'EPS') { $ContentType = 'image/eps'; }
+ elsif ($OutputFormat eq 'PDF') { $ContentType = 'application/pdf'; }
+ }
+ }
-if (!$GraphHeight)
-{
- $GraphHeight = gc_get_scalar ('GraphHeight', 100);
-}
+ if (param ('debug'))
+ {
+ print <<HTTP;
+Content-Type: text/plain
-{ # Sanitize begin and end times
- $End ||= 0;
- $Begin ||= 0;
+HTTP
+ $ContentType = 'text/plain';
+ }
- if ($End =~ m/\D/)
+ init ();
+
+ if ($GraphWidth)
{
- $End = 0;
+ $GraphWidth =~ s/\D//g;
}
- if (!$Begin || !($Begin =~ m/^-?([1-9][0-9]*)$/))
+ if (!$GraphWidth)
{
- $Begin = -86400;
+ $GraphWidth = gc_get_scalar ('GraphWidth', 400);
}
- if ($Begin < 0)
+ if ($GraphHeight)
{
- if ($End)
+ $GraphHeight =~ s/\D//g;
+ }
+
+ if (!$GraphHeight)
+ {
+ $GraphHeight = gc_get_scalar ('GraphHeight', 100);
+ }
+
+ { # Sanitize begin and end times
+ $End ||= 0;
+ $Begin ||= 0;
+
+ if ($End =~ m/\D/)
{
- $Begin = $End + $Begin;
+ $End = 0;
}
- else
+
+ if (!$Begin || !($Begin =~ m/^-?([1-9][0-9]*)$/))
{
- $Begin = time () + $Begin;
+ $Begin = -86400;
}
- }
- if ($Begin < 0)
- {
- $Begin = time () - 86400;
- }
+ if ($Begin < 0)
+ {
+ if ($End)
+ {
+ $Begin = $End + $Begin;
+ }
+ else
+ {
+ $Begin = time () + $Begin;
+ }
+ }
- if (($End > 0) && ($Begin > $End))
- {
- my $temp = $End;
- $End = $Begin;
- $Begin = $temp;
+ if ($Begin < 0)
+ {
+ $Begin = time () - 86400;
+ }
+
+ if (($End > 0) && ($Begin > $End))
+ {
+ my $temp = $End;
+ $End = $Begin;
+ $Begin = $temp;
+ }
}
-}
-my $type = param ('type') or die;
-my $obj;
+ my $type = param ('type') or die;
+ my $obj;
-$obj = tl_load_type ($type);
-if (!$obj)
-{
- confess ("tl_load_type ($type) failed");
-}
+ $obj = tl_load_type ($type);
+ if (!$obj)
+ {
+ confess ("tl_load_type ($type) failed");
+ }
-$type = ucfirst (lc ($type));
-$type =~ s/_([A-Za-z])/\U$1\E/g;
-$type = sanitize_type ($type);
+ $type = ucfirst (lc ($type));
+ $type =~ s/_([A-Za-z])/\U$1\E/g;
+ $type = sanitize_type ($type);
-my $files = get_selected_files ();
-if ($Debug)
-{
- require Data::Dumper;
- print STDOUT Data::Dumper->Dump ([$files], ['files']);
-}
-for (@$files)
-{
- $obj->addFiles ($_);
-}
+ my $files = get_selected_files ();
+ if (param ('debug'))
+ {
+ require Data::Dumper;
+ print Data::Dumper->Dump ([$files], ['files']);
+ }
+ for (@$files)
+ {
+ $obj->addFiles ($_);
+ }
-my $expires = time ();
+ my $expires = time ();
# IF (End is `now')
# OR (Begin is before `now' AND End is after `now')
-if (($End == 0) || (($Begin <= $expires) && ($End >= $expires)))
-{
- # 400 == width in pixels
- my $timespan;
-
- if ($End == 0)
+ if (($End == 0) || (($Begin <= $expires) && ($End >= $expires)))
{
- $timespan = $expires - $Begin;
- }
- else
- {
- $timespan = $End - $Begin;
+ # 400 == width in pixels
+ my $timespan;
+
+ if ($End == 0)
+ {
+ $timespan = $expires - $Begin;
+ }
+ else
+ {
+ $timespan = $End - $Begin;
+ }
+ $expires += int ($timespan / 400.0);
}
- $expires += int ($timespan / 400.0);
-}
# IF (End is not `now')
# AND (End is before `now')
# ==> Graph will never change again!
-elsif (($End > 0) && ($End < $expires))
-{
- $expires += (366 * 86400);
-}
-elsif ($Begin > $expires)
-{
- $expires = $Begin;
-}
+ elsif (($End > 0) && ($End < $expires))
+ {
+ $expires += (366 * 86400);
+ }
+ elsif ($Begin > $expires)
+ {
+ $expires = $Begin;
+ }
# Send FLUSH command to the daemon if necessary and possible.
-flush_files ($files,
+ flush_files ($files,
begin => $Begin,
end => $End,
addr => gc_get_scalar ('UnixSockAddr', undef),
interval => gc_get_scalar ('Interval', 10));
-print STDOUT header (-Content_type => $ContentType,
- -Last_Modified => epoch_to_rfc1123 ($obj->getLastModified ()),
- -Expires => epoch_to_rfc1123 ($expires));
+ print header (-Content_type => $ContentType,
+ -Last_Modified => epoch_to_rfc1123 ($obj->getLastModified ()),
+ -Expires => epoch_to_rfc1123 ($expires));
-if ($Debug)
-{
- print "\$expires = $expires;\n";
-}
-
-my $args = $obj->getRRDArgs (0 + $Index);
-
-if ($Debug)
-{
- require Data::Dumper;
- print STDOUT Data::Dumper->Dump ([$obj], ['obj']);
- print STDOUT join (",\n", @$args) . "\n";
- print STDOUT "Last-Modified: " . epoch_to_rfc1123 ($obj->getLastModified ()) . "\n";
-}
-else
-{
- my @timesel = ();
+ if (param ('debug'))
+ {
+ print "\$expires = $expires;\n";
+ }
- if ($End) # $Begin is always true
+ my $args = $obj->getRRDArgs (0 + $Index);
+ if (param ('debug'))
{
- @timesel = ('-s', $Begin, '-e', $End);
+ require Data::Dumper;
+ print Data::Dumper->Dump ([$obj], ['obj']);
+ print join (",\n", @$args) . "\n";
+ print "Last-Modified: " . epoch_to_rfc1123 ($obj->getLastModified ()) . "\n";
}
else
{
- @timesel = ('-s', $Begin); # End is implicitely `now'.
- }
+ my @timesel = ();
+ my $tmpfile = tmpnam ();
+ my $status;
- $| = 1;
- RRDs::graph ('-', '-a', $OutputFormat, '--width', $GraphWidth, '--height', $GraphHeight, @timesel, @$args);
- if (my $err = RRDs::error ())
- {
- print STDERR "RRDs::graph failed: $err\n";
- exit (1);
+ if ($End) # $Begin is always true
+ {
+ @timesel = ('-s', $Begin, '-e', $End);
+ }
+ else
+ {
+ @timesel = ('-s', $Begin); # End is implicitely `now'.
+ }
+
+ if (-S "/var/run/rrdcached.sock" && -w "/var/run/rrdcached.sock")
+ {
+ $ENV{"RRDCACHED_ADDRESS"} = "/var/run/rrdcached.sock";
+ }
+ unlink ($tmpfile);
+ RRDs::graph ($tmpfile, '-a', $OutputFormat, '--width', $GraphWidth, '--height', $GraphHeight, @timesel, @$args);
+ if (my $err = RRDs::error ())
+ {
+ print STDERR "RRDs::graph failed: $err\n";
+ exit (1);
+ }
+
+ $status = open (IMG, '<', $tmpfile) or die ("open ($tmpfile): $!");
+ if (!$status)
+ {
+ print STDERR "graph.cgi: Unable to open temporary file \"$tmpfile\" for reading: $!\n";
+ }
+ else
+ {
+ local $/ = undef;
+ while (my $data = <IMG>)
+ {
+ print STDOUT $data;
+ }
+
+ close (IMG);
+ unlink ($tmpfile);
+ }
}
-}
+} # sub main
-exit (0);
+main ();
# vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
index 85064b868f2354f4d5aff7f00bff1a5746be7d98..679c1eeade3a71da59c467ad365dc6ece2d8738d 100755 (executable)
#!/usr/bin/perl
-# Copyright (C) 2008 Florian octo Forster <octo at verplant.org>
+# 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
# 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 lib ('../lib');
use utf8;
+use vars (qw($BASE_DIR));
+
+BEGIN
+{
+ if (defined $ENV{'SCRIPT_FILENAME'})
+ {
+ if ($ENV{'SCRIPT_FILENAME'} =~ m{^(/.+)/bin/[^/]+$})
+ {
+ $BASE_DIR = $1;
+ unshift (@INC, "$BASE_DIR/lib");
+ }
+ }
+}
use Carp (qw(cluck confess));
-use FindBin ('$RealBin');
use CGI (':cgi');
use CGI::Carp ('fatalsToBrowser');
use HTML::Entities ('encode_entities');
get_plugin_selection flush_files));
use Collectd::Graph::Type ();
-our $Debug = param ('debug') ? 1 : 0;
-
our $TimeSpans =
{
Hour => 3600,
Year => 366 * 86400
};
-my $action = param ('action') || 'list_hosts';
-our %Actions =
+my %Actions =
(
list_hosts => \&action_list_hosts,
show_selection => \&action_show_selection
);
-if (!exists ($Actions{$action}))
+my $have_init = 0;
+sub init
{
- print STDERR "No such action: $action\n";
- exit 1;
+ if ($have_init)
+ {
+ return;
+ }
+
+ print STDERR "INC = (" . join (', ', @INC) . ");\n";
+
+ gc_read_config ("$BASE_DIR/etc/collection.conf");
+
+ $have_init = 1;
}
-gc_read_config ("$RealBin/../etc/collection.conf");
+sub main
+{
+ my $Debug = param ('debug') ? 1 : 0;
+ my $action = param ('action') || 'list_hosts';
+
+ if (!exists ($Actions{$action}))
+ {
+ print STDERR "No such action: $action\n";
+ return (1);
+ }
+
+ init ();
-$Actions{$action}->();
-exit (0);
+ $Actions{$action}->();
+ return (1);
+} # sub main
sub can_handle_xhtml
{
}
} # can_handle_xhtml
-{my $html_started;
+my $html_started;
sub start_html
{
return if ($html_started);
if (can_handle_xhtml ())
{
+ print header (-Content_Type => 'application/xhtml+xml; charset=UTF-8');
print <<HTML;
-Content-Type: application/xhtml+xml; charset=UTF-8
-
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
}
else
{
+ print header (-Content_Type => 'text/html; charset=UTF-8');
print <<HTML;
-Content-Type: text/html; charset=UTF-8
-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<body onload="nav_init ($begin, $end);">
HTML
$html_started = 1;
-}}
+}
sub end_html
{
</body>
</html>
HTML
+ $html_started = 0;
}
sub show_selector
$all_files = get_selected_files ();
$timespan = get_timespan_selection ();
- if ($Debug)
+ if (param ('debug'))
{
print "<pre>", Data::Dumper->Dump ([$all_files], ['all_files']), "</pre>\n";
}
for (sort (keys %$types))
{
my $type = $_;
+
+ if (!defined ($types->{$type}))
+ {
+ next;
+ }
+
my $graphs_num = $types->{$type}->getGraphsNum ();
for (my $i = 0; $i < $graphs_num; $i++)
end_html ();
}
+main ();
+
=head1 SEE ALSO
L<Collectd::Graph::Type>
diff --git a/contrib/collection3/lib/Collectd/Graph/Common.pm b/contrib/collection3/lib/Collectd/Graph/Common.pm
index c6e250819430c4330f5bf00ba48c847ab2b12819..cc7e141f8828380fb8978c796faf4df46f4c6653 100644 (file)
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 Exporter;
use Collectd::Graph::Config (qw(gc_get_scalar));
+our $Cache = {};
+
$ColorCanvas = 'FFFFFF';
$ColorFullBlue = '0000FF';
$ColorHalfBlue = 'B7B7F7';
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);
sub get_all_hosts
{
- my $dh;
- my @ret = ();
- my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
+ my $ret = [];
- opendir ($dh, "$data_dir") or confess ("opendir ($data_dir): $!");
- while (my $entry = readdir ($dh))
+ if (defined ($Cache->{'get_all_hosts'}))
{
- next if ($entry =~ m/^\./);
- next if (!-d "$data_dir/$entry");
- next if (!-r "$data_dir/$entry" or !-x "$data_dir/$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
{
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 = $_;
closedir ($dh);
} # for (@hosts)
+ $Cache->{'get_all_plugins'}{$cache_key} = $ret;
if (wantarray ())
{
return (sort (keys %$ret));
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 $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
- #if ($ident->{'hostname'})
- #{
- #$all_files = get_files_for_host ($ident->{'hostname'});
- #}
- #else
- #{
- $all_files = get_files_from_directory ($data_dir, 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)
+ }
+
+ $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