#!/usr/bin/perl # # IOG v1.0 - Input/Output Grapher # Copyright (c) 2000-2002 James Dogopoulos # # Please read the "Artistic" license included. # # E-mail iog@dynw.com with any bug reports, # fixes or comments. # BEGIN{ if ($ARGV[0] eq "NT") { $main::OS = 'NT'; } else { $main::OS = 'UNIX'; } $main::SL = { UNIX=>'/', NT=>'\\' }->{$main::OS}; $main::PS = { UNIX=>':', NT=>';' }->{$main::OS}; $main::binpath =""; if ($0 =~ /^(.+\Q${main::SL}\E)/) { $main::binpath="$1"; } else { foreach $pathname ( split ${main::PS}, $ENV{'PATH'}) { if ((($main::OS eq 'NT') && (-e "$pathname${main::SL}$0")) || (-x "$pathname${main::SL}$0")) { $main::binpath=$pathname; last; } } } unshift (@INC,$main::binpath); } use SDBM_File; use BER; use SNMP_Session; use Fcntl; my($inoid,$outoid,$host,$community,$snmpget,$datafile,$cfgfile,%inf); my($inoctets,$outoctets,$path,$iogver,$hostreset,$kbsize,$mbsize,$gbsize); $cfgfile="/etc/iog.cfg"; $iogver="v1.0"; # Default Byte Sizes $kbsize="1024"; $mbsize="1048576"; $gbsize="1073"; # Date/Time stuff # my @weekdays = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); my @months = qw(January February March April May June July August September October November December); my %days = (1 => "1st", 2 => "2nd", 3 => "3rd", 21 => "21st", 22 => "22nd", 23 => "23rd", 31 => "31st"); my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $lday = $mday - 1; sub last_mday { my ($month, $year) = @_; ( qw(31 0 31 30 31 30 31 31 30 31 30 31) )[$month] || 28 + (($year % 100 && !($year % 4))|| !($year % 400)); } if ($days{$mday}) { $pday = $days{$mday}; $nday = $days{$lday}; } else { $pday = $mday."th"; $nday = $lday."th"; } # Read config file. # open(CONFIG,$cfgfile) || die("Cannot open $cfgfile!"); while () { s/\s+$//g; # remove whitespace at the end of the line s/\s/ /g; # replace whitespace by space next if /^\s*\#/; # ignore comment lines next if /^\s*$/; # ignore empty lines if ($_ =~ /\[.*.\]/) { chkuptime($_); next; } my($name,$host,$community,$inoid,$outoid,$path) = split(/:/, $_); $path =~ s/\n//; $datafile = "$name".".dat"; my @results = snmpget2($host,$community,$inoid,$outoid); next if ($results[0] eq "error"); $inoctets = $results[0]; $outoctets = $results[1]; main($name,$host,$community,$inoid,$outoid,$path,$datafile); } close(CONFIG); # SNMP Get routine. Thanks to Simon Leinen for the SNMP module. # http://www.switch.ch/misc/leinen/snmp/perl/ # sub snmpget { my($host, $community, $inoid, $outoid) = @_; my($response, $bindings, $binding, $value, $oid, $session, @results); my %oidnames = qw(ifInOctets 1.3.6.1.2.1.2.2.1.10 ifOutOctets 1.3.6.1.2.1.2.2.1.16 ifHCInOctets 1.3.6.1.2.1.31.1.1.1.6 ifHCOutOctets 1.3.6.1.2.1.31.1.1.1.10); my ($inoidname,$inoidport) = split(/\./, $inoid); my ($outoidname,$outoidport) = split(/\./, $outoid); $inoid = encode_oid(split(/\./, ($oidnames{$inoidname} . ".$inoidport"))); $outoid = encode_oid(split(/\./, ($oidnames{$outoidname} . ".$outoidport"))); my @oids = ($inoid,$outoid); if ($inoidname =~ /HC/i or $outoidname =~ /HC/i) { $session = SNMPv2c_Session->open($host, $community, 161) or return "error"; } else { $session = SNMP_Session->open($host, $community, 161) or return "error"; }; if ($session->get_request_response (@oids)) { $response = $session->pdu_buffer; ($bindings) = $session->decode_get_response ($response); while ($bindings ne '') { ($binding,$bindings) = decode_sequence ($bindings); ($oid,$value) = decode_by_template ($binding, "%O%@"); push (@results, pretty_print($value)); } return @results; } else { warn "SNMP Error: $SNMP_Session::errmsg\n"; return "error"; } } sub snmpgetup { my($host, $community, $inoid) = @_; my($response, $bindings, $binding, $value, $oid, $result); my %oidnames = qw(sysUpTime 1.3.6.1.2.1.1.3 sysUpTime.0 1.3.6.1.2.1.1.3.0); $inoid = encode_oid(split(/\./, $oidnames{$inoid})); my $session = SNMP_Session->open($host, $community, 161) or return "0"; if ($session->get_request_response ($inoid)) { $response = $session->pdu_buffer; ($bindings) = $session->decode_get_response ($response); while ($bindings ne '') { ($binding,$bindings) = decode_sequence ($bindings); ($oid,$value) = decode_by_template ($binding, "%O%@"); $result = pretty_print($value); } return $result; } else { warn "SNMP Error: $SNMP_Session::errmsg\n"; return 0; } } ##################################################################################### # Section personnalisée pour faire du SNMP en TCP. # NS 22/02/03 ##################################################################################### sub snmpget2 { my($host, $community, $inoid, $outoid) = @_; open IN, "snmpget -T TCP $host $community interfaces.ifTable.ifEntry.$inoid |"; my $inresult = ; chomp($inresult); close(IN); open OUT, "snmpget -T TCP $host $community interfaces.ifTable.ifEntry.$outoid |"; my $outresult = ; chomp($outresult); close(OUT); my @intable = split(/ /,$inresult ); my @outtable = split(/ /,$outresult ); my @results = ($intable[-1],$outtable[-1]); return @results; } sub snmpgetup2 { my($host, $community, $upoid) = @_; open UP, "snmpget -T TCP $host $community $upoid |"; my $uptimeresult = ; chomp($uptimeresult); close(UP); $uptimeresult =~ s/^.*\) //; $uptimeresult =~ s/...$//; return $uptimeresult; } #################################################################################### sub chkuptime { $_ =~ s/\[|\]//g; my($uphost,$upip,$upcommunity,$upoid,$upfile) = split (/:/, $_); my $upresult = snmpgetup2($upip,$upcommunity,$upoid); tie(%inf, 'SDBM_File', ($upfile."$main::SL"."uptimes"), O_RDWR|O_CREAT, 0640) or print "WARNING: Error opening uptime database file!\n"; if ($upresult < $inf{$uphost} && $upresult > "1") { $hostreset = "1"; } else { $hostreset = "0"; } if ($upresult > "1") { $inf{$uphost} = $upresult; } untie(%inf); } sub main { my($name,$host,$community,$inoid,$outoid,$path,$datafile) = @_; tie(%inf, 'SDBM_File', ($path."$main::SL".$datafile), O_RDWR|O_CREAT, 0640) or print "Error opening database file for $name at $host\n"; if (-s (($path."$main::SL".$datafile) . ".pag")) { if ($inf{day} != $mday && $hour > "0") { newday(); dailyhtml($name,$host,$path); } if ($inf{month} != $mon) { $newmon = "1"; newday(); dailyhtml($name,$host,$path); newmonth($name,$path); monthlyhtml($name,$host,$path); } if ($inf{year} != ($year + "1900")) { newyear($name,$path); } if (!$newmon) { updatedata(); } if ($inf{day} != $mday) { $newday = "1"; } else { $newday = "0"; } hourlyhtml($name,$host,$path,$newday); } else { createdata(); hourlyhtml($name,$host,$path); } untie(%inf); } # create data file if ! exist # sub createdata { %inf = (lastin => $inoctets, lastout => $outoctets, month => $mon, day => $mday, year => ($year + "1900")); } # # sub newyear { my($name,$path) = @_; my($count); $count = 0; while ($count <= "11") { delete $inf{"m" . $count}; $count++; } # move yearly html file. $oldfile="$path"."$main::SL"."$name"."-months".".html"; $newfile="$path"."$main::SL"."$name"."-year".($year).".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } $inf{year} = ($year + "1900"); } # # sub newmonth { my($name,$path) = @_; my($count,$intotal,$outtotal,$inoct,$outoct); # get MB total for the month and store it. $count = 1; while ($count <= "31") { if ($inf{"d" . $count}) { ($inoct,$outoct) = split(/:/, $inf{"d" . $count}); $intotal += $inoct; $outtotal += $outoct; } $count++; } $intotal = ($intotal / $mbsize); $outtotal = ($outtotal / $mbsize); $inf{"m" . $inf{month}} = "$intotal:$outtotal"; # clear days $count = 1; while ($count <= "31") { delete $inf{"d" . $count}; $count++; } # move monthly html file. $oldfile="$path"."$main::SL"."$name"."-days".".html"; $newfile="$path"."$main::SL"."$name"."-month".($mon).".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } # set $inf{month} to the new month. $inf{month} = $mon; } # newday: # run every time the day of the month changes on the system. # sub newday { my($count,$nmday,$intotal,$outtotal,$inoct,$outoct); # get megabyte total for the day and store it. # $count = 0; while ($count <= "23") { if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); $intotal += $inoct; $outtotal += $outoct; } $count++; } if ($newmon) { $nmday = last_mday($inf{month}, $inf{year}); } else { $nmday = ($mday - 1); } $inf{"d" . $nmday} = "$intotal:$outtotal:" . ($intotal + $outtotal); # clear hours # $count = 0; while ($count <= "23") { delete $inf{$count}; $count++; } $inf{day} = $mday; } # update DBM file. # sub updatedata { my ($lasthour,$wrapin,$wrapout); my $intwrap="4294967296"; if ($hour eq "0") { $lasthour = "23"; } else { $lasthour = ($hour - "1"); } if ($hostreset == "1") { $inf{lastin} = $inf{lastout} = "0"; } # detect if a counter has wrapped and adjust. # if ($inoctets < $inf{lastin}) { $wrapin = $inoctets; $inoctets = ($intwrap - $inf{lastin}) + $inoctets; $inf{lastin} = "0"; } if ($outoctets < $inf{lastout}) { $wrapout = $outoctets; $outoctets = ($intwrap - $inf{lastout}) + $outoctets; $inf{lastout} = "0"; } $inf{$lasthour} = (($inoctets - $inf{lastin}).":".($outoctets - $inf{lastout})); if ($wrapin) { $inf{lastin} = $wrapin } else { $inf{lastin} = $inoctets } if ($wrapout) { $inf{lastout} = $wrapout } else { $inf{lastout} = $outoctets } } sub footer { print DHTML "


IOG $iogver - Input Output Grapher
-
James Dogopoulos <jd\@dynw.com>
Questions or comments to iog\@dynw.com

"; } # make the hourly html # sub hourlyhtml { my($name,$host,$path,$newday) = @_; # make todays graph # my $enddays = last_mday($mon, ($year + "1900")); my $count = "0"; my ($besthour,$bestday,$inoct,$outoct) = "0"; # find busiest hour # while ($count <= "23") { if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); } else { $inoct = $outoct = "0"; } if ($inoct > $besthour) { $besthour = $inoct; } if ($outoct > $besthour) { $besthour = $outoct; } $count++; } my $hscalemax = ($besthour / "1000000"); my ($hscaleunit,$intotal,$outtotal) = 0; if ($hscalemax > "0") { $hscaleunit = ("450" / $hscalemax); } open(DHTML, ">>$path".$main::SL."$name".".html") or print "can't open in $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host: $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; my $dexist = (-f "$path".$main::SL."$name"."-days.html"); my $mexist = (-f "$path".$main::SL."$name"."-months.html"); if ($newday != "1") { if ($dexist && $mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { if ($dexist && !$mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { if (!$dexist && $mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]"; } } } } else { if ($dexist && $mexist) { print DHTML " [ This Month | Previous Months ]

"; } else { if ($dexist && !$mexist) { print DHTML " [ This Month | Previous Months ]

"; } else { if (!$dexist && $mexist) { print DHTML " [ This Month | Previous Months ]

"; } } } } if ($newday eq "1") { $tday = "$nday"; } else { $tday = "$pday"; } print DHTML "

$months[$mon] $tday - Network I/O for $name ($host)

"; print DHTML ""; $count = "0"; while ($count <= "23") { my($inwidth,$outwidth); if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct / "1000000" * $hscaleunit); $outwidth = ($outoct / "1000000" * $hscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$mbin,$mbout); $mbin = sprintf("%.1f", $inoct / $mbsize); $mbout = sprintf("%.1f", $outoct / $mbsize); if ($mbin > $gbsize or $mbout > $gbsize) { $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gstring = ""; } else { $gstring = "\n"; print DHTML $gstring; $count++; } $intotal = sprintf("%.f", ($intotal / $mbsize)); $outtotal = sprintf("%.f", ($outtotal / $mbsize)); print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
In: $mbin MB (". sprintf("%.f", $inoct / $kbsize)." KB)
Out: $mbout MB (".sprintf("%.f", $outoct / $kbsize)." KB)"; } $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); print DHTML "
"."$count".":00
\n"; print DHTML "

"; if ($intotal > $gbsize or $outtotal > $gbsize) { my $gbtotal = sprintf("%.1f", ($intotal + $outtotal) / $gbsize); print DHTML "Today's Total: $gbtotal GB
In: $intotal MB - Out: $outtotal MB
"; } else { print DHTML "Today's Total: ".($intotal + $outtotal)." MB
In: $intotal MB - Out: $outtotal MB
"; } footer(); flock(DHTML, 8); close(DHTML); } sub monthlyhtml { my ($name,$host,$path) = @_; my ($bestmonth,$m_intotal,$m_outtotal,$m_total); my $count = 0; # find busiest month while ($count <= "11") { if ($inf{"m" . $count}) { ($m_intotal,$m_outtotal) = split(/:/, $inf{"m" . $count}); if ($m_intotal > $bestmonth) { $bestmonth = $m_intotal; } if ($m_outtotal > $bestmonth) { $bestmonth = $m_outtotal; } } $count++; } my $mscalemax = $bestmonth; my ($mscaleunit,$intotal,$outtotal) = 0; if ($mscalemax > "0") { $mscaleunit = ("450" / $mscalemax); } open(DHTML, ">>$path".$main::SL."$name"."-months.html") or print "can't open $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host : $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; my $dexist = (-f "$path".$main::SL."$name"."-days.html"); if ($dexist) { print DHTML "[ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]

"; } print DHTML "

Monthly Network I/O for $name ($host)

"; print DHTML ""; $count = "0"; while ($count <= "11") { my($inwidth,$outwidth,$intotal,$outtotal,$inoct,$outoct,$mtotal); if ($inf{"m" . $count}) { ($inoct,$outoct,$mtotal) = split(/:/, $inf{"m" . $count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct * $mscaleunit); $outwidth = ($outoct * $mscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$gbtotal,$mbin,$mbout); $mbin = sprintf("%.f", $inoct); $mbout = sprintf("%.f", $outoct); $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gbtotal = sprintf("%.1f", ($gbin + $gbout)); $gstring = ""; $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); if (-f "$path".$main::SL."$name"."-month".($count + "1").".html") { $mlink = "$months[$count]"; } else { $mlink = "$months[$count]"; } print DHTML "\n"; print DHTML $gstring; $count++ } print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
$mlink
$gbtotal GB

\n"; print DHTML "

"; footer(); flock(DHTML, 8); close(DHTML); } sub dailyhtml { my ($bestday,$d_intotal,$d_outtotal) = 0; my ($name,$host,$path) = @_; my $count = 1; my $endday = last_mday($inf{month}, $inf{year}); if ($endday eq $mday) { $lastday="1"; } else { $lastday="0"; } # fix math errors from previous sub if ($newmon) { $mon--; } # move Today's html file unless it's a new month. if (!$newmon) { $oldfile="$path"."$main::SL"."$name".".html"; $newfile="$path"."$main::SL"."$name"."-day".($mday - "1").".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } } # find busiest day (should be merged with totals) while ($count <= $endday) { if ($inf{"d" . $count}) { ($d_intotal,$d_outtotal) = split(/:/, $inf{"d" . $count}); if ($d_intotal > $bestday) { $bestday = $d_intotal; } if ($d_outtotal > $bestday) { $bestday = $d_outtotal; } } $count++; } my $dscalemax = ($bestday / "1000000"); my ($dscaleunit,$intotal,$outtotal) = 0; if ($dscalemax > "0") { $dscaleunit = ("450" / $dscalemax); } open(DHTML, ">>$path".$main::SL."$name"."-days.html") or print "can't open $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host : $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; if (-f "$path".$main::SL."$name"."-months.html") { print DHTML "[ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]

"; } print DHTML "

$months[$mon] - Network I/O for $name ($host)

"; print DHTML ""; $count = "1"; while ($count <= $endday) { my($inwidth,$outwidth,$inoct,$outoct,$pday); if ($inf{"d" . $count}) { ($inoct,$outoct) = split(/:/, $inf{"d" . $count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct / "1000000" * $dscaleunit); $outwidth = ($outoct / "1000000" * $dscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$mbin,$mbout); $mbin = sprintf("%.f", $inoct / $mbsize); $mbout = sprintf("%.f", $outoct / $mbsize); if ($mbin > $gbsize or $mbout > $gbsize) { $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gstring = ""; } else { $gstring = "\n"; print DHTML $gstring; $count++; } $intotal = sprintf("%.f", ($intotal / $mbsize)); $outtotal = sprintf("%.f", ($outtotal / $mbsize)); my $gbtotal = sprintf("%.1f", (($intotal + $outtotal) / $gbsize)); print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
In: $mbin MB (". sprintf("%.f", $inoct / $kbsize)." KB)
Out: $mbout MB (".sprintf("%.f", $outoct / $kbsize)." KB)"; } $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); if ($days{$count}) { $pday = $days{$count}; } else { $pday = $count."th"; } if (-f "$path".$main::SL."$name"."-day".$count.".html" && $lastday eq "0" && ($newmon ne "1")) { $pday = "$pday"; } print DHTML "
$pday
\n"; print DHTML "

"; print DHTML "Monthly Total: $gbtotal GB
In: $intotal MB - Out: $outtotal MB
"; footer(); flock(DHTML, 8); close(DHTML); # reverse math errors if ($newmon) { $mon++; } } # END # # IOG v1.0 - Input/Output Grapher # Copyright 2000-2002 (c) James Dogopoulos #