1 |
#!/usr/bin/perl |
2 |
############################################################ |
3 |
# |
4 |
# $Id: rrd-server.pl 1092 2008-01-23 14:23:51Z nicolaw $ |
5 |
# rrd-server.pl - Data gathering script for RRD::Simple |
6 |
# |
7 |
# Copyright 2006, 2007, 2008 Nicola Worthington |
8 |
# |
9 |
# Licensed under the Apache License, Version 2.0 (the "License"); |
10 |
# you may not use this file except in compliance with the License. |
11 |
# You may obtain a copy of the License at |
12 |
# |
13 |
# http://www.apache.org/licenses/LICENSE-2.0 |
14 |
# |
15 |
# Unless required by applicable law or agreed to in writing, software |
16 |
# distributed under the License is distributed on an "AS IS" BASIS, |
17 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 |
# See the License for the specific language governing permissions and |
19 |
# limitations under the License. |
20 |
# |
21 |
############################################################ |
22 |
# vim:ts=4:sw=4:tw=78 |
23 |
|
24 |
BEGIN { |
25 |
# User defined constants |
26 |
use constant BASEDIR => '/var/www/rrd'; |
27 |
use constant THEME => ('BACK#F5F5FF','SHADEA#C8C8FF','SHADEB#9696BE', |
28 |
'ARROW#61B51B','GRID#404852','MGRID#67C6DE'); |
29 |
} |
30 |
|
31 |
|
32 |
|
33 |
BEGIN { |
34 |
# Ensure we can find RRDs.so for RRDs.pm |
35 |
eval "use RRDs"; |
36 |
if ($@ && !defined $ENV{LD_LIBRARY_PATH}) { |
37 |
$ENV{LD_LIBRARY_PATH} = BASEDIR.'/lib'; |
38 |
exec($0,@ARGV); |
39 |
} |
40 |
} |
41 |
|
42 |
use 5.004; |
43 |
use strict; |
44 |
use warnings; |
45 |
use lib qw(../lib); |
46 |
use RRD::Simple 1.41; |
47 |
use RRDs; |
48 |
use Memoize; |
49 |
use Getopt::Std qw(); |
50 |
use File::Basename qw(basename); |
51 |
use File::Path qw(); |
52 |
use Config::General qw(); |
53 |
use File::Spec::Functions qw(catfile catdir); |
54 |
use vars qw($VERSION); |
55 |
|
56 |
$VERSION = '1.43' || sprintf('%d', q$Revision: 1092 $ =~ /(\d+)/g); |
57 |
|
58 |
# Get command line options |
59 |
my %opt = (); |
60 |
$Getopt::Std::STANDARD_HELP_VERSION = 1; |
61 |
$Getopt::Std::STANDARD_HELP_VERSION = 1; |
62 |
Getopt::Std::getopts('r:u:G:T:gthvVf?', \%opt); |
63 |
|
64 |
$opt{g} ||= $opt{G}; |
65 |
$opt{t} ||= $opt{T}; |
66 |
|
67 |
# Display help or version |
68 |
(VERSION_MESSAGE() && exit) if defined $opt{v}; |
69 |
(HELP_MESSAGE() && exit) if defined $opt{h} || defined $opt{'?'} || |
70 |
!(defined $opt{u} || defined $opt{g} || defined $opt{t} || defined $opt{r}); |
71 |
|
72 |
# cd to the righr location and define directories |
73 |
chdir BASEDIR || die sprintf("Unable to chdir to '%s': %s", BASEDIR, $!); |
74 |
my %dir = map { ( $_ => BASEDIR."/$_" ) } qw(bin data etc graphs cgi-bin thumbnails); |
75 |
|
76 |
# Create an RRD::Simple object |
77 |
my $rrd = RRD::Simple->new(rrdtool => "$dir{bin}/rrdtool"); |
78 |
|
79 |
# Cache results from read_create_data() |
80 |
memoize('read_create_data'); |
81 |
memoize('read_graph_data'); |
82 |
memoize('basename'); |
83 |
memoize('graph_def'); |
84 |
|
85 |
if ( my $hostname = $opt{r} ) { |
86 |
warn "# refresh $hostname\n"; |
87 |
$opt{V} = 1; |
88 |
create_thumbnails($rrd,\%dir,$hostname); |
89 |
create_graphs($rrd,\%dir,$hostname); |
90 |
exit; |
91 |
} |
92 |
|
93 |
# Update the RRD if we've been asked to |
94 |
my $hostname = defined $opt{u} ? update_rrd($rrd,\%dir,$opt{u}) : undef; |
95 |
|
96 |
# Generate some graphs |
97 |
my @hosts; |
98 |
for my $host (($hostname, $opt{G}, $opt{T})) { |
99 |
next unless defined $host; |
100 |
for (split(/\s*[,:]\s*/,$host)) { |
101 |
push(@hosts, $_) if defined($_) && length($_); |
102 |
} |
103 |
} |
104 |
@hosts = list_dir($dir{data}) unless @hosts; |
105 |
|
106 |
for my $hostname (@hosts) { |
107 |
create_thumbnails($rrd,\%dir,$hostname) if defined $opt{t}; |
108 |
create_graphs($rrd,\%dir,$hostname) if defined $opt{g}; |
109 |
} |
110 |
|
111 |
exit; |
112 |
|
113 |
|
114 |
|
115 |
|
116 |
sub create_graphs { |
117 |
my ($rrd,$dir,$hostname,@options) = @_; |
118 |
|
119 |
my ($caller) = ((caller(1))[3] || '') =~ /.*::(.+)$/; |
120 |
my $thumbnails = defined $caller && $caller eq 'create_thumbnails' ? 1 : 0; |
121 |
my $destdir = $thumbnails ? $dir->{thumbnails} : $dir->{graphs}; |
122 |
|
123 |
my @colour_theme = (color => [ THEME ]); |
124 |
my $gdefs = read_graph_data("$dir->{etc}/graph.defs"); |
125 |
my @hosts = defined $hostname ? ($hostname) |
126 |
: grep { -d catdir($dir->{data}, $_) } list_dir("$dir->{data}"); |
127 |
|
128 |
# For each hostname |
129 |
for my $hostname (sort @hosts) { |
130 |
# Create the graph directory for this hostname |
131 |
my $destination = "$destdir/$hostname"; |
132 |
File::Path::mkpath($destination) unless -d $destination; |
133 |
|
134 |
# For each RRD |
135 |
for my $file (grep { $_ =~ /\.rrd$/i && !-d catfile($dir->{data},$hostname,$_) } |
136 |
list_dir(catdir($dir->{data},$hostname)) |
137 |
) { |
138 |
|
139 |
# next unless $file =~ /cpu_utilisation/; |
140 |
|
141 |
my $rrdfile = catfile($dir->{data},$hostname,$file); |
142 |
my $graph = basename($file,'.rrd'); |
143 |
my $gdef = graph_def($gdefs,$graph); |
144 |
|
145 |
# Make sure we parse these raw commands with care |
146 |
my @raw_cmd_list = qw(DEF CDEF VDEF TEXTALIGN AREA STACK LINE\d* HRULE\d* VRULE\d* TICK SHIFT GPRINT PRINT COMMENT); |
147 |
my $raw_cmd_regex = '('.join('|',@raw_cmd_list).')'; |
148 |
# my $raw_cmd_regex = qr/^(?:[VC]?DEF|G?PRINT|COMMENT|[HV]RULE\d*|LINE\d*|AREA|TICK|SHIFT|STACK|TEXTALIGN)$/i; |
149 |
my @raw_commands; |
150 |
my @def_sources; |
151 |
my @def_sources_draw; |
152 |
|
153 |
# Allow users to put raw commands in the graph.defs file |
154 |
for my $raw_cmd (@raw_cmd_list) { |
155 |
for my $cmd (grep(/^$raw_cmd$/i, keys %{$gdef})) { |
156 |
my $values = $gdef->{$cmd}; |
157 |
$values = [($values)] unless ref($values); |
158 |
for my $v (@{$values}) { |
159 |
push @raw_commands, (sprintf('%s:%s', uc($cmd), $v) => ''); |
160 |
if ($cmd =~ /^[CV]?DEF$/i && $v =~ /^([a-z0-9\_\-]{1,30})=/) { |
161 |
push @def_sources, $1; |
162 |
} elsif ($cmd =~ /^(?:LINE\d*|AREA|G?PRINT|TICK|STACK)$/i && $v =~ /^([a-z0-9\_\-]{1,30})[#:]/) { |
163 |
push @def_sources_draw, $1; |
164 |
} |
165 |
} |
166 |
} |
167 |
} |
168 |
|
169 |
# Wrap the RRD::Simple calls in an eval() block just in case |
170 |
# the explode in a big nasty smelly heap! |
171 |
eval { |
172 |
|
173 |
# Anything that doesn't start with ^source(?:s|_) should just |
174 |
# be pushed on to the RRD::Simple->graph option stack (So this |
175 |
# would NOT include the "sources" option). |
176 |
my @graph_opts = map { ($_ => $gdef->{$_}) } |
177 |
grep(!/^source(s|_)/ && !/^$raw_cmd_regex$/i, keys %{$gdef}); |
178 |
|
179 |
# Anything that starts with ^source_ should be split up and passed |
180 |
# as a hash reference in to the RRD::Simple->graph option stack |
181 |
# (This would NOT include the "sources" option). |
182 |
push @graph_opts, map { |
183 |
# If we see a value from a key/value pair that looks |
184 |
# like it might be quoted and comma seperated, |
185 |
# "like this", 'then we should','split especially' |
186 |
if ($gdef->{$_} =~ /["']\s*,\s*["']/) { |
187 |
($_ => [ split(/\s*["']\s*,\s*["']\s*/,$gdef->{$_}) ]) |
188 |
|
189 |
# Otherwise just split on whitespace like the old |
190 |
# version of rrd-server.pl used to do. |
191 |
} else { |
192 |
($_ => [ split(/\s+/,$gdef->{$_}) ]) |
193 |
} |
194 |
} grep(/^source_/,keys %{$gdef}); |
195 |
|
196 |
# By default we want to tell RRDtool to be lazy and only generate |
197 |
# graphs when it's actually necessary. If we have the -f for force |
198 |
# flag then we won't let RRDtool be economical. |
199 |
push @graph_opts, ('lazy','') unless exists $opt{f}; |
200 |
|
201 |
# Only draw the sources we've been told to, and only |
202 |
# those that actually exist in the RRD file |
203 |
my @rrd_sources = $rrd->sources($rrdfile); |
204 |
if (defined $gdef->{sources}) { |
205 |
my @sources; |
206 |
for my $ds (split(/(?:\s+|\s*,\s*)/,$gdef->{sources})) { |
207 |
push @sources, $ds if grep(/^$ds$/,@rrd_sources); |
208 |
} |
209 |
push @graph_opts, ('sources',\@sources); |
210 |
} elsif (!@def_sources && !@def_sources_draw) { |
211 |
push @graph_opts, ('sources', [ sort @rrd_sources ]); |
212 |
} else { |
213 |
push @graph_opts, ('sources', undef); |
214 |
} |
215 |
|
216 |
printf "Generating %s/%s/%s ...\n", |
217 |
$hostname, |
218 |
($thumbnails ? 'thumbnails' : 'graphs'), |
219 |
$graph if $opt{V}; |
220 |
|
221 |
# Generate the graph and capture the results to |
222 |
# write the text file output in the same directory |
223 |
my @stack = ($rrdfile); |
224 |
push @stack, @raw_commands if @raw_commands; |
225 |
push @stack, ( destination => $destination ); |
226 |
push @stack, ( timestamp => 'both' ); |
227 |
push @stack, @colour_theme if @colour_theme; |
228 |
push @stack, @options if @options; |
229 |
push @stack, @graph_opts if @graph_opts; |
230 |
write_txt($rrd->graph(@stack)); |
231 |
|
232 |
my $glob = catfile($destination,"$graph*.png"); |
233 |
my @images = glob($glob); |
234 |
warn "[Warning] $rrdfile: Looks like \$rrd->graph() failed to generate any images in '$glob'\n." |
235 |
unless @images; |
236 |
}; |
237 |
warn "[Warning] $rrdfile: => $@" if $@; |
238 |
} |
239 |
} |
240 |
} |
241 |
|
242 |
sub graph_def { |
243 |
my ($gdefs,$graph) = @_; |
244 |
|
245 |
my $rtn = {}; |
246 |
for (keys %{$gdefs->{graph}}) { |
247 |
my $graph_key = qr(^$_$); |
248 |
if (my ($var) = $graph =~ /$graph_key/) { |
249 |
$rtn = { %{$gdefs->{graph}->{$_}} }; |
250 |
unless (defined $var && "$var" ne "1") { |
251 |
($var) = $graph =~ /_([^_]+)$/; |
252 |
} |
253 |
for my $key (keys %{$rtn}) { |
254 |
$rtn->{$key} =~ s/\$1/$var/g; |
255 |
} |
256 |
last; |
257 |
} |
258 |
} |
259 |
|
260 |
return $rtn; |
261 |
} |
262 |
|
263 |
sub list_dir { |
264 |
my $dir = shift; |
265 |
my @items = (); |
266 |
opendir(DH,$dir) || die "Unable to open file handle for directory '$dir': $!"; |
267 |
@items = grep(!/^\./,readdir(DH)); |
268 |
closedir(DH) || die "Unable to close file handle for directory '$dir': $!"; |
269 |
return @items; |
270 |
} |
271 |
|
272 |
sub create_thumbnails { |
273 |
my ($rrd,$dir,$hostname) = @_; |
274 |
my @thumbnail_options = (only_graph => '', width => 125, height => 32); |
275 |
create_graphs($rrd,$dir,$hostname,@thumbnail_options); |
276 |
} |
277 |
|
278 |
sub update_rrd { |
279 |
my ($rrd,$dir,$hostname) = @_; |
280 |
my $filename = shift @ARGV || undef; |
281 |
|
282 |
# Check out the input data |
283 |
die "Input data file '$filename' does not exist.\n" |
284 |
if defined $filename && !-f $filename; |
285 |
die "No data recieved while expecting STDIN data from rrd-client.pl.\n" |
286 |
if !$filename && !key_ready(); |
287 |
|
288 |
# Check the hostname is sane |
289 |
die "Hostname '$hostname' contains disallowed characters.\n" |
290 |
if $hostname =~ /[^\w\-\.\d]/ || $hostname =~ /^\.|\.$/; |
291 |
|
292 |
# Create the data directory for the RRD file if it doesn't exist |
293 |
File::Path::mkpath(catdir($dir->{data},$hostname)) unless -d catdir($dir->{data},$hostname); |
294 |
|
295 |
# Open the input file if specified |
296 |
if (defined $filename) { |
297 |
open(FH,'<',$filename) || die "[Error] $rrd: Unable to open file handle for file '$filename': $!"; |
298 |
select FH; |
299 |
}; |
300 |
|
301 |
# Parse the data |
302 |
my %data = (); |
303 |
while (local $_ = <>) { |
304 |
my ($path,$value) = split(/\s+/,$_); |
305 |
my ($time,@path) = split(/\./,$path); |
306 |
my $key = pop @path; |
307 |
|
308 |
# Check that none of the data is bogus or bollocks |
309 |
my $bogus = 0; |
310 |
$bogus++ unless $time =~ /^\d+$/; |
311 |
$bogus++ unless $value =~ /^[\d\.]+$/; |
312 |
for (@path) { |
313 |
$bogus++ unless /^[\w\-\_\.\d]+$/; |
314 |
} |
315 |
next if $bogus; |
316 |
|
317 |
my $rrdfile = catfile($dir->{data},$hostname,join('_',@path).'.rrd'); |
318 |
$data{$rrdfile}->{$time}->{$key} = $value; |
319 |
} |
320 |
|
321 |
# Process the data |
322 |
for my $rrdfile (sort keys %data) { |
323 |
for my $time (sort keys %{$data{$rrdfile}}) { |
324 |
eval { |
325 |
create_rrd($rrd,$dir,$rrdfile,$data{$rrdfile}->{$time}) |
326 |
unless -f $rrdfile; |
327 |
$rrd->update($rrdfile, $time, %{$data{$rrdfile}->{$time}}); |
328 |
}; |
329 |
warn "[Warning] $rrdfile: $@" if $@; |
330 |
} |
331 |
} |
332 |
|
333 |
# Close the input file if specified |
334 |
if (defined $filename) { |
335 |
select STDOUT; |
336 |
close(FH) || warn "[Warning] $rrd: Unable to close file handle for file '$filename': $!"; |
337 |
} |
338 |
|
339 |
return $hostname; |
340 |
} |
341 |
|
342 |
sub create_rrd { |
343 |
my ($rrd,$dir,$rrdfile,$data) = @_; |
344 |
my $defs = read_create_data(catfile($dir->{etc},'create.defs')); |
345 |
|
346 |
# Figure out what DS types to use |
347 |
my %create = map { ($_ => 'GAUGE') } sort keys %{$data}; |
348 |
while (my ($match,$def) = each %{$defs}) { |
349 |
next unless basename($rrdfile,qw(.rrd)) =~ /$match/; |
350 |
for my $ds (keys %create) { |
351 |
$create{$ds} = $def->{'*'}->{type} if defined $def->{'*'}->{type}; |
352 |
$create{$ds} = $def->{lc($ds)}->{type} if defined $def->{lc($ds)}->{type}; |
353 |
} |
354 |
} |
355 |
|
356 |
# Create the RRD file |
357 |
$rrd->create($rrdfile, %create); |
358 |
|
359 |
# Tune to use min and max values if specified |
360 |
while (my ($match,$def) = each %{$defs}) { |
361 |
next unless basename($rrdfile,qw(.rrd)) =~ /$match/; |
362 |
for my $ds ($rrd->sources($rrdfile)) { |
363 |
my $min = defined $def->{lc($ds)}->{min} ? $def->{lc($ds)}->{min} : |
364 |
defined $def->{'*'}->{min} ? $def->{'*'}->{min} : undef; |
365 |
RRDs::tune($rrdfile,'-i',"$ds:$min") if defined $min; |
366 |
|
367 |
my $max = defined $def->{lc($ds)}->{max} ? $def->{lc($ds)}->{max} : |
368 |
defined $def->{'*'}->{max} ? $def->{'*'}->{max} : undef; |
369 |
RRDs::tune($rrdfile,'-a',"$ds:$max") if defined $max; |
370 |
} |
371 |
} |
372 |
} |
373 |
|
374 |
sub HELP_MESSAGE { |
375 |
print qq{Syntax: rrd-server.pl <-u hostname,-g,-t,-V|-h|-v> [inputfile] |
376 |
-u <hostname> Update RRD data for <hostname> |
377 |
-g Create graphs from RRD data |
378 |
-t Create thumbnails from RRD data |
379 |
-V Display verbose progress information |
380 |
-v Display version information |
381 |
-h Display this help\n}; |
382 |
} |
383 |
|
384 |
# Display version |
385 |
sub VERSION { &VERSION_MESSAGE; } |
386 |
sub VERSION_MESSAGE { |
387 |
print "$0 version $VERSION ".'($Id: rrd-server.pl 1092 2008-01-23 14:23:51Z nicolaw $)'."\n"; |
388 |
} |
389 |
|
390 |
sub key_ready { |
391 |
my ($rin, $nfd) = ('',''); |
392 |
vec($rin, fileno(STDIN), 1) = 1; |
393 |
return $nfd = select($rin,undef,undef,3); |
394 |
} |
395 |
|
396 |
sub read_graph_data { |
397 |
my $filename = shift || undef; |
398 |
|
399 |
my %config = (); |
400 |
eval { |
401 |
my $conf = new Config::General( |
402 |
-ConfigFile => $filename, |
403 |
-LowerCaseNames => 1, |
404 |
-UseApacheInclude => 1, |
405 |
-IncludeRelative => 1, |
406 |
-MergeDuplicateBlocks => 1, |
407 |
-AllowMultiOptions => 1, |
408 |
-AutoTrue => 1, |
409 |
); |
410 |
%config = $conf->getall; |
411 |
}; |
412 |
warn "[Warning] $@" if $@; |
413 |
|
414 |
return \%config; |
415 |
} |
416 |
|
417 |
sub read_create_data { |
418 |
my $filename = shift || undef; |
419 |
my %defs = (); |
420 |
|
421 |
# Open the input file if specified |
422 |
my @data; |
423 |
if (defined $filename && -f $filename) { |
424 |
open(FH,'<',$filename) || die "Unable to open file handle for file '$filename': $!"; |
425 |
@data = <FH>; |
426 |
close(FH) || warn "Unable to close file handle for file '$filename': $!"; |
427 |
} else { |
428 |
@data = <DATA>; |
429 |
} |
430 |
|
431 |
# Parse the file that you've just selected |
432 |
for (@data) { |
433 |
last if /^__END__\s*$/; |
434 |
next if /^\s*$/ || /^\s*#/; |
435 |
|
436 |
my %def = (); |
437 |
@def{qw(rrdfile ds type min max)} = split(/\s+/,$_); |
438 |
next unless defined $def{ds}; |
439 |
$def{ds} = lc($def{ds}); |
440 |
$def{rrdfile} = qr($def{rrdfile}); |
441 |
for (keys %def) { |
442 |
if (!defined $def{$_} || $def{$_} eq '-') { |
443 |
delete $def{$_}; |
444 |
} elsif ($_ =~ /^(min|max)$/ && $def{$_} !~ /^[\d\.]+$/) { |
445 |
delete $def{$_}; |
446 |
} elsif ($_ eq 'type' && $def{$_} !~ /^(GAUGE|COUNTER|DERIVE|ABSOLUTE|COMPUTE)$/i) { |
447 |
delete $def{$_}; |
448 |
} |
449 |
} |
450 |
|
451 |
$defs{$def{rrdfile}}->{$def{ds}} = { |
452 |
map { ($_ => $def{$_}) } grep(!/^(rrdfile|ds)$/,keys %def) |
453 |
}; |
454 |
} |
455 |
|
456 |
return \%defs; |
457 |
} |
458 |
|
459 |
|
460 |
|
461 |
|
462 |
## |
463 |
## This processing and robustness of this routine is pretty |
464 |
## bloody dire and awful. It needs to be rewritten with crap |
465 |
## input data in mind rather than patching it every time I |
466 |
## find a new scenario for the data to not be as expected!! ;-) |
467 |
## |
468 |
|
469 |
sub write_txt { |
470 |
my %rtn = @_; |
471 |
while (my ($period,$data) = each %rtn) { |
472 |
my $filename = shift @{$data}; |
473 |
last if $filename =~ m,/thumbnails/,; |
474 |
|
475 |
my %values = (); |
476 |
my $max_len = 0; |
477 |
for (@{$data->[0]}) { |
478 |
my ($ds,$k,$v) = split(/\s+/,$_); |
479 |
next unless defined($ds) && length($ds) && defined($k); |
480 |
$values{$ds}->{$k} = $v; |
481 |
$max_len = length($ds) if length($ds) > $max_len; |
482 |
} |
483 |
|
484 |
if (open(FH,'>',"$filename.txt")) { |
485 |
printf FH "%s (%dx%d) %dK\n\n", |
486 |
basename($filename), |
487 |
(defined($data->[1]) ? $data->[1] : -1), |
488 |
(defined($data->[2]) ? $data->[2] : -1), |
489 |
(-e $filename ? (stat($filename))[7]/1024 : 0); |
490 |
|
491 |
for my $ds (sort keys %values) { |
492 |
for (qw(min max last)) { |
493 |
$values{$ds}->{$_} = '' |
494 |
unless defined $values{$ds}->{$_}; |
495 |
} |
496 |
printf FH "%-${max_len}s min: %s, max: %s, last: %s\n", $ds, |
497 |
$values{$ds}->{min}, $values{$ds}->{max}, $values{$ds}->{last}; |
498 |
} |
499 |
close(FH); |
500 |
} |
501 |
} |
502 |
} |
503 |
|
504 |
|
505 |
|
506 |
|
507 |
1; |
508 |
|
509 |
|
510 |
__DATA__ |
511 |
|
512 |
# * means all |
513 |
# - means undef/na |
514 |
|
515 |
# rrdfile ds type min max |
516 |
^net_traffic_.+ Transmit DERIVE 0 - |
517 |
^net_traffic_.+ Receive DERIVE 0 - |
518 |
|
519 |
# 10000000000 = 10 gigabit |
520 |
# 1000000000 = 1 gigabit |
521 |
# 100000000 = 100 megabit |
522 |
# rrdfile ds type min max |
523 |
^switch_traffic$ ifInOctets COUNTER 0 10000000000 |
524 |
^switch_traffic$ ifOutOctets COUNTER 0 10000000000 |
525 |
^switch_traffic_port\d+$ ifInOctets COUNTER 0 1000000000 |
526 |
^switch_traffic_port\d+$ ifOutOctets COUNTER 0 1000000000 |
527 |
|
528 |
# rrdfile ds type min max |
529 |
^hw_irq_interrupts_cpu\d+$ * DERIVE 0 - |
530 |
|
531 |
# rrdfile ds type min max |
532 |
^hdd_io_.+ * DERIVE 0 - |
533 |
|
534 |
# rrdfile ds type min max |
535 |
^net_nfs_operations$ * DERIVE 0 - |
536 |
|
537 |
# rrdfile ds type min max |
538 |
^apache_status$ ReqPerSec DERIVE 0 - |
539 |
^apache_status$ BytesPerSec DERIVE 0 - |
540 |
^apache_logs$ * DERIVE 0 - |
541 |
|
542 |
# rrdfile ds type min max |
543 |
^db_mysql_activity$ * DERIVE 0 - |
544 |
^db_mysql_activity_com$ * DERIVE 0 - |
545 |
^db_mysql_activity_scan$ * DERIVE 0 - |
546 |
^db_mysql_threads$ Threads_created DERIVE 0 - |
547 |
^db_mysql_traffic$ * DERIVE 0 - |
548 |
^db_mysql_connections$ * DERIVE 0 - |
549 |
^db_mysql_created_tmp$ * DERIVE 0 - |
550 |
|
551 |
# rrdfile ds type min max |
552 |
^mail_postfix_traffic$ * ABSOLUTE 0 - |
553 |
|
554 |
__END__ |
555 |
|
556 |
|