#!/usr/bin/perl -w #-d # # sar/iostat graphing tool based on rrdtool # (c) 2004 B. Cornec HP # Licensed under the GPL or Artistic License # # Original Charter: Monitor CPU/Load/Net_eth0|2 (io/s)/Disk (io/s) # 1 mesure par 20 seconde # So the script has been developped first with that context in mind # trying to be generic enough to be expandable later on # More work needs to be done, some code factorized, ... # # use strict; # Always :-) use RRDs; # for data management and graphing use Data::Dumper; # for debug use HTML::AsSubs; # for HTML generation use Storable; # for data exchange use Date::Manip; # for timestamp use Config::Auto; # for config file use sario2rrd qw(from_epoch); # local common functions # Avoid localisation problems in sar $ENV{LANG}="C"; # # Begin of configuration options # my $dir = "sar2rrd"; # Place under the html dir of user apache # Under that directory you should have one # directory per machine and in it all the # files resulting form the sar and iostat # commands (saxx and ioxx). Look at the # cron file and related script my ($l,$p,$uid,$gid,$q,$c,$gc,$apache,$empty) = getpwnam("apache") or die "apache not in passwd file"; my $base = "$apache/html/$dir"; my $config = Config::Auto::parse("$base/$dir.conf"); my @machines = @{$config->{machines}}; my @shots = @{$config->{shots}}; my $lgshot = $config->{lgshot}; my $debug = 0; foreach my $a (@ARGV) { $debug++ if ($a =~ /-v/); $| = 1; # Flush STDOUT } my $m; my %t; my %attrio = %{ retrieve("$base/$config->{svgio}") }; my %attrsar = %{ retrieve("$base/$config->{svgsar}") }; my $h = "$base/dgi.html"; open (MAIN, "> $h") || die "Unable to create $h : $!"; my @hm = (h1("sar2rrd - sar/iostats monitoring via rrdtool"), p("List of systems to monitor:")); my @index; my @tmp1; my @tmp2; print Dumper($config) if ($debug > 1); foreach $m (@machines) { # # The graphs/HTML generation # push @index,li(a({href=>"$m/dgi.html"}, "$m")); my $hm = "$base/$m/dgi.html"; open (MACHINE, "> $hm") || die "Unable to create $hm : $!"; my @hhm = (h1("sar2rrd - Monitoring $m")); my $img="$base/$m/img"; print "Graphing rrd base for $m under $img\n" if ($debug > 0); my $cpt = 1; foreach my $t (@shots) { @tmp1 = (); @tmp2 = (); my $ht = "$base/$m/tir-$cpt.html"; open (TIR, "> $ht") || die "Unable to create $ht : $!"; my @hht = (h1("sar2rrd - Monitoring $m - Shot $cpt")); my $sdt = UnixDate($t,"%s"); my $edt = $sdt + $lgshot; my $sdtiso = from_epoch($sdt); my $edtiso = from_epoch($edt); printf "Shot #$cpt - Machine $m (Between $sdt/$sdtiso et $edt/$edtiso)\n" if ($debug > 0); print "Generating " if ($debug > 0); mkdir "$img",0755 if (not (-d "$img")); unlink <$img/*-tir$cpt.png>; print "mem-tir$cpt.png " if ($debug > 0); RRDs::graph("$img/mem-tir$cpt.png","-s $sdt","-e $edt","-v KiloBytes","-aPNG","-t Memory Report - $m","DEF:s1=$base/$m/$config->{rrdsar}:memoryfree:AVERAGE","AREA:s1#00ee22:Free Memory"); my $rrderror = RRDs::error; die "Problem while generating graph: $rrderror\n" if ($rrderror); print "load-tir$cpt.png " if ($debug > 0); RRDs::graph("$img/load-tir$cpt.png","-s $sdt","-e $edt","-S",$config->{step},"-aPNG","-t","Load Report - $m","DEF:s1=$base/$m/$config->{rrdsar}:load1:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:load5:AVERAGE","DEF:s3=$base/$m/$config->{rrdsar}:runq:AVERAGE","LINE2:s1#00b6e4:Load 1m","LINE2:s2#00ee22:Load 5m","LINE2:s3#ff0000:Run Queue"); $rrderror = RRDs::error; die "Problem while generating graph: $rrderror\n" if ($rrderror); push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/mem-tir$cpt.png"})); push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/load-tir$cpt.png"})); push @tmp1,HTML::AsSubs::tr(@tmp1); my $col = 0; foreach my $i (@{$attrsar{$m}{measures}},@{$attrio{$m}{measures}}) { if ($i =~ /^eth/) { $i =~ s/-[inout]+//; next if (-f "$img/$i-tir$cpt.png"); print "$i-tir$cpt.png " if ($debug > 0); RRDs::graph("$img/$i-tir$cpt.png","-s",$sdt,"-e",$edt,"-v packets/s","-S",$config->{step},"-aPNG","-t","Network Report $i - $m","DEF:s1=$base/$m/$config->{rrdsar}:$i-in:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:$i-out:AVERAGE","LINE2:s1#ff0000:$i (in)","LINE2:s2#00ee22:$i (out)"); push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i-tir$cpt.png"})); $col++; if ($col == 2) { push @tmp1,HTML::AsSubs::tr(@tmp2); @tmp2 = (); $col = 0; } } if (($i =~ /^sd/) || ($i =~ /^hd/) || ($i =~ /^cciss/)) { $i =~ s/-[inout]+//; next if (-f "$img/$i-tir$cpt.png"); print "$i-tir$cpt.png " if ($debug > 0); RRDs::graph("$img/$i-tir$cpt.png","-s",$sdt,"-e",$edt,"-v Op/s","-S",$config->{step},"-aPNG","-t","Disk Report $i - $m","DEF:s1=$base/$m/$config->{rrdio}:$i-in:AVERAGE","DEF:s2=$base/$m/$config->{rrdio}:$i-out:AVERAGE","LINE2:s1#ff0000:$i (in)","LINE2:s2#00ee22:$i (out)"); push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i-tir$cpt.png"})); $col++; if ($col == 2) { push @tmp1,HTML::AsSubs::tr(@tmp2); @tmp2 = (); $col = 0; } } if (($i =~ /^cpu/) || ($i =~ /^all/)) { $i =~ s/-[a-z]+//; next if (-f "$img/$i-tir$cpt.png"); print "$i-tir$cpt.png " if ($debug > 0); RRDs::graph("$img/$i-tir$cpt.png","-s",$sdt,"-e",$edt,"-S",$config->{step},"-aPNG","-t","CPU Report $i - $m","DEF:s1=$base/$m/$config->{rrdsar}:$i-idle:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:$i-nice:AVERAGE","DEF:s3=$base/$m/$config->{rrdsar}:$i-system:AVERAGE","DEF:s4=$base/$m/$config->{rrdsar}:$i-user:AVERAGE","AREA:s1#00b6e4:$i (idle)","STACK:s2#00ee22:$i (nice)","STACK:s3#ff0000:$i (system)","STACK:s4#000000:$i (user)"); push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i-tir$cpt.png"})); $col++; if ($col == 2) { push @tmp1,HTML::AsSubs::tr(@tmp2); @tmp2 = (); $col = 0; } } } $rrderror = RRDs::error; die "Problem while generating graph: $rrderror\n" if ($rrderror); print "\n" if ($debug > 0); push @hht,table(@tmp1); my $hht = body(@hht); print TIR $hht->as_HTML; close(TIR); push @hhm,li(a({href=>"tir-$cpt.html"}, "Tir $cpt")); $cpt++; } my $hhm = body(@hhm); print MACHINE $hhm->as_HTML; close(MACHINE); } push @hm,ul(@index); my $hm = body(@hm); print MAIN $hm->as_HTML; close MAIN; print "Point your browser to $config->{http}/$dir/dgi.html\n" if ($debug > 0); # # Second pass # $h = "$base/dgi-tirs.html"; open (MAIN, "> $h") || die "Unable to create $h : $!"; @hm = (h1("sar2rrd - sar/iostats monitoring via rrdtool"), p("List of shots:")); @index = (); my $cpt = 1; my %attrs; foreach $m (@machines) { foreach my $attr (@{$attrsar{$m}{measures}},@{$attrio{$m}{measures}}) { next if ($attr =~ /^load/); next if ($attr =~ /^runq/); $attr = "mem" if ($attr =~ /^memory/); $attr = "load" if ($attr =~ /^plist/); $attrs{$attr}++; } } foreach my $t (@shots) { # # The graphs/HTML generation # push @index,li(a({href=>"dgi-tir-$cpt.html"}, "Tir $cpt")); my $hm = "$base/dgi-tir-$cpt.html"; open (SHOT, "> $hm") || die "Unable to create $hm : $!"; my @hhm = (h1("sar2rrd - Monitoring Shots")); print "Graphing rrd base for Shot $cpt\n" if ($debug > 0); foreach my $i (sort keys %attrs) { @tmp1 = (); @tmp2 = (); my $ht = "$base/attr-$cpt-$i.html"; open (ATTR, "> $ht") || die "Unable to create $ht : $!"; my @hht = (h1("sar2rrd - Monitoring $i - Tir $cpt")); my $col = 0; foreach $m (@machines) { my $img="$base/$m/img"; #push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/load-tir$cpt.png"})); #push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/load-tir$cpt.png"})); #push @tmp1,HTML::AsSubs::tr(@tmp1); push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i-tir$cpt.png"})); $col++; if ($col == 2) { push @tmp1,HTML::AsSubs::tr(@tmp2); @tmp2 = (); $col = 0; } } push @hht,table(@tmp1); my $hht = body(@hht); print ATTR $hht->as_HTML; close(ATTR); push @hhm,li(a({href=>"attr-$cpt-$i.html"}, "$i")); } my $hhm = body(@hhm); print SHOT $hhm->as_HTML; close(SHOT); $cpt++; } push @hm,ul(@index); $hm = body(@hm); print MAIN $hm->as_HTML; close MAIN; print "Point your browser to $config->{http}/$dir/dgi-tirs.html\n" if ($debug > 0);