#!/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 :
#!/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>
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