statgraph/StatGraph.pm
2011-03-30 19:04:35 +01:00

781 lines
33 KiB
Perl
Executable file

use RRDs;
use strict;
# Takes array ref of statgrab output.
# Returns hash structure
sub sgparse ($) {
my $text = shift;
my %tree;
foreach (@$text) {
chomp;
m/^([^=]*) = (.*)$/ or die "bad line in statgrab output";
my @parts = split /\./, $1;
if ($#parts == 2) {
$tree{$parts[0]}{$parts[1]}{$parts[2]} = $2;
} else {
$tree{$parts[0]}{$parts[1]} = $2;
}
}
return %tree;
}
sub confparse ($) {
my $text = shift;
my %tree;
foreach (@$text) {
chomp;
next if (m/^#/);
next if (m/^$/);
m/^([^=]*) = (.*)$/ or die "bad line in config $_";
my @parts = split /\./, $1;
if ($#parts == 2) {
$tree{$parts[0]}{$parts[1]}{$parts[2]} = $2;
} else {
$tree{$parts[0]}{$parts[1]} = $2;
}
}
return %tree;
}
## Connect to remote host and retrieve statgrab results
sub get_net_results ($$$) {
use IO::Socket;
my ($remote_host, $remote_port, $cache) = @_;
my ($line, $response, $socket, $flag, @res);
$socket = IO::Socket::INET->new(PeerAddr => $remote_host,
PeerPort => $remote_port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port\n";
#while($line = <$socket>){
# push @res, $line;
#}
@res = (<$socket>);
my $results = join('', @res);
if ($results ne "") {
open CACHE, ">$cache";
print CACHE $results;
close CACHE;
} else {
die "No result from $remote_host";
}
return sgparse(\@res);
}
## Run command on local host to retrieve statgrab results
## Can be used to get local stats, or call ssh, or similar...
sub get_exec_results ($$) {
my $command = shift;
my $cache = shift;
open STATGRAB, "$command|" or warn "$command failed: $!";
my @res = (<STATGRAB>);
my $results = join('', @res);
if ($results ne "") {
open CACHE, ">$cache";
print CACHE $results;
close CACHE;
} else {
die "No result from $command";
}
return sgparse(\@res);
}
## Create RRDs where relevant
sub create_rrd ($$$$) {
my $rrdlocation = shift;
my $type = shift;
my $host = shift;
my $devname = shift;
use RRDs;
print " Creating RRD: $host $type $devname\n";
if ($type eq 'cpu') {
RRDs::create ("$rrdlocation$host.cpu.rrd",
"--step", "60",
"DS:idle:COUNTER:120:U:U",
"DS:iowait:COUNTER:120:U:U",
"DS:kernel:COUNTER:120:U:U",
"DS:nice:COUNTER:120:U:U",
"DS:swap:COUNTER:120:U:U",
"DS:total:COUNTER:120:U:U",
"DS:user:COUNTER:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'load') {
RRDs::create ("$rrdlocation$host.load.rrd",
"--step", "60",
"DS:min1:GAUGE:120:U:U",
"DS:min5:GAUGE:120:U:U",
"DS:min15:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'mem') {
RRDs::create ("$rrdlocation$host.mem.rrd",
"--step", "60",
"DS:cache:GAUGE:120:U:U",
"DS:free:GAUGE:120:U:U",
"DS:total:GAUGE:120:U:U",
"DS:used:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'page') {
RRDs::create ("$rrdlocation$host.page.rrd",
"--step", "60",
"DS:in:COUNTER:120:U:U",
"DS:out:COUNTER:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'proc') {
RRDs::create ("$rrdlocation$host.proc.rrd",
"--step", "60",
"DS:running:GAUGE:120:U:U",
"DS:sleeping:GAUGE:120:U:U",
"DS:stopped:GAUGE:120:U:U",
"DS:total:GAUGE:120:U:U",
"DS:zombie:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'user') {
RRDs::create ("$rrdlocation$host.user.rrd",
"--step", "60",
"DS:num:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'swap') {
RRDs::create ("$rrdlocation$host.swap.rrd",
"--step", "60",
"DS:free:GAUGE:120:U:U",
"DS:total:GAUGE:120:U:U",
"DS:used:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'disk') {
RRDs::create ("$rrdlocation$host.disk.$devname.rrd",
"--step", "60",
"DS:read_bytes:COUNTER:120:U:U",
"DS:write_bytes:COUNTER:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'net') {
RRDs::create ("$rrdlocation$host.net.$devname.rrd",
"--step", "60",
"DS:rx:COUNTER:120:U:U",
"DS:tx:COUNTER:120:U:U",
"DS:ipackets:COUNTER:120:U:U",
"DS:opackets:COUNTER:120:U:U",
"DS:ierrors:COUNTER:120:U:U",
"DS:oerrors:COUNTER:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
} elsif ($type eq 'fs') {
RRDs::create ("$rrdlocation$host.fs.$devname.rrd",
"--step", "60",
"DS:used:GAUGE:120:U:U",
"DS:size:GAUGE:120:U:U",
"DS:used_inodes:GAUGE:120:U:U",
"DS:total_inodes:GAUGE:120:U:U",
"RRA:AVERAGE:0.5:1:2160", # 1.5 days
"RRA:AVERAGE:0.5:15:1008", # 1.5 weeks
"RRA:AVERAGE:0.5:60:1008", # 6 weeks
"RRA:AVERAGE:0.5:720:1460", # 2 years
"RRA:MAX:0.5:1:2160", # 1.5 days
"RRA:MAX:0.5:15:1008", # 1.5 weeks
"RRA:MAX:0.5:60:1008", # 6 weeks
"RRA:MAX:0.5:720:1460"); # 2 years
}
}
sub update_rrd ($$) {
my $rrd = shift;
my $data = shift;
#print "$rrd, $data\n";
RRDs::update($rrd, $data);
my $ERR=RRDs::error;
print "ERROR while updating $rrd: $ERR\n" if $ERR;
}
sub create_graph ($$$$$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $type = shift;
my $host = shift;
my $devname = shift;
my $offsets = shift;
my $friendly = shift;
my $colours = shift;
my %colours = %$colours;
# Check colours
$colours{stack1} = '#FF0000' unless $colours{stack1};
$colours{stack2} = '#FFFF00' unless $colours{stack2};
$colours{stack3} = '#00FFFF' unless $colours{stack3};
$colours{stack4} = '#00FF00' unless $colours{stack4};
$colours{stack5} = '#0000FF' unless $colours{stack5};
$colours{load1} = '#CECFFF' unless $colours{load1};
$colours{load5} = '#7375FF' unless $colours{load5};
$colours{load15} = '#0000FF' unless $colours{load15};
$colours{area} = '#CECFFF' unless $colours{area};
$colours{line} = '#0000FF' unless $colours{line};
$colours{in} = '#00FF00' unless $colours{in};
$colours{out} = '#0000FF' unless $colours{out};
foreach my $offset (@$offsets) {
if ($type eq 'cpu') {
create_graph_cpu($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'load') {
create_graph_load($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'mem') {
create_graph_mem($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'page') {
create_graph_page($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'proc') {
create_graph_proc($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'user') {
create_graph_user($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'swap') {
create_graph_swap($rrdlocation, $location, $host, $offset, \%colours);
} elsif ($type eq 'disk') {
create_graph_disk($rrdlocation, $location, $host, $devname, $offset, \%colours);
} elsif ($type eq 'net') {
create_graph_net($rrdlocation, $location, $host, $devname, $offset, \%colours);
} elsif ($type eq 'fs') {
create_graph_fs($rrdlocation, $location, $host, $devname, $offset, $friendly, \%colours);
}
}
}
sub create_graph_cpu ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "cpu";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-t", "CPU usage for $host",
"--vertical-label", "% cpu used",
"DEF:idle=$rrdlocation$host.$type.rrd:idle:AVERAGE",
"DEF:iowait=$rrdlocation$host.$type.rrd:iowait:AVERAGE",
"DEF:kernel=$rrdlocation$host.$type.rrd:kernel:AVERAGE",
"DEF:nice=$rrdlocation$host.$type.rrd:nice:AVERAGE",
"DEF:swap=$rrdlocation$host.$type.rrd:swap:AVERAGE",
"DEF:user=$rrdlocation$host.$type.rrd:user:AVERAGE",
"AREA:kernel$colours{stack1}:kernel cpu",
"GPRINT:kernel:LAST:Current\\: \%8.2lf %s",
"GPRINT:kernel:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:kernel:MAX:Max\\: \%8.2lf %s\\n",
"STACK:swap$colours{stack2}:swap cpu ",
"GPRINT:swap:LAST:Current\\: \%8.2lf %s",
"GPRINT:swap:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:swap:MAX:Max\\: \%8.2lf %s\\n",
"STACK:iowait$colours{stack3}:iowait cpu",
"GPRINT:iowait:LAST:Current\\: \%8.2lf %s",
"GPRINT:iowait:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:iowait:MAX:Max\\: \%8.2lf %s\\n",
"STACK:nice$colours{stack4}:nice cpu ",
"GPRINT:nice:LAST:Current\\: \%8.2lf %s",
"GPRINT:nice:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:nice:MAX:Max\\: \%8.2lf %s\\n",
"STACK:user$colours{stack5}:user cpu ",
"GPRINT:user:LAST:Current\\: \%8.2lf %s",
"GPRINT:user:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:user:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_load ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "load";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",
"-u", "1",
"-a", "PNG",
"-t", "load averages for $host",
"--units-exponent", "1",
"--vertical-label", "processes in run queue",
"DEF:load1=$rrdlocation$host.$type.rrd:min1:AVERAGE",
"DEF:load5=$rrdlocation$host.$type.rrd:min5:AVERAGE",
"DEF:load15=$rrdlocation$host.$type.rrd:min15:AVERAGE",
"LINE2:load1$colours{load1}:1 minute load ",
"GPRINT:load1:LAST:Current\\: \%8.2lf %s",
"GPRINT:load1:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:load1:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:load5$colours{load5}:5 minute load ",
"GPRINT:load5:LAST:Current\\: \%8.2lf %s",
"GPRINT:load5:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:load5:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:load15$colours{load15}:15 minute load",
"GPRINT:load15:LAST:Current\\: \%8.2lf %s",
"GPRINT:load15:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:load15:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_mem ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "mem";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-u", "100",
"-t", "memory usage for $host",
"--base", "1024",
"--vertical-label", "% memory used",
"DEF:free=$rrdlocation$host.$type.rrd:free:AVERAGE",
"DEF:cache=$rrdlocation$host.$type.rrd:cache:AVERAGE",
"DEF:used=$rrdlocation$host.$type.rrd:used:AVERAGE",
"DEF:total=$rrdlocation$host.$type.rrd:total:AVERAGE",
"CDEF:peruse=total,free,total,LT,free,0,IF,-,total,/,100,*",
"CDEF:percacuse=cache,total,LT,cache,0,IF,total,/,100,*",
"AREA:peruse$colours{area}:Used ",
"GPRINT:peruse:LAST:Current\\: \%8.2lf %s",
"GPRINT:peruse:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:peruse:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:percacuse$colours{line}:Cache",
"GPRINT:percacuse:LAST:Current\\: \%8.2lf %s",
"GPRINT:percacuse:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:percacuse:MAX:Max\\: \%8.2lf %s\\n",
"GPRINT:total:LAST:Current total memory\\: \%.2lf %sb\\c");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_proc ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "proc";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",,
"-a", "PNG",
"-t", "processes on $host",
"--units-exponent", "1",
"--vertical-label", "num of processes",
"DEF:running=$rrdlocation$host.$type.rrd:running:AVERAGE",
"DEF:sleeping=$rrdlocation$host.$type.rrd:sleeping:AVERAGE",
"DEF:stopped=$rrdlocation$host.$type.rrd:stopped:AVERAGE",
"DEF:zombie=$rrdlocation$host.$type.rrd:zombie:AVERAGE",
"AREA:stopped$colours{stack1}:stopped processes ",
"GPRINT:stopped:LAST:Current\\: \%8.2lf %s",
"GPRINT:stopped:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:stopped:MAX:Max\\: \%8.2lf %s\\n",
"STACK:zombie$colours{stack2}:zombie processes ",
"GPRINT:zombie:LAST:Current\\: \%8.2lf %s",
"GPRINT:zombie:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:zombie:MAX:Max\\: \%8.2lf %s\\n",
"STACK:sleeping$colours{stack3}:sleeping processes",
"GPRINT:sleeping:LAST:Current\\: \%8.2lf %s",
"GPRINT:sleeping:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:sleeping:MAX:Max\\: \%8.2lf %s\\n",
"STACK:running$colours{stack4}:running processes ",
"GPRINT:running:LAST:Current\\: \%8.2lf %s",
"GPRINT:running:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:running:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_page ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "page";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",,
"-a", "PNG",
"-t", "paging activity on $host",
"--units-exponent", "1",
"--vertical-label", "pages/second",
"DEF:in=$rrdlocation$host.$type.rrd:in:AVERAGE",
"DEF:out=$rrdlocation$host.$type.rrd:out:AVERAGE",
"AREA:in$colours{in}:pages in ",
"GPRINT:in:LAST:Current\\: \%8.2lf %s",
"GPRINT:in:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:in:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:out$colours{out}:pages out",
"GPRINT:out:LAST:Current\\: \%8.2lf %s",
"GPRINT:out:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:out:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_user ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "user";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",
"-u", "1",
"-a", "PNG",
"-t", "users on $host",
"--units-exponent", "1",
"--vertical-label", "users logged in",
"DEF:num=$rrdlocation$host.$type.rrd:num:AVERAGE",
"LINE2:num$colours{line}:Logged in users",
"GPRINT:num:LAST:Current\\: \%8.2lf %s",
"GPRINT:num:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:num:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_swap ($$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "swap";
RRDs::graph ("$location$host.$type.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-u", "100",
"-t", "swap use on $host",
"--base", "1024",
"--vertical-label", "% swap used",
"DEF:free=$rrdlocation$host.$type.rrd:free:AVERAGE",
"DEF:used=$rrdlocation$host.$type.rrd:used:AVERAGE",
"DEF:total=$rrdlocation$host.$type.rrd:total:AVERAGE",
"CDEF:peruse=total,free,total,LT,free,0,IF,-,total,/,100,*",
"AREA:peruse$colours{area}:Used",
"GPRINT:peruse:LAST:Current\\: \%8.2lf %s",
"GPRINT:peruse:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:peruse:MAX:Max\\: \%8.2lf %s\\n",
"GPRINT:total:LAST:Current total swap\\: \%.2lf %sb\\c");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_disk ($$$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $dev = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "disk";
RRDs::graph ("$location$host.$type.$dev.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-t", "disk io on $host for $dev",
"--base", "1024",
"--vertical-label", "bytes per second",
"DEF:read_bytes=$rrdlocation$host.$type.$dev.rrd:read_bytes:AVERAGE",
"DEF:write_bytes=$rrdlocation$host.$type.$dev.rrd:write_bytes:AVERAGE",
"AREA:read_bytes$colours{in}:read bytes ",
"GPRINT:read_bytes:LAST:Current\\: \%8.2lf %s",
"GPRINT:read_bytes:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:read_bytes:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:write_bytes$colours{out}:write bytes",
"GPRINT:write_bytes:LAST:Current\\: \%8.2lf %s",
"GPRINT:write_bytes:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:write_bytes:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_net ($$$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $dev = shift;
my $offset = shift;
my $colours = shift;
my %colours = %{$colours};
my $type = "net";
RRDs::graph ("$location$host.$type.$dev.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-t", "network io on $host for $dev",
"--base", "1024",
"--vertical-label", "bytes per second",
"DEF:rx=$rrdlocation$host.$type.$dev.rrd:rx:AVERAGE",
"DEF:tx=$rrdlocation$host.$type.$dev.rrd:tx:AVERAGE",
"AREA:rx$colours{in}:recieved bytes ",
"GPRINT:rx:LAST:Current\\: \%8.2lf %s",
"GPRINT:rx:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:rx:MAX:Max\\: \%8.2lf %s\\n",
"LINE2:tx$colours{out}:transmitted bytes",
"GPRINT:tx:LAST:Current\\: \%8.2lf %s",
"GPRINT:tx:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:tx:MAX:Max\\: \%8.2lf %s\\n");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub create_graph_fs ($$$$$$$) {
my $rrdlocation = shift;
my $location = shift;
my $host = shift;
my $dev = shift;
my $offset = shift;
my $mountpoint = shift || $dev;
my $colours = shift;
my %colours = %{$colours};
my $type = "fs";
$dev =~ s/:/\\:/g;
RRDs::graph ("$location$host.$type.$dev.$offset.png",
"--start", "-$offset",
"-l", "0",
"-a", "PNG",
"-u", "100",
"-t", "disk usage on $host for $mountpoint",
"--base", "1024",
"--vertical-label", "% used",
"DEF:used=$rrdlocation$host.$type.$dev.rrd:used:AVERAGE",
"DEF:size=$rrdlocation$host.$type.$dev.rrd:size:AVERAGE",
"DEF:used_inodes=$rrdlocation$host.$type.$dev.rrd:used_inodes:AVERAGE",
"DEF:total_inodes=$rrdlocation$host.$type.$dev.rrd:total_inodes:AVERAGE",
"CDEF:peruse=used,size,/,100,*",
"CDEF:perinode=used_inodes,total_inodes,/,100,*",
"AREA:peruse$colours{area}:space used ",
"GPRINT:peruse:LAST:Current\\: \%8.2lf %s",
"GPRINT:peruse:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:peruse:MAX:Max\\: \%8.2lf %s\\n",
"GPRINT:size:LAST:Current total space\\: \%.2lf %sb\\c",
"LINE2:perinode$colours{line}:inodes used",
"GPRINT:perinode:LAST:Current\\: \%8.2lf %s",
"GPRINT:perinode:AVERAGE:Average\\: \%8.2lf %s",
"GPRINT:perinode:MAX:Max\\: \%8.2lf %s\\n",
"GPRINT:total_inodes:LAST:Current total inodes\\: \%.2lf %s\\c");
my $ERR=RRDs::error;
die "ERROR : $ERR\n" if $ERR;
}
sub htmlheader ($) {
my $title = shift;
return "<html><head><meta http-equiv='refresh' content='60'>
<title>$title</title></head>
<body>";
}
sub htmlfooter () {
return "<p><img src='sg-p-small.png' alt='Powered by StatGraph' /></p>
</body></html>";
}
sub create_page ($$$$$) {
my $location = shift;
my $type = shift;
my $host = shift;
my $devname = shift;
my $offsets = shift;
# print " Creating graphs: $host $type $devname\n";
my %nicenames = (
'cpu' => "CPU utilisation for $host",
'load' => "Load averages for $host",
'mem' => "Memory usage for $host",
'page' => "Paging activity for $host",
'proc' => "Processes for $host",
'user' => "User activity for $host",
'swap' => "Swap usage for $host",
'disk' => "Disk IO for $host on $devname",
'net' => "Network IO for $host on $devname",
'fs' => "Filsystem Utilisation for $host on $devname");
my $dev = "";
$dev = ".$devname" if ($devname ne "");
open OUT, ">$location$host-$type$dev.html";
print OUT htmlheader("$nicenames{$type}");
print OUT "<h1>$nicenames{$type}</h1>\n";
print OUT "<p>Last updated: " . nice_date();
foreach my $offset (@$offsets) {
print OUT "<h2>" . nice_time($offset). "</h2><img src='$host.$type$dev.$offset.png'><br />\n";
}
close OUT;
}
sub nice_time ($) {
my $seconds = shift;
my $minute = '60';
my $hour = '3600';
my $day = 24 * $hour;
my $week = 7 * $day;
my $month = 4 * $week;
my $year = 365 * $day;
my @stack;
my $tmp = int($seconds / $year);
if ($tmp > 0) {
push @stack, "$tmp years";
$seconds = $seconds % $year;
}
$tmp = int($seconds / $month);
if ($tmp > 0) {
push @stack, "$tmp months";
$seconds = $seconds % $month;
}
$tmp = int($seconds / $week);
if ($tmp > 0) {
push @stack, "$tmp weeks";
$seconds = $seconds % $week;
}
$tmp = int($seconds / $day);
if ($tmp > 0) {
push @stack, "$tmp days";
$seconds = $seconds % $day;
}
$tmp = int($seconds / $hour);
if ($tmp > 0) {
push @stack, "$tmp hours";
$seconds = $seconds % $hour;
}
$tmp = int($seconds / $minute);
if ($tmp > 0) {
push @stack, "$tmp minutes";
$seconds = $seconds % $minute;
}
push (@stack, "$seconds seconds") if ($seconds > 0);
return join (", ", @stack);
}
sub nice_date () {
my ($seconds, $minutes, $hours, $day_of_month, $month, $year, $wday, $yday, $isdst) = localtime(time);
return sprintf("%02d:%02d:%02d-%04d/%02d/%02d\n", $hours, $minutes, $seconds, $year+1900, $month+1, $day_of_month);
}
1;