#!/usr/bin/perl -w #-d # # sar/iostat graphing tool based on rrdtool # (c) 2004 B. Cornec HP # Licensed under the GPL or Artistic License # # Common functions # package sario2rrd; use Exporter 'import'; @EXPORT_OK = qw(create_attr create_gauge update_gauge from_epoch); use strict; use English; # for $UID use RRDs; # for data management and graphing use Data::Dumper; # for debug use Date::Manip; # for timestamp # # Compute the number of fields to create in rrdtool # and the mini/maxi timestamp for the start/end (-s/-e option) # sub create_attr { my ($t,$attr,$m,$shot,$debug) = @_; # # Initialisation # if (not (defined $attr->{$m}{mintmst})) { $attr->{$m}{mintmst} = 99999999999999; } if (not (defined $attr->{$m}{maxtmst})) { $attr->{$m}{maxtmst} = 0; } foreach my $ts (keys %{$t}) { print "ts: $ts\n" if ($debug > 3); # # Compute the number of fields for the rrd base # and a good timestamp corresponding to the presence # of all the fields # my $nb = keys %{$t->{$ts}}; if ($nb > $attr->{$m}{nbfields}) { $attr->{$m}{nbfields} = $nb; $attr->{$m}{goodtmst} = $ts; } } # # List of all tags in rrd base # push @{$attr->{$m}{measures}},(sort keys %{$t->{$attr->{$m}{goodtmst}}}); foreach my $ts (keys %{$t}) { # # Compute the first/last timestamp # if ($shot == 1) { # # Fill empty parts of the hash in case of need for # fixed dates in extraction # foreach my $f (@{$attr->{$m}{measures}}) { $t->{$ts}{$f} = 0 if (not (defined $t->{$ts}{$f})); } } my $nb = keys %{$t->{$ts}}; if ($nb == $attr->{$m}{nbfields}) { $attr->{$m}{mintmst} = $ts if ($ts < $attr->{$m}{mintmst}); $attr->{$m}{maxtmst} = $ts if ($ts > $attr->{$m}{maxtmst}); } } # # Avoids boundaries problems during update # $attr->{$m}{mintmst}--; $attr->{$m}{maxtmst}++; print Dumper($attr) if ($debug > 1); }; # # Create the GAUGE entries in the rrd base # sub create_gauge { my ($t,$attr,$step,$rrd,$uid,$gid,$m,$debug) = @_; my @rrdc = (); foreach my $k (@{$attr->{$m}{measures}}) { my $step4 = $step*4; push @rrdc,"DS:$k:GAUGE:$step4:U:U"; } print "Creating rrd base $rrd for $m " if ($debug > 0); print "rrdc:\n",Dumper(@rrdc) if ($debug > 2); #my @rrdc2 = ("RRA:AVERAGE:0.5:1:4800","RRA:MAX:0.5:1:4800","RRA:MIN:0.5:1:4800"); my @rrdc2 = ("RRA:AVERAGE:0.5:1:4800","RRA:AVERAGE:0.5:6:4900","RRA:MAX:0.5:1:4800","RRA:MAX:0.5:6:4900","RRA:MIN:0.5:1:4800","RRA:MIN:0.5:6:700"); unlink $rrd; RRDs::create ("$rrd","-b $attr->{$m}{mintmst}","-s $step",@rrdc,@rrdc2); my $rrderror = RRDs::error; die "Problem while updating rrd: $rrderror\n" if ($rrderror); printf "(%d fields)\n",$attr->{$m}{nbfields} if ($debug > 0); printf "[ ",$attr->{$m}{nbfields} if ($debug > 0); foreach my $f (@{$attr->{$m}{measures}}) { print "$f " if ($debug > 0); } printf " ]\n",$attr->{$m}{nbfields} if ($debug > 0); chown $uid, $gid, "$rrd" || warn "Unable to chown $rrd to $uid" if ($UID == 0); }; # # Update the GAUGE entries in the rrd base # sub update_gauge { my ($t,$attr,$rrd,$m,$debug) = @_; print "Updating rrd base for $m\n" if ($debug > 0); foreach my $ts (sort keys %{$t}) { my $rrdu = ""; $rrdu .= "$ts"; foreach my $k (sort keys %{$t->{$ts}}) { $rrdu .= ":$t->{$ts}{$k}"; } # Depends on localisation $rrdu =~ s/,/./g; my $cnt = () = $rrdu =~ /:/g; if ($cnt != $attr->{$m}{nbfields}) { printf "Skiping update %s ... (%d fields)\n",substr($rrdu,0,15),$cnt if ($debug > 1); } else { printf "Updating with %s ... (%d fields)\n",substr($rrdu,0,15),$cnt if ($debug > 1); printf "rrdu: $rrdu\n" if ($debug > 2); RRDs::update("$rrd","$rrdu"); my $rrderror = RRDs::error; die "Problem while updating rrd: $rrderror\n" if ($rrderror); } } }; # # Print Date correctly from epoch sec # sub from_epoch { my ($t) = @_; return UnixDate(ParseDate("epoch $t"),"%Y-%m-%d %H:%M:%S"); }; 1;