########################################## ## ## DESCRIPTION ## ## RRD function for tc-graph. ## Which is part of the ADSL-optimizer. ## ## REQUIRES ## ## ## AUTHOR ## Jesper Dangaard Brouer , d.15/4-2004 ## ## CHANGELOG ## 2004-04-15: Initial version. ## ## $Id: RRD-func.pl,v 1.10 2004/05/27 17:02:12 hawk Exp $ ########################################## use RRDs; if (not defined $rrd_datadir) { our $rrd_datadir = "/var/spool/rrdqueues/"; } if (not defined $STEP) { my $STEP=10; } my $heartbeat=$STEP*2; # Update script samples every 10 seconds. # 24*60*60 = 86400 seconds (== one day) # 8640 *10 = 86400 seconds (== one day) # 8640 * 5days = 43200 seconds with 10 sec samples # my @rrd_data_sources = ("-s", $STEP, "DS:bytes:COUNTER:$heartbeat:0:U", "DS:bits:COUNTER:$heartbeat:0:U", "DS:pkts:COUNTER:$heartbeat:0:U", "DS:dropped:COUNTER:$heartbeat:0:U", "DS:overlimits:COUNTER:$heartbeat:0:U", "DS:lended:COUNTER:$heartbeat:0:U", "DS:borrowed:COUNTER:$heartbeat:0:U", "DS:giants:COUNTER:$heartbeat:0:U", "DS:backlog:GAUGE:$heartbeat:0:U", "RRA:AVERAGE:0.5:1:43200", "RRA:AVERAGE:0.5:7:8640", "RRA:AVERAGE:0.5:31:8640", "RRA:AVERAGE:0.5:372:8640", "RRA:MAX:0.5:7:8640", "RRA:MAX:0.5:31:8640", "RRA:MAX:0.5:372:8640" ); sub get_filename_rrd($) { my $class_device = "$_[0]"; my $filename = "${rrd_datadir}class_${class_device}.rrd"; return $filename; } sub create_rrdfile($) { my $class_device = "$_[0]"; my $filename = get_filename_rrd($class_device); RRDs::create $filename, @rrd_data_sources; my $ERROR = RRDs::error; if ($ERROR) { my $timestamp = time; die "$timestamp: ERROR - Unable to create RRDfile \"$filename\": $ERROR\n"; } } sub format_class_data($) { my $class = $_[0]; my ($rrd_template, $rrd_data); my (@array_template, @array_data); #print "Ref:". ref($class) ."\n"; # Select and correct undef values and key while ( (my $key, my $value) = each %{$class}) { # Skip timestamps if ( ($key eq "last_update") || ($key eq "file_update") || ($key =~ /hfsc_/ )) {next} push @array_template, $key; if ( (not defined $value) || ("$value" eq "") ) { $value = "U"; } push @array_data, $value; } # Makes a RRD suitable input format $rrd_template = join(":",@array_template); $rrd_data = join(":",@array_data); return ($rrd_template, $rrd_data); } sub update_rrds { my $res=0; my @test = keys %classes_data; if ( $#test <= 0) { print time, " [update_rrds] WARNING: classes_data empty!\n"; return "classes_data empty"; } # Find the class_device (keys) in %classes_data for my $class_device ( keys %classes_data ) { if ("last_update" eq "$class_device") {next} # Verify file exist (else create it) my $filename = get_filename_rrd($class_device); if ( ! -f $filename ) { print "Creating RRDfile: $filename\n"; create_rrdfile($class_device); } #print "$class_device\n"; # Make a RRD suitable input format my ($rrd_template, $rrd_data) = format_class_data($classes_data{$class_device}); #print "rrd_template: $rrd_template\n"; #print "rrd_data: $rrd_data\n"; # WHAT ABOUT: # $classes_data{$device}{last_update} ???? my ($tmp, $device) = split /_/, $class_device; #print "device: $device $classes_data{last_update}{$device} \n"; if ( (exists $classes_data{last_update}{$device}) ) { if ((($classes_data{$class_device}{last_update} + $heartbeat) < $classes_data{last_update}{$device})) { print "WARNING: the class $class_device was"; print "not updated in lastrun + heartbeat...\n"; print "Assuming $class_device is removed,"; print " thus deleteing from hash table."; # # ??? MAYBE DELETE THE OLD HASH ??? $res="Deleting class $class_device"; for my $key ( keys %{ $classes_data{$class_device} } ) { delete( $classes_data{$class_device}{$key}); print " Deleting key: $key from: $class_device \n"; } delete $classes_data{$class_device}; next; } } # Verifies that it is new data, # and not old data which already have been updated # FIXME # print "$0 FIXME update_rrds \n"; if ( exists $classes_data{$class_device}{file_update} ) { if (($classes_data{$class_device}{file_update} >= $classes_data{$class_device}{last_update})) { print "Warning ($class_device):"; print " data already updated... old data or deleted class?\n"; $res="Old data or deleted class"; # ??? MAYBE DELETE THE OLD HASH ??? next; } } # Update the RRD file my $update_time = $classes_data{$class_device}{last_update}; # print "Updates: $filename time:$update_time\n"; # print " --template=$rrd_template\n"; # print " $update_time:$rrd_data\n"; # `rrdtool update $filename --template=$rrd_template $update_time:$rrd_data`; RRDs::update ($filename, "--template=$rrd_template", "N:$rrd_data"); my $ERROR = RRDs::error; if ($ERROR) { my $timestamp = time; print "$timestamp: WARNING - "; print "Unable to update RRDfile \"$filename\": $ERROR\n"; $res="Unable to update RRDfile \"$filename\""; } else { $classes_data{$class_device}{file_update} = time; } } return $res; } return 1;