that the compiled binary actually behaves as it should, but since NANs
are likely never passed to the libm you have a good chance to be lucky.
+ Likewise, collectd needs to know the layout of doubles in memory, in order
+ to craft uniform network packets over different architectures. For this, it
+ needs to know how to convert doubles into the memory layout used by x86. The
+ configure script tries to figure this out by compiling and running a few
+ small test programs. This is of course not possible when cross-compiling.
+ You can use the `--with-fp-layout' option to tell the configure script which
+ conversion method to assume. Valid arguments are:
+
+ * `nothing' (12345678 -> 12345678)
+ * `endianflip' (12345678 -> 87654321)
+ * `intswap' (12345678 -> 56781234)
+
Contact
-------
- For questions, bugreports, development information and basically all other
- concerns please send an email to collectd's mailinglist at
+ For questions, bug reports, development information and basically all other
+ concerns please send an email to collectd's mailing list at
<collectd at verplant.org>.
For live discussion and more personal contact visit us in IRC, we're in
Sebastian tokkee Harl <sh at tokkee.org>,
and many contributors (see `AUTHORS').
- Please send bugreports and patches to the mailinglist, see `Contact' above.
+ Please send bug reports and patches to the mailing list, see `Contact'
+ above.
--- /dev/null
+Options +ExecCGI
+AddHandler cgi-script .cgi
+#DataDir "/var/lib/collectd/rrd"
GraphWidth 400
#UnixSockAddr "/var/run/collectd-unixsock"
<Type apache_bytes>
use vars (qw($ColorCanvas $ColorFullBlue $ColorHalfBlue));
-use Collectd::Unixsock;
-
+use Collectd::Unixsock ();
use Carp (qw(confess cluck));
use CGI (':cgi');
use Exporter;
+use Collectd::Graph::Config (qw(gc_get_scalar));
$ColorCanvas = 'FFFFFF';
$ColorFullBlue = '0000FF';
flush_files
));
-our $DataDir = '/var/lib/collectd/rrd';
+our $DefaultDataDir = '/var/lib/collectd/rrd';
return (1);
sub ident_to_filename
{
my $ident = shift;
+ my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
my $ret = '';
}
else
{
- $ret .= "$DataDir/";
+ $ret .= "$data_dir/";
}
if (!$ident->{'hostname'})
{
my $dh;
my @ret = ();
+ my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
- opendir ($dh, "$DataDir") or confess ("opendir ($DataDir): $!");
+ opendir ($dh, "$data_dir") or confess ("opendir ($data_dir): $!");
while (my $entry = readdir ($dh))
{
next if ($entry =~ m/^\./);
- next if (!-d "$DataDir/$entry");
+ next if (!-d "$data_dir/$entry");
push (@ret, sanitize_hostname ($entry));
}
closedir ($dh);
my @hosts = @_;
my $ret = {};
my $dh;
+ my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
if (!@hosts)
{
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#^([^-]+)-(.+)$#)
{
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
my $ident = shift;
my $all_files;
my @ret = ();
+ my $data_dir = gc_get_scalar ('DataDir', $DefaultDataDir);
#if ($ident->{'hostname'})
#{
#}
#else
#{
- $all_files = get_files_from_directory ($DataDir, 3);
+ $all_files = get_files_from_directory ($data_dir, 3);
#}
@ret = grep { _filter_ident ($ident, $_) == 0 } (@$all_files);
=cut
-# Copyright (C) 2008 Florian octo Forster <octo at verplant.org>
+# 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
use Carp (qw(cluck confess));
use Exporter ();
use Config::General ('ParseConfig');
-use Collectd::Graph::Type ();
@Collectd::Graph::Config::ISA = ('Exporter');
@Collectd::Graph::Config::EXPORT_OK = (qw(gc_read_config gc_get_config
package Collectd::Graph::Type::Df;
+# 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');
my $faded_green = get_faded_color ('00ff00');
my $faded_red = get_faded_color ('ff0000');
- return (['-t', 'Free space (' . $ident->{'type_instance'} . ')', '-v', 'Bytes', '-l', '0',
+ return (['-t', 'Diskspace (' . $ident->{'type_instance'} . ')', '-v', 'Bytes', '-l', '0',
"DEF:free_min=${filename}:free:MIN",
"DEF:free_avg=${filename}:free:AVERAGE",
"DEF:free_max=${filename}:free:MAX",
package Collectd::Graph::Type::GenericIO;
+# 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');
}
push (@ret,
+ "CDEF:avg_rx_bytes=avg_rx,8,/",
+ "VDEF:global_min_rx=min_rx,MINIMUM",
+ "VDEF:global_avg_rx=avg_rx,AVERAGE",
+ "VDEF:global_max_rx=max_rx,MAXIMUM",
+ "VDEF:global_tot_rx=avg_rx_bytes,TOTAL",
+ "CDEF:avg_tx_bytes=avg_tx,8,/",
+ "VDEF:global_min_tx=min_tx,MINIMUM",
+ "VDEF:global_avg_tx=avg_tx,AVERAGE",
+ "VDEF:global_max_tx=max_tx,MAXIMUM",
+ "VDEF:global_tot_tx=avg_tx_bytes,TOTAL");
+
+ push (@ret,
"CDEF:overlap=avg_rx,avg_tx,LT,avg_rx,avg_tx,IF",
"AREA:avg_rx#${rx_color_bg}",
"AREA:avg_tx#${tx_color_bg}",
"AREA:overlap#${overlap_color}",
"LINE1:avg_rx#${rx_color_fg}:${rx_ds_name}",
- "GPRINT:min_rx:MIN:${format} Min,",
- "GPRINT:avg_rx:AVERAGE:${format} Avg,",
- "GPRINT:max_rx:MAX:${format} Max,",
- "GPRINT:avg_rx:LAST:${format} Last\\l",
+ "GPRINT:global_min_rx:${format} Min,",
+ "GPRINT:global_avg_rx:${format} Avg,",
+ "GPRINT:global_max_rx:${format} Max,",
+ "GPRINT:global_tot_rx:ca. ${format} Total\\l",
"LINE1:avg_tx#${tx_color_fg}:${tx_ds_name}",
- "GPRINT:min_tx:MIN:${format} Min,",
- "GPRINT:avg_tx:AVERAGE:${format} Avg,",
- "GPRINT:max_tx:MAX:${format} Max,",
- "GPRINT:avg_tx:LAST:${format} Last\\l");
+ "GPRINT:global_min_tx:${format} Min,",
+ "GPRINT:global_avg_tx:${format} Avg,",
+ "GPRINT:global_max_tx:${format} Max,",
+ "GPRINT:global_tot_tx:ca. ${format} Total\\l");
return (\@ret);
} # getRRDArgs
package Collectd::Graph::Type::GenericStacked;
+# 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');
my $colors = $obj->{'rrd_colors'} || {};
my @ret = ('-t', $rrd_title, @$rrd_opts);
+ my $ignore_unknown = $obj->{'ignore_unknown'} || 0;
+ if ($ignore_unknown)
+ {
+ if ($ignore_unknown =~ m/^(yes|true|on)$/i)
+ {
+ $ignore_unknown = 1;
+ }
+ else
+ {
+ $ignore_unknown = 0;
+ }
+ }
+
if (defined $obj->{'rrd_vertical'})
{
push (@ret, '-v', $obj->{'rrd_vertical'});
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);
if ($i == (@$idents - 1))
{
push (@ret,
- "CDEF:cdef${i}=avg${i}");
+ "CDEF:cdef${i}=avg${i},UN,0,avg${i},IF");
}
else
{
my $j = $i + 1;
push (@ret,
- "CDEF:cdef${i}=cdef${j},avg${i},+");
+ "CDEF:cdef${i}=avg${i},UN,0,avg${i},IF,cdef${j},+");
}
}
=cut
-# Copyright (C) 2008 Florian octo Forster <octo at verplant.org>
+# 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
@Collectd::Graph::TypeLoader::EXPORT_OK = ('tl_load_type');
our @ArrayMembers = (qw(data_sources rrd_opts custom_order));
-our @ScalarMembers = (qw(rrd_title rrd_format rrd_vertical scale));
+our @ScalarMembers = (qw(rrd_title rrd_format rrd_vertical scale ignore_unknown));
our @DSMappedMembers = (qw(ds_names rrd_colors));
our %MemberToConfigMap =
rrd_vertical => 'rrdverticallabel',
rrd_colors => 'color',
scale => 'scale', # GenericIO only
- custom_order => 'order' # GenericStacked only
+ custom_order => 'order', # GenericStacked only
+ ignore_unknown => 'ignoreunknown' # GenericStacked only
);
return (1);
my $module = shift;
my $obj;
- local $SIG{__WARN__} = sub {};
- local $SIG{__DIE__} = sub {};
+ local $SIG{__WARN__} = sub { print STDERR "WARNING: " . join (', ', @_) . "\n"; };
+ local $SIG{__DIE__} = sub { print STDERR "FATAL: " . join (', ', @_) . "\n"; };
eval <<PERL;
require $module;
}
else
{
- $opts->{'script'} = $script;
- push (@$Scripts, $opts);
+ if (ref ($opts) eq 'ARRAY')
+ {
+ for (@$opts)
+ {
+ my $opt = $_;
+ $opt->{'script'} = $script;
+ push (@$Scripts, $opt);
+ }
+ }
+ else
+ {
+ $opts->{'script'} = $script;
+ push (@$Scripts, $opts);
+ }
}
} # for (keys %$scripts)
} # handle_config_script
}
}
-function GraphListFromCookie() {
+function GraphListFromCookie(lname) {
if (document.cookie.length > 0) {
- cookies = document.cookie.split('; ');
+ var cname= 'graphLst'+lname+'=';
+ var cookies = document.cookie.split('; ');
for (i = 0; i < cookies.length; i++)
- if (cookies[i].substring(0, 9) == 'graphLst=')
- return cookies[i].substring(9).split('/');
+ if (cookies[i].substring(0, cname.length) == cname)
+ return cookies[i].substring(cname.length).split('/');
}
return new Array();
}
+function GraphListNameSort(a, b) {
+ if (a[0] > b[0])
+ return 1
+ else if (a[0] < b[0])
+ return -1;
+ else
+ return 0;
+}
+
+function GraphListRefresh() {
+ var select = document.getElementById('GraphList');
+ var childCnt = select.childNodes.length;
+ var oldValue = select.selectedIndex > 0 ? select.options[select.selectedIndex].value : '/';
+ while (childCnt > 0)
+ select.removeChild(select.childNodes[--childCnt]);
+
+ // Determine available names
+ var options = new Array();
+ if (document.cookie.length > 0) {
+ var cookies = document.cookie.split('; ');
+ for (i = 0; i < cookies.length; i++)
+ if (cookies[i].substring(0, 8) == 'graphLst') {
+ var p = cookies[i].indexOf('=');
+ if (p < 0)
+ continue;
+ options.push(new Array(cookies[i].substring(8, p), cookies[i].substring(p+1).split('/').length));
+ }
+ }
+ options.sort(GraphListNameSort);
+
+ var optCnt = options ? options.length : 0;
+ if (optCnt == 0) {
+ select.setAttribute('disabled', 'disabled');
+ return -1;
+ } else {
+ select.removeAttribute('disabled');
+ for (i = 0; i < optCnt; i++) {
+ newOption = document.createElement("option");
+ newOption.value = options[i][0];
+ if (newOption.value == oldValue)
+ newOption.setAttribute('selected', 'selected');
+ if (options[i][1] == 1)
+ newOption.appendChild(document.createTextNode(newOption.value+' (1 graph)'));
+ else
+ newOption.appendChild(document.createTextNode(newOption.value+' ('+options[i][1]+' graphs)'));
+ select.appendChild(newOption);
+ }
+ return select.selectedIndex;
+ }
+}
+
+function GraphListCheckName(doalert) {
+ var lname = document.getElementById('GraphListName');
+ if (lname) {
+ if (lname.value.match(/^[a-zA-Z0-9_-]+$/)) {
+ lname.style.backgroundColor = '';
+ return lname.value;
+ } else {
+ lname.style.backgroundColor = '#ffdddd';
+ if (doalert && lname.value.length == 0)
+ alert('Graph list name is empty.\n\n'+
+ 'Please fill in a name and try again.');
+ else if (doalert)
+ alert('Graph list name contains non-permitted character.\n\n'+
+ 'Only anlphanumerical characters (a-z, A-Z, 0-9), hyphen (-) and underscore (_) are permitted.\n'+
+ 'Please correct and try again.');
+ lname.focus();
+ }
+ }
+ return '';
+}
+
function GraphSave() {
+ var lstName = GraphListCheckName(true);
+ if (lstName.length == 0)
+ return;
if (graphList.length > 0) {
// Save graph list to cookie
var str = '';
str += graphList[i].substring(g+1);
}
- document.cookie = 'graphLst='+str;
- if (GraphListFromCookie().length == 0)
- alert("Failed to save graph list to cookie.");
+ document.cookie = 'graphLst'+lstName+'='+str;
+ if (GraphListFromCookie(lstName).length == 0)
+ alert("Failed to save graph list '"+lstName+"' to cookie.");
else
alert("Successfully saved current graph list.");
} else {
- document.cookie = 'graphLst=; expires='+new Date().toGMTString();
+ document.cookie = 'graphLst'+lstName+'=; expires='+new Date().toGMTString();
alert("Cleared saved graph list.");
}
+ GraphListRefresh();
+}
+
+function GraphDrop() {
+ var cname = document.getElementById('GraphList');
+ if (cname && cname.selectedIndex >= 0) {
+ cname = cname.options[cname.selectedIndex].value;
+ document.cookie = 'graphLst'+cname+'=; expires='+new Date().toGMTString();
+ GraphListRefresh();
+ } else
+ return;
}
function GraphLoad() {
+ var cname = document.getElementById('GraphList');
+ if (cname && cname.selectedIndex >= 0)
+ cname = cname.options[cname.selectedIndex].value;
+ else
+ return;
// Load graph list from cookie
- var grLst = GraphListFromCookie();
+ var grLst = GraphListFromCookie(cname);
+ var oldLength = graphList.length;
for (i = 0; i < grLst.length; i++) {
var host = '';
var plugin = '';
GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
}
if (grLst.length == 0)
- alert("No list found for loading.");
- else if (grLst.length != graphList.length)
+ alert("No list '"+cname+"' found for loading.");
+ else if (grLst.length + oldLength != graphList.length)
alert("Could not load all graphs, probably damaged cookie.");
}
$MetaGraphDefs['apache_scoreboard'] = 'meta_graph_apache_scoreboard';
$MetaGraphDefs['mysql_commands'] = 'meta_graph_mysql_commands';
$MetaGraphDefs['mysql_handler'] = 'meta_graph_mysql_commands';
+ $MetaGraphDefs['tcp_connections'] = 'meta_graph_tcp_connections';
+ $MetaGraphDefs['dns_opcode'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_qtype'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_rcode'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_request'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_resolver'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_update'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_zops'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_response'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_query'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_reject'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_notify'] = 'meta_graph_dns_event';
+ $MetaGraphDefs['dns_transfer'] = 'meta_graph_dns_event';
if (function_exists('load_graph_definitions_local'))
load_graph_definitions_local($logarithmic, $tinylegend);
$files = array();
$opts['colors'] = array(
+ // Linux - System memoery
'free' => '00e000',
'cached' => '0000ff',
'buffered' => 'ffb000',
- 'used' => 'ff0000'
+ 'used' => 'ff0000',
+ // Bind - Server memory
+ 'TotalUse' => '00e000',
+ 'InUse' => 'ff0000',
+ 'BlockSize' => '8888dd',
+ 'ContextSize' => '444499',
+ 'Lost' => '222222'
);
- $type_instances = array('free', 'cached', 'buffered', 'used');
+ $type_instances = array('free', 'cached', 'buffered', 'used', 'TotalUse', 'InUse', 'BlockSize', 'ContextSize', 'Lost');
while (list($k, $inst) = each($type_instances)) {
$file = '';
foreach ($config['datadirs'] as $datadir)
if ($file == '')
continue;
- $sources[] = array('name'=>$inst, 'file'=>$file, 'ds'=>'count');
+ $sources[] = array('name'=>$inst, 'file'=>$file, 'ds'=>'value');
}
return collectd_draw_meta_stack($opts, $sources);
}
+function meta_graph_dns_event($host, $plugin, $plugin_instance, $type, $type_instances, $opts = array()) {
+ global $config;
+ $sources = array();
+
+ $title = "$host/$plugin".(!is_null($plugin_instance) ? "-$plugin_instance" : '')."/$type";
+ if (!isset($opts['title']))
+ $opts['title'] = $title;
+ $opts['rrd_opts'] = array('-v', 'Events', '-r', '-l', '0');
+
+ $files = array();
+// $opts['colors'] = array(
+// );
+
+// $type_instances = array('IQUERY', 'NOTIFY');
+ while (list($k, $inst) = each($type_instances)) {
+ $file = '';
+ $title = $opts['title'];
+ foreach ($config['datadirs'] as $datadir)
+ if (is_file($datadir.'/'.$title.'-'.$inst.'.rrd')) {
+ $file = $datadir.'/'.$title.'-'.$inst.'.rrd';
+ break;
+ }
+ if ($file == '')
+ continue;
+
+ $sources[] = array('name'=>$inst, 'file'=>$file);
+ }
+ return collectd_draw_meta_stack($opts, $sources);
+}
+
?>
if (is_null($identifier) || (is_array($identifier) && count($identifier) == 0) || !(is_string($identifier) || is_array($identifier)))
return false;
- if (is_null($host) || !is_string($host) || strlen($host) == 0)
- return false;
- if (is_null($plugin) || !is_string($plugin) || strlen($plugin) == 0)
- return false;
- if (is_null($pinst) || !is_string($pinst))
- return false;
- if (is_null($type) || !is_string($type) || strlen($type) == 0)
- return false;
- if (is_null($tinst) || (is_array($tinst) && count($tinst) == 0) || !(is_string($tinst) || is_array($tinst)))
- return false;
-
$u_errno = 0;
$u_errmsg = '';
if ($socket = @fsockopen($config['collectd_sock'], 0, $u_errno, $u_errmsg)) {
return $str;
}
+function rrd_escape($str) {
+ return str_replace(array('\\', ':'), array('\\\\', '\\:'), $str);
+}
+
/**
* Determine useful information about RRD file
* @file Name of RRD file to analyse
if (strlen($k) > $l_max)
$l_max = strlen($k);
if ($has_min)
- $graph[] = sprintf('DEF:%s_min=%s:%s:MIN', $k, $rrdinfo['filename'], $k);
+ $graph[] = sprintf('DEF:%s_min=%s:%s:MIN', $k, rrd_escape($rrdinfo['filename']), $k);
if ($has_avg)
- $graph[] = sprintf('DEF:%s_avg=%s:%s:AVERAGE', $k, $rrdinfo['filename'], $k);
+ $graph[] = sprintf('DEF:%s_avg=%s:%s:AVERAGE', $k, rrd_escape($rrdinfo['filename']), $k);
if ($has_max)
- $graph[] = sprintf('DEF:%s_max=%s:%s:MAX', $k, $rrdinfo['filename'], $k);
+ $graph[] = sprintf('DEF:%s_max=%s:%s:MAX', $k, rrd_escape($rrdinfo['filename']), $k);
}
if ($has_min && $has_max || $has_min && $has_avg || $has_avg && $has_max) {
$n = 1;
continue;
$file = str_replace(":", "\\:", $file);
- $rrd_args = str_replace('{file}', $file, $rrd_args);
+ $rrd_args = str_replace('{file}', rrd_escape($file), $rrd_args);
$rrdgraph = array_merge($rrd_cmd, $rrd_args);
$cmd = RRDTOOL;
$max_inst_name = 0;
foreach($sources as &$inst_data) {
- $inst_name = $inst_data['name'];
+ $inst_name = str_replace('!', '_', $inst_data['name']);
$file = $inst_data['file'];
$ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
if (!is_file($file))
continue;
- $cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
- $cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
- $cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
+ $cmd[] = 'DEF:'.$inst_name.'_min='.rrd_escape($file).':'.$ds.':MIN';
+ $cmd[] = 'DEF:'.$inst_name.'_avg='.rrd_escape($file).':'.$ds.':AVERAGE';
+ $cmd[] = 'DEF:'.$inst_name.'_max='.rrd_escape($file).':'.$ds.':MAX';
$cmd[] = 'CDEF:'.$inst_name.'_nnl='.$inst_name.'_avg,UN,0,'.$inst_name.'_avg,IF';
}
$inst_data = end($sources);
$inst_data1 = end($sources);
while (($inst_data0 = prev($sources)) !== false) {
- $inst_name0 = $inst_data0['name'];
- $inst_name1 = $inst_data1['name'];
+ $inst_name0 = str_replace('!', '_', $inst_data0['name']);
+ $inst_name1 = str_replace('!', '_', $inst_data1['name']);
$cmd[] = 'CDEF:'.$inst_name0.'_stk='.$inst_name0.'_nnl,'.$inst_name1.'_stk,+';
$inst_data1 = $inst_data0;
}
foreach($sources as &$inst_data) {
- $inst_name = $inst_data['name'];
- $legend = sprintf('%s', $inst_name);
+ $inst_name = str_replace('!', '_', $inst_data['name']);
+ $legend = sprintf('%s', $inst_data['name']);
while (strlen($legend) < $max_inst_name)
$legend .= ' ';
$number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
$max_inst_name = 0;
foreach ($sources as &$inst_data) {
- $inst_name = $inst_data['name'];
+ $inst_name = str_replace('!', '_', $inst_data['name']);
$file = $inst_data['file'];
$ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
if (!is_file($file))
continue;
- $cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
- $cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
- $cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
+ $cmd[] = 'DEF:'.$inst_name.'_min='.rrd_escape($file).':'.$ds.':MIN';
+ $cmd[] = 'DEF:'.$inst_name.'_avg='.rrd_escape($file).':'.$ds.':AVERAGE';
+ $cmd[] = 'DEF:'.$inst_name.'_max='.rrd_escape($file).':'.$ds.':MAX';
}
foreach ($sources as &$inst_data) {
- $inst_name = $inst_data['name'];
+ $inst_name = str_replace('!', '_', $inst_data['name']);
$legend = sprintf('%s', $inst_name);
while (strlen($legend) < $max_inst_name)
$legend .= ' ';
return error(400, "Bad request", $title, $msg);
}
+/**
+ * Incomplete / invalid request
+ */
+function error500($title, $msg) {
+ return error(500, "Internal error", $title, $msg);
+}
+
// Process input arguments
$host = read_var('host', $_GET, null);
if (is_null($host))
<script type="text/javascript" src="<?php echo htmlspecialchars($url_base.'browser.js'); ?>"></script>
</head>
- <body onload="ListRefreshHost()"><div class="body">
+ <body onload="ListRefreshHost(); GraphListRefresh(); "><div class="body">
<h1><img src="collectd-logo.png" align="bottom" alt="" /> Collectd browser for system statistics graphs</h1>
<div class="selector"><a href="javascript:toggleDiv('selector')"><span id="selector_sw">Hide</span> graph selection tool</a><div id="selector" class="selectorbox">
<table>
<tr>
<td class="sc" colspan="3"><input id="btnAdd" name="btnAdd" type="button" disabled="disabled" onclick="GraphAppend()" value="Add graph" />
<input id="btnClear" name="btnClear" type="button" disabled="disabled" onclick="GraphDropAll()" value="Remove all graphs" />
- <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefresh(null)" value="Refresh all graphs" />
- <input id="btnSave" name="btnSave" type="button" onclick="GraphSave()" value="Save" title="Save graph list to cookie" />
- <input id="btnLoad" name="btnLoad" type="button" onclick="GraphLoad()" value="Load" title="Load graph list from cookie" /></td>
+ <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefresh(null)" value="Refresh all graphs" /></td>
+ </tr>
+ <tr>
+ <td class="s1" rowspan="2">Graph list favorites:</td>
+ <td class="s3"><input type="text" style="width: 100%" maxlength="30" id="GraphListName" name="GraphListName" value="default" onchange="GraphListCheckName(false)" /></td>
+ <td class="s3"><a href="javascript:GraphSave()"><img src="save.png" width="16" height="16" alt="S" title="Save graph list to cookie" /></a></td>
+ </tr>
+ <tr>
+ <td class="s2"><select id="GraphList" name="GraphList" onfocus="GraphListRefresh()">
+ <option value="default">default</option>
+ </select></td>
+ <td class="s3"><a href="javascript:GraphLoad()"><img src="load.png" width="16" height="16" alt="L" title="Load graph list from cookie" /></a><a href="javascript:GraphDrop()"><img src="delete.png" width="16" height="16" alt="D" title="Delete graph list from cookie" /></a></td>
</tr>
</table>
</div></div>
</Query>
<Query disk_io>
- Statement "SELECT sum(heap_blks_read) AS heap_read, \
- sum(heap_blks_hit) AS heap_hit, \
- sum(idx_blks_read) AS idx_read, \
- sum(idx_blks_hit) AS idx_hit, \
- sum(toast_blks_read) AS toast_read, \
- sum(toast_blks_hit) AS toast_hit, \
- sum(tidx_blks_read) AS tidx_read, \
- sum(tidx_blks_hit) AS tidx_hit \
+ Statement "SELECT coalesce(sum(heap_blks_read), 0) AS heap_read, \
+ coalesce(sum(heap_blks_hit), 0) AS heap_hit, \
+ coalesce(sum(idx_blks_read), 0) AS idx_read, \
+ coalesce(sum(idx_blks_hit), 0) AS idx_hit, \
+ coalesce(sum(toast_blks_read), 0) AS toast_read, \
+ coalesce(sum(toast_blks_hit), 0) AS toast_hit, \
+ coalesce(sum(tidx_blks_read), 0) AS tidx_read, \
+ coalesce(sum(tidx_blks_hit), 0) AS tidx_hit \
FROM pg_statio_user_tables;"
<Result>
rrd_cache_t *cache_entry;
char **values;
int values_num;
+ int status;
int i;
pthread_mutex_lock (&queue_lock);
while (true)
{
struct timespec ts_wait;
- int status;
while ((flushq_head == NULL) && (queue_head == NULL)
&& (do_shutdown == 0))
* we make a copy of it's values */
pthread_mutex_lock (&cache_lock);
- c_avl_get (cache, queue_entry->filename, (void *) &cache_entry);
+ status = c_avl_get (cache, queue_entry->filename,
+ (void *) &cache_entry);
- values = cache_entry->values;
- values_num = cache_entry->values_num;
+ if (status == 0)
+ {
+ values = cache_entry->values;
+ values_num = cache_entry->values_num;
- cache_entry->values = NULL;
- cache_entry->values_num = 0;
- cache_entry->flags = FLAG_NONE;
+ cache_entry->values = NULL;
+ cache_entry->values_num = 0;
+ cache_entry->flags = FLAG_NONE;
+ }
pthread_mutex_unlock (&cache_lock);
+ if (status != 0)
+ {
+ sfree (queue_entry->filename);
+ sfree (queue_entry);
+ continue;
+ }
+
/* Update `tv_next_update' */
if (write_rate > 0.0)
{
pthread_mutex_lock (&cache_lock);
+ /* This shouldn't happen, but it did happen at least once, so we'll be
+ * careful. */
+ if (cache == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ WARNING ("rrdtool plugin: cache == NULL.");
+ return (-1);
+ }
+
c_avl_get (cache, filename, (void *) &rc);
if (rc == NULL)
}
} /* void csnmp_host_open_session */
+/* TODO: Check if negative values wrap around. Problem: negative temperatures. */
static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
double scale, double shift)
{
{
c_avl_node_t *n;
+ assert (t != NULL);
+
n = search (t, key);
if (n == NULL)
return (-1);