$true= (1==1);
$false= !$true;
$unexpected= "unexpected"; $noARAPUser= ";"; $programYear= 99; @monthsToDays= (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
%monthsToNumeric= ("Jan" => "01",
"Feb" => "02",
"Mar" => "03",
"Apr" => "04",
"May" => "05",
"Jun" => "06",
"Jul" => "07",
"Aug" => "08",
"Sep" => "09",
"Oct" => "10",
"Nov" => "11",
"Dec" => "12" );
%daysEachMonth= ("01" => "31",
"02" => "28",
"03" => "31",
"04" => "30",
"05" => "31",
"06" => "30",
"07" => "31",
"08" => "31",
"09" => "30",
"10" => "31",
"11" => "30",
"12" => "31" );
%secondsToMonths= ( 0 => "01",
2678400 => "02",
5097600 => "03",
7776000 => "04",
10368000 => "05",
13046400 => "06",
15638400 => "07",
18316800 => "08",
20995200 => "09",
23587200 => "10",
26265600 => "11",
28857600 => "12" );
%ports= (); @isdnInterfaces= (); @modemInterfaces= (); %isdnChannels= (); %userDurations= (); %arapDurations= (); %arapUsers= (); %durations= (); %connections= (); %userReceived= (); %userTransmitted= (); %received= (); %transmitted= (); @configured= (); %modemProblems= (); %callerProblems= (); %unmatched= (); %nameless= (); %namelessDurations= (); %abnormalTermUsers= (); %abnormalTermTypes= ();
use Getopt::Long;
GetOptions("d|debug" => \$debug,
"r|reverse" => \$reverse,
"p|primer=s" => \$primerLog,
"t|top" => \$top,
);
$top= 10 unless $top;
if ($reverse)
{ @files= reverse sort @ARGV; }
else
{
@files= sort @ARGV;
}
PrimeModemCounts($primerLog) if $primerLog;
foreach $file (@files)
{ ProcessLog($file);
}
Report(GetDates($files[0], $files[$#files]));
exit;
sub PrimeModemCounts
{
my($file)= shift;
print "Priming initial values from $file...\n\n" if $debug;
open(Input, $file) or die "Cannot read from $file: $!";
while (<Input>)
{ if (/\%CALLRECORD-3-MCOM_TERSE_CALL_REC/)
{ my($dso, $port, $callID, $userID, $ip, $calling, $called,
$standard, $protocol, $compression, $initRate, $finalRate,
$snr, $transferred)= split(", ");
$port= 1 + ($1-1)*24 + $2 if $port=~ /slot\/port=(\d+)\/(\d+)/;
if ($transferred=~ /(\d+)\/(\d+)/)
{
$received{$port}= $1; $transmitted{$port}= $2; }
$arapUsers{$port}= $false if exists($arapUsers{$port});
$arapDurations{$port}= $false
if exists($arapDurations{$port});
next; }
if (/\%ISDN-6-CONNECT: Interface Serial(\d+):(\d+)/)
{ my($interface)= $1 * 24 + $2; my($to)= /to (.+)/;
if ($to)
{
my($calling, $userID)= split(" ", $to);
if ($calling and $userID)
{ $calling= "21726" . $calling
if $calling < 99999; $isdnChannels{$calling}= $userID; print "New call from $calling by $userID\n" if $debug;
}
}
next; }
if (/\%ARAP-6-ADDRFREE: TTY (\d+).+user ([^\s]+).+; (\d+) second/)
{ $arapUsers{$1}= $2; $arapDurations{$1}= $3; $arapUsers{$1}=~ s/;$/ (a)/ if $2 ne $noARAPUser;
next; }
}
close(Input);
}
sub ProcessLog
{
my($file)= shift;
my(%isdnDurations)= ();
print "Processing $file...\n\n" if $debug;
open(Input, $file) or die "Cannot read from $file: $!";
while (<Input>)
{ next if /\%LINEPROTO-5-UPDOWN/ or /\%LINK-5-CHANGED/ or /\%LINK-3-UPDOWN/;
if (/\%CALLRECORD-3-MCOM_TERSE_CALL_REC/)
{ my($dso, $port, $callID, $userID, $ip, $calling, $called, $standard, $protocol, $compression, $initRate, $finalRate,
$snr, $transferred, $ec, $time, $finalState,
$discRadius, $discLocal, $discRemote)= split(", ");
my($disconnectTime)= /^(.{15})/;
my($month, $day)= $disconnectTime=~ /^(.{3})\s+(\d+)/;
$month= $monthsToNumeric{$month};
$day= "0$day" if $day < 10;
$disconnectTime=~ s/^.{6}/$programYear$month$day/;
$userID=~ s/userid=//; if (length($userID) > 16)
{ $userID=~ s/^(.{13}).*$/$1\.\.\./;
}
$time=~ s/time=//;
$discRadius=~ s/disc\(radius\)=//;
$port= 1 + ($1-1)*24 + $2 if $port=~ /slot\/port=(\d+)\/(\d+)/;
push(@modemInterfaces, ConnectTime($disconnectTime, $time) . "; +$port");
push(@modemInterfaces, "$disconnectTime; -$port");
$dso= $1 * 10 + $2 * 24 + $3 if $dso=~ /=(\d+)\/(\d+)\/(\d+)/;
$ports{$dso}--;
my($myReceived)= 0;
my($myTransmitted)= 0;
if ($transferred=~ /(\d+)\/(\d+)/)
{
if (exists($received{$port}))
{
$myReceived= $1 - $received{$port};
}
else
{
print "Initial received count for modem $port\n" if $debug;
}
$received{$port}= $1; if (exists($transmitted{$port}))
{
$myTransmitted= $2 - $transmitted{$port};
}
else
{
print "Initial transmitted count for modem $port\n" if $debug;
}
$transmitted{$port}= $2; }
else
{ print "Malformed transmission counts <$transferred>\n" if $debug;
}
if ($userID eq "(n/a)")
{ if($arapUsers{$port})
{ if ($arapUsers{$port} eq $noARAPUser)
{ $calling= s/^calling=//;
$calling= "unknown" unless $calling;
$calling= "ARAP $calling";
$nameless{$calling}++; $namelessDurations{$calling}+= $time;
}
else
{ $userID= $arapUsers{$port}; if (length($userID) > 16)
{ $userID=~ s/^(.{13}).*$/$1\.\.\./;
}
$time= $arapDurations{$port};
$connections{$userID}++;
$durations{$time}= $userID;
$userDurations{$userID}+= $time;
$userReceived{$userID}+= $myReceived if $myReceived > 0;
$userTransmitted{$userID}+= $myTransmitted if $myTransmitted > 0;
}
}
else
{ $calling= s/^calling=//; $calling= "unknown" unless $calling;
$calling= "PPP $calling";
$nameless{$calling}++; $namelessDurations{$calling}+= $time;
}
}
else
{ $userID.= " [p]"; $connections{$userID}++;
$durations{$time}= $userID;
$userDurations{$userID}+= $time;
$userReceived{$userID}+= $myReceived if $myReceived > 0;
$userTransmitted{$userID}+= $myTransmitted if $myTransmitted > 0;
if ($discRadius ne "User Request/Received Terminate")
{ $abnormalTermUsers{"$userID\t$discRadius"}++;
$abnormalTermTypes{$discRadius}++;
}
print "Stranded ARAP record on port $port!"
if $arapUsers{$port} and $debug;
}
$arapUsers{$port}= $false; $arapDurations{$port}= $false;
next; }
if (/\%CALLRECORD-3-MCOM_TERSE_CALL_FAILED_REC/)
{ my($dso, $port, $callID, $calling, $called,
$time, $finalState, $discLocal, $discRemote)= split(", ");
my($disconnectTime)= /^(.{15})/;
my($month, $day)= $disconnectTime=~ /^(.{3})\s+(\d+)/;
$month= $monthsToNumeric{$month};
$day= "0".$day if $day < 10;
$disconnectTime=~ s/^.{6}/$programYear$month$day/;
$time=~ s/time=//;
$calling=~ s/calling=//; $port= 1 + ($1-1)*24 + $2 if $port=~ /slot\/port=(\d+)\/(\d+)/;
$time= 10 unless $time; push(@modemInterfaces, ConnectTime($disconnectTime, $time) . "; +$port");
push(@modemInterfaces, "$disconnectTime; -$port");
$dso= $1 * 10 + $2 * 24 + $3 if $dso=~ /=(\d+)\/(\d+)\/(\d+)/;
$ports{$dso}--;
$modemProblems{$port}++; $callerProblems{$calling}++; next; }
if (/\%ARAP-6-ADDRFREE: TTY (\d+).+user ([^\s]+).+; (\d+) second/)
{ $arapUsers{$1}= $2; $arapDurations{$1}= $3; $arapUsers{$1}=~ s/;$/ (a)/ if $2 ne $noARAPUser;
next; }
next if /\%ARAP-6-ADDRUSED/;
if (/\%ISDN-6-DISCONNECT: Interface Serial(\d+):(\d+)/)
{ my($interface)= $1 * 24 + $2; my($time)= /call lasted (\d+) second/;
my($disconnectTime)= /^(.{15})/;
my($month, $day)= $disconnectTime=~ /^(.{3})\s+(\d+)/;
$month= $monthsToNumeric{$month};
$day= "0".$day if $day < 10;
$disconnectTime=~ s/^.{6}/$programYear$month$day/;
push(@isdnInterfaces, ConnectTime($disconnectTime, $time) . "; +$interface");
push(@isdnInterfaces, "$disconnectTime; -$interface");
my($from)= /from ([^,]+)/;
if ($from)
{
my($calling, $userID)= split(" ", $from);
if ($userID)
{
if (length($userID) > 16)
{ $userID=~ s/^(.{13}).*$/$1\.\.\./;
}
if ((exists($isdnChannels{$calling+1})
and $isdnChannels{$calling+1} eq $userID)
or (exists($isdnChannels{$calling-1})
and $isdnChannels{$calling-1} eq $userID))
{ print "First channel of a dual-channel call: ",
"$userID via $calling\n" if $debug;
$isdnDurations{$userID}= $time;
$isdnChannels{$calling}= $false;
}
else
{
if ($isdnDurations{$userID})
{ $time= $isdnDurations{$userID}
if $time < $isdnDurations{$userID};
$isdnDurations{$userID}= $false;
print "Second channel disconnecting of a dual-channel call:\n",
"\t $userID via $calling lasting $time\n\n" if $debug;
$userID.= " {2}"; }
else
{ print "Single channel disconnect from $calling by $userID ",
"lasting $time\n" if $debug;
$userID.= " {1}"; }
$connections{$userID}++;
$durations{$time}= $userID;
$userDurations{$userID}+= $time;
}
}
else
{ $ports{$interface}++; }
}
next; }
if (/\%ISDN-6-CONNECT: Interface Serial(\d+):(\d+)/)
{ my($interface)= $1 * 24 + $2; my($to)= /to (.+)/;
if ($to)
{
my($calling, $userID)= split(" ", $to);
if ($calling and $userID)
{ $calling= "21726" . $calling
if $calling < 99999; $isdnChannels{$calling}= $userID; print "New call from $calling by $userID\n" if $debug;
}
}
next; }
if (/^(.{15,15}).+\%SYS-5-CONFIG_I:(.+)$/)
{ push(@configured, "$1$2\n");
next; }
next if /-Traceback=/;
next if /\%AT-6-NODEWRONG/;
next if /\%ARAP-6-MNP4T401/;
next if /\%ARAP-6-RESENDSLOW/;
next if /\%ARAP-6-RCVGIANT/;
next if /\%ARAP-6-MAXRESENDS/;
next if /\%SYS-3-CPUHOG/;
next if /\%AAAA-3-INVSTATE/;
if (/%([^:]+):/)
{ $unmatched{$1}++;
}
else
{ /^\s*(.*)\s*$/; $unmatched{$1}= 0;
$unmatched{$unexpected}++;
}
}
close(Input);
}
sub Report
{
my($dateRange)= shift; my($index); my($value); my($name); my(@ranks); my($stranded)= "";
print "\nDial-up report: $dateRange\n";
print "=======================================================\n";
my($month, $day)= $dateRange=~ /^(.{3})\s+(\d+)/;
$month= $monthsToNumeric{$month};
$day= "0".$day if $day < 10;
$dateRange=~ s/^.{6}/$programYear$month$day/;
print "\n Peak Active ISDN Channels Each Hour\n\n",
Tabulate($dateRange, sort(@isdnInterfaces)),
"\n\n\n Peak Active Modems Each Hour\n\n",
Tabulate($dateRange, sort(@modemInterfaces)), "\n\n";
print "\nStranded ports\n--------------\n";
foreach (sort { $a <=> $b; } (keys(%ports)))
{
next unless $ports{$_}; $stranded.= sprintf " Port %2d, state %2d\n", $_, $ports{$_};
}
$stranded= "None!\n" unless $stranded;
print $stranded;
if (each(%modemProblems))
{ print "\nFailed calls by modem\n---------------------\n";
@ranks=
sort {$modemProblems{$a}<=>$modemProblems{$b};} (keys(%modemProblems));
while ($value= pop(@ranks))
{ printf " modem %2d: %3d failed call%s\n", $value,
$modemProblems{$value}, $modemProblems{$value} == 1 ? "" : "s";
}
}
if (each(%callerProblems))
{ print "\nFailed calls by caller\n----------------------\n";
@ranks= sort {$callerProblems{$a}<=>$callerProblems{$b};}
(keys(%callerProblems));
while ($value= pop(@ranks))
{ if ($value eq "(n/a)")
{
printf " unknown: %3d failed call%s\n", $callerProblems{$value},
$callerProblems{$value} == 1 ? "" : "s";
}
else
{
printf "%13s: %3d failed call%s\n", $value, $callerProblems{$value},
$callerProblems{$value} == 1 ? "" : "s";
}
}
}
if (each(%nameless))
{ print "\nNameless call records\n---------------------\n";
foreach (sort {$nameless{$a}<=>$nameless{$b};} (keys(%nameless)))
{ if ($namelessDurations{$_})
{ printf "%20s: %3d call%s averaging %s (total: %6ld s)\n",
$_, $nameless{$_}, $nameless{$_} == 1 ? " " : "s",
VerboseTime($namelessDurations{$_} / $nameless{$_} + .49),
$namelessDurations{$_};
}
else
{ printf "%20s: %3d call%s of unknown duration\n",
$_, $nameless{$_}, $nameless{$_} == 1 ? " " : "s";
}
}
}
if (each(%abnormalTermTypes))
{ print "\nAbnormal terminations by type\n-----------------------------\n";
foreach (sort {$abnormalTermTypes{$b}<=>$abnormalTermTypes{$a};}
(keys(%abnormalTermTypes)))
{ printf "%9d %s\n", $abnormalTermTypes{$_}, $_;
}
}
if (each(%abnormalTermUsers))
{ print "\nMost abnormal terminations by a user",
"\n------------------------------------\n";
@ranks= sort {$abnormalTermUsers{$a}<=>$abnormalTermUsers{$b};}
(keys(%abnormalTermUsers));
for ($index= 0; $index < $top; $index++)
{ $value= pop(@ranks);
last unless $value; my($userID, $type)= split("\t", $value);
printf "%20s: %3d %s\n", $userID, $abnormalTermUsers{$value}, $type;
}
}
if (each(%userTransmitted))
{ print "\nMost data received by a user\n----------------------------\n";
@ranks= sort {$userTransmitted{$a}<=>$userTransmitted{$b};}
(keys(%userTransmitted));
for ($index= 0; $index < $top; $index++)
{ $value= pop(@ranks);
last unless $value; printf "%20s: %s\n", $value,
DataSize($userTransmitted{$value}, $userDurations{$value});
}
}
if (each(%userReceived))
{ print "\nMost data sent by a user\n------------------------\n";
@ranks= sort {$userReceived{$a}<=>$userReceived{$b};}
(keys(%userReceived));
for ($index= 0; $index < $top; $index++)
{ $value= pop(@ranks);
last unless $value; printf "%20s: %s\n", $value,
DataSize($userReceived{$value}, $userDurations{$value});
}
}
if (each(%durations))
{ print "\nLongest calls\n-------------\n";
@ranks= sort { $a <=> $b; } (keys(%durations));
for ($index= 0; $index < $top; $index++)
{ $value= pop(@ranks);
last unless $value; printf "%20s: %s\n", $durations{$value}, VerboseTime($value);
}
}
if (each(%connections))
{ print "\nSuccessfull callers ranked by frequency",
"\n---------------------------------------\n";
foreach (sort {$connections{$b}<=>$connections{$a}} (keys(%connections)))
{ printf "%20s: %5d connection%s lasting %s (%9ld s)\n",
$_, $connections{$_},
$connections{$_} == 1 ? " " : "s", ApproximateTime($userDurations{$_}),
$userDurations{$_};
}
}
if (@configured)
{ print "\nConfiguration changes\n---------------------\n";
foreach (@configured)
{ print;
}
}
if (each(%unmatched))
{ print "\nUnexpected records and lines\n----------------------------\n";
foreach (sort {$unmatched{$b}<=>$unmatched{$a}} (keys(%unmatched)))
{ if ($unmatched{$_} == 0)
{ print "\n$_" if $debug;
}
else
{ printf "%6d %s line%s\n", $unmatched{$_}, $_,
$unmatched{$_}==1 ? "" : "s";
}
}
}
}
sub GetDates
{
my($firstLog)= shift;
my($lastLog)= shift;
my($firstDate, $lastDate);
open(Input, $firstLog) or die "Cannot read from $firstLog: $!";
$firstDate= <Input>; close(Input);
open(Input, $lastLog) or die "Cannot read from $lastLog: $!";
if (seek(Input, -1000, 2))
{ while (<Input>)
{ $lastDate= $_; }
}
else
{
$lastDate= "<unknown>";
}
close(Input);
return (sprintf("%15.15s through %15.15s", $firstDate, $lastDate));
}
sub DataSize
{
my($size)= shift; my($time)= shift;
return "inconceivable! ($size)" if $size < 1;
return "nothing ($size)" if $size == 0;
return "one byte ($size)" if $size == 1;
my($rate); if ($time)
{ $rate= sprintf(", %5.2f Kbps)", ($size * 8) / ($time * 1024));
}
else
{ $rate= ")";
}
return "$size bytes ($size chars$rate"
if $size < 1000;
return sprintf("%6.2f kilobytes (%9ld chars$rate", $size / 1024, $size)
if $size < 1000 * 1024;
return sprintf("%6.2f megabytes (%9ld chars$rate",
$size / (1024 * 1024), $size)
if $size < 1000 * 1024 * 1024;
return sprintf("%6.2f gigabytes ($size chars$rate",
$size / (1024 * 1024 * 1024));
}
sub VerboseTime
{
use integer; my($time)= shift; my($phrase)= ""; my($span);
return "inconceivable! ($time)" if $time < 0;
return "no time" unless $time;
if ($span= $time % 60)
{ $phrase= sprintf("%2d second%s", $span, $span>1 ? "s" : "");
}
return $phrase unless $time/= 60;
if ($span= $time % 60)
{ $phrase= sprintf("%2d minute%s%s", $span,
$span>1 ? "s" : "",
$phrase ? ($span>1 ? ", " : ", ") . $phrase : "");
}
return $phrase unless $time/= 60;
if ($span= $time % 24)
{ $phrase= sprintf("%2d hour%s%s", $span,
$span>1 ? "s" : "",
$phrase ? ($span>1 ? ", " : ", ") . $phrase : "");
}
return $phrase unless $time/= 24;
if ($span= $time % 7)
{ $phrase= sprintf("%2d day%s%s", $span,
$span>1 ? "s" : "",
$phrase ? ($span>1 ? ", " : ", ") . $phrase : "");
}
return $phrase unless $time/= 7;
if ($span= $time % 52)
{ $phrase= sprintf("%2d week%s%s", $span,
$span>1 ? "s" : "",
$phrase ? ($span>1 ? ", " : ", ") . $phrase : "");
}
return $phrase unless $time/= 52;
$phrase= sprintf("%2d year%s%s", $span,
$span>1 ? "s" : "",
$phrase ? ($span>1 ? ", " : ", ") . $phrase : "");
return $phrase;
}
sub ApproximateTime
{
my($time)= shift;
return "inconceivable! " if $time < 0;
return "no time at all " unless $time;
return sprintf(" %2d second%s ", $time, $time>1 ? "s" : " ")
if ($time < 45);
return "about 1 minute " if ($time < 91);
return sprintf("about %2.0f minutes ", $time/60)
if ($time < 3600);
return "about an hour " if ($time < 5401);
return sprintf("about %2.0f hours ", $time/3600)
if ($time < 86400);
return "about 1 day " if ($time < 129601);
return sprintf("about %2.0f days ", $time/86400)
if ($time < 604800);
return "about 1 week " if ($time < 907201);
return sprintf("about %2.0f weeks ", $time/604800)
if ($time < 31449600);
return "about 1 year " if ($time < 47174400);
return sprintf("about %2.0f years ", $time/31449600);
}
sub ConnectTime
{
use integer;
my($disconnectTime)= shift;
my($span)= shift;
my($year, $month, $day, $hour, $minute, $second)=
$disconnectTime=~ /^(\d\d)(\d\d)(\d\d)\s+(\d+):(\d+):(\d+)/;
my($disconnectSeconds)= ($monthsToDays[$month-1]+$day-1) * 86400
+ $hour * 3600 + $minute * 60 + $second;
my($connectSeconds)= $disconnectSeconds - $span;
while ($connectSeconds < 0)
{ $connectSeconds+= 365 * 86400;
$year--;
}
foreach (reverse sort { $a <=> $b; } keys(%secondsToMonths))
{
if ($connectSeconds >= $_)
{ print "$connectSeconds exceeds $_\n" if $debug;
$month= $secondsToMonths{$_};
$connectSeconds-= $_;
last;
}
}
$day= $connectSeconds / 86400 + 1;
$day= "0" . $day if $day < 10;
$connectSeconds%= 86400;
$hour= $connectSeconds / 3600;
$hour= "0" . $hour if $hour < 10;
$connectSeconds%= 3600;
$minute= $connectSeconds / 60;
$minute= "0" . $minute if $minute < 10;
$second= $connectSeconds % 60;
$second= "0" . $second if $second < 10;
print "$year$month$day $hour:$minute:$second to $disconnectTime ($span)\n"
if $debug;
return "$year$month$day $hour:$minute:$second";
}
sub Tabulate
{
my($firstDate)= shift; my($firstHour);
my($event); my($current)= 0; my($max)= 0;
my($min)= 99;
my($date);
my($lastDate);
my($hour);
my($lastHour);
my(@maxima)= (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
my(@minima)=
(99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99);
my(@means)= (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
my(@counts)= (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
my($table); my($topRow)= 0; my($header)= " < hr 0 1 2 3 4 5 6 7 8 9 10 11" .
" 12 13 14 15 16 17 18 19 20 21 22 23";
my($separator)= ":-------------------------------------" .
"------------------------------------";
($firstDate, $firstHour)= $firstDate=~ /^(\d{6}) (\d\d)/;
$lastDate= $firstDate;
$lastHour= $firstHour;
$table= $header . "\n date " . $separator;
$lastDate=~ /\d\d(\d\d)(\d\d)/;
$table.= "\n$1\/$2 : "; for ($hour= 0; $hour < $lastHour; $hour++)
{ $table.= " ";
}
while($event= shift)
{ ($date, $hour)= $event=~ /^(\d{6}) (\d\d)/;
if ($date < $firstDate)
{ $date= $firstDate;
$hour= $firstHour;
$track= $false;
}
elsif ($date == $firstDate and $hour < $firstHour)
{
$hour= $firstHour;
$track= $false;
}
else
{ $track= $true; }
while ($lastDate < $date)
{ while ($lastHour < 24)
{ $table.= $max ? sprintf("%3d", $max) : " ";
$minima[$lastHour]= $min if $track and ($min < $minima[$lastHour]);
$maxima[$lastHour]= $max if $track and ($max > $maxima[$lastHour]);
$means[$lastHour]+= $current if $track;
$counts[$lastHour]++ if $track;
$lastHour++;
$max= $min= $current; }
my($year, $month, $day)= $lastDate=~ /^(\d\d)(\d\d)(\d\d)/;
$lastHour= 0; $day++; if ($day > $daysEachMonth{$month})
{ $date=~ /^\d\d(\d\d)(\d\d)/;
unless ($month == 2 and $day == 29 and $1 == 2 and $2 == 29)
{ $month++;
if ($month < 10)
{ $month= "0$month" if $month < 10;
}
elsif ($month > 12)
{ $month= "01";
$year++;
}
$day= "01";
}
}
$lastDate= "$year$month$day";
$table.= "\n$month\/$day : "; }
while ($lastHour < $hour)
{ $table.= $max ? sprintf("%3d", $max) : " ";
$minima[$lastHour]= $min if $track and ($min < $minima[$lastHour]);
$maxima[$lastHour]= $max if $track and ($max > $maxima[$lastHour]);
$means[$lastHour]+= $current if $track;
$counts[$lastHour]++ if $track;
$lastHour++;
$max= $min= $current; }
$event=~ /\+/ ? $current++ : $current--;
if ($current < 0)
{ print "Bogus interface count: $event ($track)\n";
$current= 0;
}
$max= $current if $current > $max;
$min= $current if $current < $min;
print "Zero count: $event ($track)\n" if $debug and ($min == 0);
$means[$hour]+= $current if $track;
$counts[$hour]++ if $track;
$minima[$hour]= $min if $track and ($min < $minima[$hour]);
$maxima[$hour]= $max if $track and ($max > $maxima[$hour]);
}
$table.= sprintf("%3d", $max);
$table.= "\n " . $separator . "\n" . $header . "\n \# " . $separator;
foreach (@maxima)
{ $topRow= $_ if $_ > $topRow;
}
do { $table.= sprintf("\n %2d : ", $topRow);
for ($hour= 0; $hour < 24; $hour++)
{ my($tick)= " ";
$tick= " - " if $minima[$hour] == $topRow;
$tick= " + " if $maxima[$hour] == $topRow;
$tick= " | " if $maxima[$hour] > $topRow and $topRow > $minima[$hour];
$tick= " * " if ($counts[$hour])
and (int($means[$hour]/$counts[$hour]+0.5) == $topRow);
$table.= $tick;
}
}
while ($topRow--);
return $table . "\n " . $separator;
}