"Fossies" - the Fresh Open Source Software Archive

Member "squid-graph/squid-graph" (2 Oct 2006, 38958 Bytes) of package /linux/privat/old/squid-graph-3.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #!/usr/bin/perl
    2 
    3 #####################################################################
    4 #
    5 # Squid Graph version 3.2
    6 # http://squid-graph.sourceforge.net
    7 #
    8 # This program is distributed under the GNU General Public License
    9 # See gpl.txt for full license information
   10 #
   11 #####################################################################
   12 
   13 use strict;
   14 use GD;
   15 
   16 # Program version (DO NOT TOUCH THIS)
   17 my $VER = "3.2 release";
   18 
   19 # Enable console logging? (1 = on, 0 = off)
   20 my $CONSOLELOG = 1;
   21 
   22 # "Global" variables (DO NOT TOUCH THESE)
   23 my %config; # configuration details here
   24 my %color;  # colours configuration
   25 
   26 # Define graph colours [RRR,GGG,BBB]
   27 $color{'bg'}   = ['F5','F5','F5']; # graph background color
   28 $color{'fg'}   = ['00','00','00']; # graph foreground color
   29 $color{'gr'}   = ['00','00','FF']; # graph total line color
   30 $color{'hit'}  = ['FF','00','00']; # graph hit line color
   31 $color{'miss'} = ['00','FF','00']; # graph miss line color
   32 $color{'ims'}  = ['FF','00','FF']; # graph ims hit line color
   33 $color{'hbg'}  = ['FF','FF','FF']; # html report background color
   34 
   35 ############ DO NOT EDIT ANYTHING BELOW THIS LINE ##############
   36 
   37 # Forward subroutine declaration
   38 sub main();     # main program body
   39 sub error($);       # error(string: $msg);
   40 sub warning($);     # warning(string: $msg);
   41 sub console_log($); # console_log(string: $msg);
   42 sub parse_argv();   # requires defined %config
   43 sub config_check(); # requires defined %config
   44 sub create_gd();    # returns $imgAccess, $graphAccess;
   45 sub write_img($$);  # write image to file
   46 sub plot($$\$\@\@\@\@); # plot($type,$gdimg,@totalData,@hitData,@missData,$imsData);
   47 sub hr_units($);    # hr_units(int: $num);
   48 sub hr_bytes($);    # hr_bytes(int: $num);
   49 sub hr_digits($$);  # hr_digits(int: $num, char: $units);
   50 sub dec_truncate($$);   # dec_truncate($num,$decplaces);
   51 sub comma_sep($);   # comma_sep($num);
   52 sub help();     # help(string: $helpCmd);
   53 
   54 # Parse and check arguments
   55 parse_argv();
   56 if (config_check()) {
   57     main();
   58 }
   59 else {
   60     error("Configuration check failed.");
   61 }
   62 
   63 # Main subroutine
   64 sub main() {
   65 
   66     #
   67     # NOTES
   68     #
   69     # Graph stats: Total, Hit, Miss, IMS/Err
   70     #       TCP, UDP
   71     #       Access, Transfer
   72     #
   73 
   74     my ($have_tcp, $have_udp) = (0,0);
   75     my $have_cumulative = 0;
   76     my $have_transfer = 1;
   77     my $logStart = 0;
   78     my $title = "Squid Graph Logfile Analysis Report";
   79     my $graphLength = 60*60*24; # Graph is 24 hours long
   80     my $progStart = $^T;
   81     my $progSpeed = 0;
   82     my $duration = 0;
   83     my $lineCounter = 0;
   84     my $errorLines = 0;
   85 
   86     # Statistics data
   87     my @tcpAccessTotal;
   88     my @tcpAccessHit;
   89     my @tcpAccessMiss;
   90     my @tcpAccessIMS;
   91     my @tcpTransferTotal;
   92     my @tcpTransferHit;
   93     my @tcpTransferMiss;
   94     my @tcpTransferIMS;
   95     my @tcpTimeTotal;
   96     my @tcpTimeHit;
   97     my @tcpTimeMiss;
   98     my @tcpTimeIMS;
   99     my @udpAccessTotal;
  100     my @udpAccessHit;
  101     my @udpAccessMiss;
  102     my @udpTransferTotal;
  103     my @udpTransferHit;
  104     my @udpTransferMiss;
  105     my @udpTimeTotal;
  106     my @udpTimeHit;
  107     my @udpTimeMiss;
  108 
  109     # Image objects
  110     my ($tcpAccessImg, $tcpTransferImg, $tcpTimeImg);
  111     my ($udpAccessImg, $udpTransferImg, $udpTimeImg);
  112 
  113     # Stats counter
  114     my $i = 0;
  115 
  116     console_log("Squid-graph $VER OK. Program started.");
  117     console_log("Graph domain is $graphLength seconds.");
  118 
  119     # Report title specified
  120     if (exists $config{'title'}) {
  121         $title = $config{'title'};
  122     }
  123     console_log("Setting report title to \"$title\".");
  124 
  125     # Determine if cumulative graps were configured
  126     if (exists $config{'cumulative'}) {
  127         console_log("Configured for cumulative curves.");
  128         $have_cumulative = 1;
  129     }
  130     else {
  131         console_log("Configured for default histograms.");
  132     }
  133 
  134     # Determine if TCP or UDP configured
  135     if (exists $config{'tcp-only'}) {
  136         console_log('Configured have_tcp.');
  137         ($have_tcp, $have_udp) = (1,0);
  138     }
  139     elsif (exists $config{'udp-only'}) {
  140         console_log('Configured have_udp.');
  141         ($have_tcp, $have_udp) = (0,1);
  142     }
  143     else {
  144         console_log('Configured have_tcp and have_udp.');
  145         ($have_tcp, $have_udp) = (1,1);
  146     }
  147 
  148     # Determine have_transfer
  149     if (exists $config{'no-transfer-duration'}) {
  150         console_log("Transfer duration graph(s) disabled.");
  151         $have_transfer = 0;
  152     }
  153     elsif ($have_cumulative) {
  154         console_log("Transfer duration graph(s) automatically disabled.");
  155         $have_transfer = 0;
  156     }
  157     else {
  158         console_log("Transfer duration graph(s) enabled.");
  159     }
  160 
  161     # Was --start or --end specified?
  162     if (exists $config{'start'}) {
  163         $logStart = $config{'start'};
  164     }
  165     elsif (exists $config{'end'}) {
  166         $logStart = $config{'end'} - $graphLength;
  167     }
  168     else {
  169         $logStart = time() - $graphLength;
  170     }
  171     console_log("Configured start time to $logStart.");
  172 
  173     # Are we ready?
  174     console_log("Reading STDIN for logfile input.");
  175 
  176     foreach (<STDIN>) {
  177         # Increment line counter
  178         $lineCounter++;
  179 
  180         # Activity log
  181         #console_log("Read $lineCounter lines from STDIN.") if ($lineCounter%80000 == 0);
  182 
  183         # Split the line
  184         my @logParts = split(' ');
  185 
  186         # Check if lines are erroneous, i.e. incorrect number of parts
  187         if ($#logParts != 9) {
  188             $errorLines++;
  189             console_log("Invalid log data at line $lineCounter. Error #$errorLines.");
  190         }
  191 
  192         # Skip irrelevant lines
  193         elsif (($logParts[0] >= $logStart) && ($i < 288)) {
  194 
  195             # Gets the x value correct
  196             while ($logStart + (300 * ($i + 1)) < $logParts[0]) { $i++; }
  197 
  198             # Declare vars
  199             my $isTCP = 0;
  200             my $isUDP = 0;
  201             my $isHit = 0;
  202             my $isMiss = 0;
  203 
  204             # Is this a hit or miss?
  205             $isHit = 1 if ($logParts[3] =~ /HIT/);
  206             $isMiss = 1 if ($logParts[3] =~ /MISS/);
  207 
  208             # Protocol check
  209             if ($logParts[3] =~ /TCP/) { $isTCP = 1 if ($have_tcp); }
  210             elsif ($logParts[3] =~ /UDP/) { $isUDP = 1 if ($have_udp); }
  211 
  212             # Unknown protocol? Can't be!
  213             else {
  214                 $errorLines++;
  215                 console_log("Invalid log data at line $lineCounter. Error #$errorLines.");
  216             }
  217 
  218             # Collect data
  219             if ($isTCP) {
  220                 $tcpAccessTotal[$i]++;
  221                 $tcpTransferTotal[$i] += $logParts[4];
  222                 $tcpTimeTotal[$i] += $logParts[1]/1000;
  223                 if ($isHit) {
  224                     $tcpAccessHit[$i]++;
  225                     $tcpTransferHit[$i] += $logParts[4];
  226                     $tcpTimeHit[$i] += $logParts[1]/1000;
  227                     if ($logParts[3] =~ /IMS/) {
  228                         $tcpAccessIMS[$i]++;
  229                         $tcpTransferIMS[$i] += $logParts[4];
  230                     }
  231                 }
  232                 elsif ($isMiss) {
  233                     $tcpAccessMiss[$i]++;
  234                     $tcpTransferMiss[$i] += $logParts[4];
  235                     $tcpTimeMiss[$i] += $logParts[1]/1000;
  236                 }
  237             }
  238             elsif ($isUDP) {
  239                 $udpAccessTotal[$i]++;
  240                 $udpTransferTotal[$i] += $logParts[4];
  241                 $udpTimeTotal[$i] += $logParts[1]/1000;
  242                 if ($isHit) {
  243                     $udpAccessHit[$i]++;
  244                     $udpTransferHit[$i] += $logParts[4];
  245                     $udpTimeHit[$i] += $logParts[1]/1000;
  246                 }
  247                 elsif ($isMiss) {
  248                     $udpAccessMiss[$i]++;
  249                     $udpTransferMiss[$i] += $logParts[4];
  250                     $udpTimeMiss[$i] += $logParts[1]/1000;
  251                 }
  252             }
  253 
  254             # Undefine vars
  255             undef $isTCP;
  256             undef $isUDP;
  257             undef $isHit;
  258             undef $isMiss;
  259         }
  260 
  261         undef @logParts;
  262     }
  263 
  264     # Calculate transfer duration averages
  265     if ($have_transfer) {
  266         # Activity log
  267         console_log("Calculating averages for TCP/UDP transfer duration.");
  268 
  269         # Start looping
  270         my $i;
  271         for ($i = 0; $i < 288; $i++) {
  272             if ($have_tcp) {
  273                 $tcpTimeTotal[$i] = ($tcpAccessTotal[$i] == 0)?0:$tcpTimeTotal[$i]/$tcpAccessTotal[$i];
  274                 $tcpTimeHit[$i] = ($tcpAccessHit[$i] == 0)?0:$tcpTimeHit[$i]/$tcpAccessHit[$i];
  275                 $tcpTimeMiss[$i] = ($tcpAccessMiss[$i] == 0)?0:$tcpTimeMiss[$i]/$tcpAccessMiss[$i]; 
  276             }
  277             if ($have_udp) {
  278                 $udpTimeTotal[$i] = ($udpAccessTotal[$i] == 0)?0:$udpTimeTotal[$i]/$udpAccessTotal[$i];
  279                 $udpTimeHit[$i] = ($udpAccessHit[$i] == 0)?0:$udpTimeHit[$i]/$udpAccessHit[$i];
  280                 $udpTimeMiss[$i] = ($udpAccessMiss[$i] == 0)?0:$udpTimeMiss[$i]/$udpAccessMiss[$i];
  281             }
  282         }
  283         undef $i;
  284     }
  285 
  286     # Cumulate the data
  287     if ($have_cumulative) {
  288         # Activity log
  289         console_log("Cumulating log data for TCP/UDP graphs.");
  290 
  291         # Start looping
  292         my $i;
  293         for ($i = 0; $i < 288; $i++) {
  294             if ($have_tcp) {
  295                 $tcpAccessTotal[$i + 1] += $tcpAccessTotal[$i];
  296                 $tcpAccessHit[$i + 1] += $tcpAccessHit[$i];
  297                 $tcpAccessMiss[$i + 1] += $tcpAccessMiss[$i];
  298                 $tcpAccessIMS[$i + 1] += $tcpAccessIMS[$i];
  299                 $tcpTransferTotal[$i + 1] += $tcpTransferTotal[$i];
  300                 $tcpTransferHit[$i + 1] += $tcpTransferHit[$i];
  301                 $tcpTransferMiss[$i + 1] += $tcpTransferMiss[$i];
  302                 $tcpTransferIMS[$i + 1] += $tcpTransferIMS[$i];
  303             }
  304             if ($have_udp) {
  305                 $udpAccessTotal[$i + 1] += $udpAccessTotal[$i];
  306                 $udpAccessHit[$i + 1] += $udpAccessHit[$i];
  307                 $udpAccessMiss[$i + 1] += $udpAccessMiss[$i];
  308                 $udpTransferTotal[$i + 1] += $udpTransferTotal[$i];
  309                 $udpTransferHit[$i + 1] += $udpTransferHit[$i];
  310                 $udpTransferMiss[$i + 1] += $udpTransferMiss[$i];
  311             }
  312         }
  313         undef $i;
  314     }
  315 
  316     # Done parsing, now calculate some stats
  317     $duration = time() - $progStart;
  318     $duration = 1 if ($duration <= 0);
  319     $progSpeed = dec_truncate($lineCounter/$duration,2);
  320 
  321     # Do some console logging
  322     console_log("Done reading $lineCounter lines from logfile on STDIN. ($errorLines errors)");
  323     console_log("Analysis duration is $duration seconds, $progSpeed lines/sec.");
  324 
  325     # Create image objects
  326     if ($have_tcp) {
  327         console_log('Creating TCP image objects.');
  328         $tcpAccessImg = create_gd();
  329         $tcpTransferImg = create_gd();
  330         $tcpTimeImg = create_gd() if ($have_transfer);
  331     }
  332     if ($have_udp) {
  333         console_log('Creating UDP image objects.');
  334         $udpAccessImg = create_gd();
  335         $udpTransferImg = create_gd();
  336         $udpTimeImg = create_gd() if ($have_transfer);
  337     }
  338 
  339     # Plot the graphs
  340     my $c;
  341     my @nullArr;
  342     $c = 'C' if ($have_cumulative);
  343     if ($have_tcp) {
  344         console_log("Plotting graph of TCP accesses.");
  345         plot("TA$c", $logStart, $tcpAccessImg,@tcpAccessTotal,@tcpAccessHit,@tcpAccessMiss,@tcpAccessIMS);
  346         console_log("Plotting graph of TCP transfers.");
  347         plot("TX$c", $logStart, $tcpTransferImg,@tcpTransferTotal,@tcpTransferHit,@tcpTransferMiss,@tcpAccessIMS);
  348         if ($have_transfer) {
  349             console_log("Plotting graph of TCP transfer duration.");
  350             plot("TD", $logStart, $tcpTimeImg,@tcpTimeTotal,@tcpTimeHit,@tcpTimeMiss,@nullArr);
  351         }
  352     }
  353     if ($have_udp) {
  354         console_log("Plotting graph of UDP accesses.");
  355         plot("UA$c", $logStart, $udpAccessImg,@udpAccessTotal,@udpAccessHit,@udpTransferMiss,@nullArr);
  356         console_log("Plotting graph of UDP transfers.");
  357         plot("UX$c", $logStart, $udpTransferImg,@udpTransferTotal,@udpTransferHit,@udpTransferMiss,@nullArr);
  358         if ($have_transfer) {
  359             console_log("Plotting graph of UDP transfer duration.");
  360             plot("UD", $logStart, $udpTimeImg,@udpTimeTotal,@udpTimeHit,@udpTimeMiss,@nullArr);
  361         }
  362     }
  363     undef @nullArr;
  364     undef $c;
  365 
  366     # Graph plotted! Now we save it
  367     if ($have_tcp) {
  368         write_img($tcpAccessImg,'tcp-access.png');
  369         write_img($tcpTransferImg,'tcp-transfer.png');
  370         write_img($tcpTimeImg,'tcp-duration.png') if ($have_transfer);
  371     }
  372     if ($have_udp) {
  373         write_img($udpAccessImg,'udp-access.png');
  374         write_img($udpTransferImg,'udp-transfer.png');
  375         write_img($udpTimeImg,'udp-duration.png') if ($have_transfer);
  376     }
  377 
  378     # Time to gather additional statistics which are not on the graph :)
  379     console_log("Gathering additional statistics.");
  380 
  381     my $tcpAccessTotals = 0;
  382     my $tcpAccessAverage = 0;
  383 
  384     my $tcpAccessMissTotals = 0;
  385     my $tcpAccessMissPercentage = 0;
  386     my $tcpAccessMissAverage = 0;
  387 
  388     my $tcpAccessHitTotals = 0;
  389     my $tcpAccessHitPercentage = 0;
  390     my $tcpAccessHitAverage = 0;
  391 
  392     my $tcpAccessIMSTotals = 0;
  393     my $tcpAccessIMSPercentage = 0;
  394     my $tcpAccessIMSAverage = 0;
  395 
  396     my $tcpTransferTotals = 0;
  397     my $tcpTransferAverage = 0;
  398 
  399     my $tcpTransferHitTotals = 0;
  400     my $tcpTransferHitPercentage = 0;
  401     my $tcpTransferHitAverage = 0;
  402 
  403     my $tcpTransferMissTotals = 0;
  404     my $tcpTransferMissPercentage = 0;
  405     my $tcpTransferMissAverage = 0;
  406 
  407     my $tcpTransferIMSTotals = 0;
  408     my $tcpTransferIMSPercentage = 0;
  409     my $tcpTransferIMSAverage = 0;
  410 
  411     my $tcpTimeTotals = 0;
  412     my $tcpTimeAverage = 0;
  413     my $tcpTimeHitTotals = 0;
  414     my $tcpTimeHitAverage = 0;
  415     my $tcpTimeMissTotals = 0;
  416     my $tcpTimeMissAverage = 0;
  417 
  418     my $udpAccessTotals = 0;
  419     my $udpAccessAverage = 0;
  420 
  421     my $udpAccessMissTotals = 0;
  422     my $udpAccessMissPercentage = 0;
  423     my $udpAccessMissAverage = 0;
  424 
  425     my $udpAccessHitTotals = 0;
  426     my $udpAccessHitPercentage = 0;
  427     my $udpAccessHitAverage = 0;
  428 
  429     my $udpTransferTotals = 0;
  430     my $udpTransferAverage = 0;
  431 
  432     my $udpTransferMissTotals = 0;
  433     my $udpTransferMissPercentage = 0;
  434     my $udpTransferMissAverage = 0;
  435 
  436     my $udpTransferHitTotals = 0;
  437     my $udpTransferHitPercentage = 0;
  438     my $udpTransferHitAverage = 0;
  439 
  440     my $udpTimeTotals = 0;
  441     my $udpTimeAverage = 0;
  442     my $udpTimeHitTotals = 0;
  443     my $udpTimeHitAverage = 0;
  444     my $udpTimeMissTotals = 0;
  445     my $udpTimeMissAverage = 0;
  446 
  447 
  448     # Get the totals
  449 
  450     if ($have_cumulative) {
  451         if ($have_tcp) {
  452             $tcpAccessTotals = $tcpAccessTotal[$#tcpAccessTotal];
  453             $tcpAccessHitTotals = $tcpAccessHit[$#tcpAccessHit];
  454             $tcpAccessMissTotals = $tcpAccessMiss[$#tcpAccessMiss];
  455             $tcpAccessIMSTotals = $tcpAccessIMS[$#tcpAccessIMS];
  456 
  457             $tcpTransferTotals = $tcpTransferTotal[$#tcpTransferTotal];
  458             $tcpTransferHitTotals = $tcpTransferHit[$#tcpTransferHit];
  459             $tcpTransferMissTotals = $tcpTransferMiss[$#tcpTransferMiss];
  460             $tcpTransferIMSTotals = $tcpTransferIMS[$#tcpTransferIMS];
  461         }
  462         if ($have_udp) {
  463             $udpAccessTotals = $udpAccessTotal[$#udpAccessTotal];
  464             $udpAccessHitTotals = $udpAccessHit[$#udpAccessHit];
  465             $udpAccessMissTotals = $udpAccessMiss[$#udpAccessMiss];
  466 
  467             $udpTransferTotals = $udpTransferTotal[$#udpTransferTotal];
  468             $udpTransferHitTotals = $udpTransferHit[$#udpTransferHit];
  469             $udpTransferMissTotals = $udpTransferMiss[$#udpTransferMiss];
  470         }
  471 
  472     }
  473     else {
  474         my $i;
  475         for ($i = 0; $i < 288; $i++) {
  476             if ($have_tcp) {
  477                 $tcpAccessTotals += $tcpAccessTotal[$i];
  478                 $tcpAccessHitTotals += $tcpAccessHit[$i];
  479                 $tcpAccessMissTotals += $tcpAccessMiss[$i];
  480                 $tcpAccessIMSTotals += $tcpAccessIMS[$i];
  481 
  482                 $tcpTransferTotals += $tcpTransferTotal[$i];
  483                 $tcpTransferHitTotals += $tcpTransferHit[$i];
  484                 $tcpTransferMissTotals += $tcpTransferMiss[$i];
  485                 $tcpTransferIMSTotals += $tcpTransferIMS[$i];
  486 
  487                 if ($have_transfer) {
  488                     $tcpTimeTotals += $tcpTimeTotal[$i];
  489                     $tcpTimeHitTotals += $tcpTimeHit[$i];
  490                     $tcpTimeMissTotals += $tcpTimeMiss[$i];
  491                 }
  492             }
  493 
  494             if ($have_udp) {
  495                 $udpAccessTotals += $udpAccessTotal[$i];
  496                 $udpAccessHitTotals += $udpAccessHit[$i];
  497                 $udpAccessMissTotals += $udpAccessMiss[$i];
  498 
  499                 $udpTransferTotals += $udpTransferTotal[$i];
  500                 $udpTransferHitTotals += $udpTransferHit[$i];
  501                 $udpTransferMissTotals += $udpTransferMiss[$i];
  502 
  503                 if ($have_transfer) {
  504                     $udpTimeTotals += $udpTimeTotal[$i];
  505                     $udpTimeHitTotals += $udpTimeHit[$i];
  506                     $udpTimeMissTotals += $udpTimeMiss[$i];
  507                 }
  508             }
  509         }
  510         undef $i;
  511     }
  512 
  513     # Calculate averages and percentages
  514 
  515     sub percentage($$) {
  516         my $val = shift;
  517         my $tot = shift;
  518         return dec_truncate(($tot == 0)?0:(($val/$tot) * 100),2);
  519     };
  520 
  521     if ($have_tcp) {
  522             $tcpAccessAverage = dec_truncate($tcpAccessTotals/24,2);
  523             $tcpAccessHitAverage = dec_truncate($tcpAccessHitTotals/24,2);
  524             $tcpAccessMissAverage = dec_truncate($tcpAccessMissTotals/24,2);
  525             $tcpAccessIMSAverage = dec_truncate($tcpAccessIMSTotals/24,2);
  526 
  527             $tcpTransferAverage = hr_bytes($tcpTransferTotals/24);
  528             $tcpTransferHitAverage = hr_bytes($tcpTransferHitTotals/24);
  529             $tcpTransferMissAverage = hr_bytes($tcpTransferMissTotals/24);
  530             $tcpTransferIMSAverage = hr_bytes($tcpTransferIMSTotals/24);
  531 
  532             $tcpAccessHitPercentage = percentage($tcpAccessHitTotals,$tcpAccessTotals);
  533             $tcpAccessMissPercentage = percentage($tcpAccessMissTotals,$tcpAccessTotals);
  534 
  535             $tcpTransferHitPercentage = percentage($tcpTransferHitTotals,$tcpTransferTotals);
  536             $tcpTransferMissPercentage = percentage($tcpTransferMissTotals,$tcpTransferTotals);
  537 
  538             if ($have_transfer) {
  539                 $tcpTimeAverage = dec_truncate($tcpTimeTotals/288,2);
  540                 $tcpTimeHitAverage = dec_truncate($tcpTimeHitTotals/288,2);
  541                 $tcpTimeMissAverage = dec_truncate($tcpTimeMissTotals/288,2);
  542             }
  543     }
  544 
  545     if ($have_udp) {
  546             $udpAccessAverage = dec_truncate($udpAccessTotals/24,2);
  547             $udpAccessHitAverage = dec_truncate($udpAccessHitTotals/24,2);
  548             $udpAccessMissAverage = dec_truncate($udpAccessMissTotals/24,2);
  549 
  550             $udpTransferAverage = hr_bytes($udpTransferTotals/24);
  551             $udpTransferHitAverage = hr_bytes($udpTransferHitTotals/24);
  552             $udpTransferMissAverage = hr_bytes($udpTransferMissTotals/24);
  553 
  554             $udpAccessHitPercentage = percentage($udpAccessHitTotals,$udpAccessTotals);
  555             $udpAccessMissPercentage = percentage($udpAccessMissTotals,$udpAccessTotals);
  556 
  557             $udpTransferHitPercentage = percentage($udpTransferHitTotals,$udpTransferTotals);
  558             $udpTransferMissPercentage = percentage($udpTransferMissTotals,$udpTransferTotals);
  559 
  560             if ($have_transfer) {
  561                 $udpTimeAverage = dec_truncate($udpTimeTotals/288,2);
  562                 $udpTimeHitAverage = dec_truncate($udpTimeHitTotals/288,2);
  563                 $udpTimeMissAverage = dec_truncate($udpTimeMissTotals/288,2);
  564             }
  565     }
  566 
  567     # Some tiny date/time conversions
  568     my $progStartTime = localtime($progStart);
  569     my $logStartTime = localtime($logStart);
  570     my $logEndTime = localtime($logStart + 86400);
  571 
  572     # Colours
  573     my $bgcolor = "$color{'hbg'}[0]$color{'hbg'}[1]$color{'hbg'}[2]";
  574     my $fgcolor = "$color{'fg'}[0]$color{'fg'}[1]$color{'fg'}[2]";
  575     my $grcolor = "$color{'gr'}[0]$color{'gr'}[1]$color{'gr'}[2]";
  576     my $hitcolor = "$color{'hit'}[0]$color{'hit'}[1]$color{'hit'}[2]";
  577     my $misscolor = "$color{'miss'}[0]$color{'miss'}[1]$color{'miss'}[2]";
  578     my $imscolor = "$color{'ims'}[0]$color{'ims'}[1]$color{'ims'}[2]" if ($have_tcp);
  579 
  580     # Make some things more redable to the human eye
  581     if ($have_tcp) {
  582         $tcpAccessTotals = dec_truncate($tcpAccessTotals,2);
  583         $tcpAccessHitTotals = dec_truncate($tcpAccessHitTotals,2);
  584         $tcpAccessMissTotals = dec_truncate($tcpAccessMissTotals,2);
  585         $tcpAccessIMSTotals = dec_truncate($tcpAccessIMSTotals,2);
  586         $tcpTransferTotals = hr_bytes($tcpTransferTotals);
  587         $tcpTransferHitTotals = hr_bytes($tcpTransferHitTotals);
  588         $tcpTransferMissTotals = hr_bytes($tcpTransferMissTotals);
  589         $tcpTransferIMSTotals = hr_bytes($tcpTransferIMSTotals);
  590     }
  591     if ($have_udp) {
  592         $udpAccessTotals = dec_truncate($udpAccessTotals,2);
  593         $udpAccessHitTotals = dec_truncate($udpAccessHitTotals,2);
  594         $udpAccessMissTotals = dec_truncate($udpAccessMissTotals,2);
  595         $udpTransferTotals = hr_bytes($udpTransferTotals);
  596         $udpTransferHitTotals = hr_bytes($udpTransferHitTotals);
  597         $udpTransferMissTotals = hr_bytes($udpTransferMissTotals);
  598     }
  599 
  600 
  601     console_log("Writing index.html file.");
  602 
  603     open(IDX, ">$config{'output-dir'}/index.html") ||
  604         error("Can't write to file $config{'output-dir'}/index.html. Check directory permissions?");
  605 
  606     print IDX "<HTML>\n";
  607     print IDX "<HEAD>\n";
  608     print IDX "<TITLE>$title</TITLE>\n";
  609     print IDX "</HEAD>\n";
  610     print IDX "<BODY BGCOLOR=\"#$bgcolor\" TEXT=\"#$fgcolor\">\n";
  611     print IDX "<H1>$title</H1>\n";
  612     print IDX "<BR>\n";
  613 
  614     print IDX "<TABLE BORDER=0>\n";
  615     print IDX "<TR><TD><B>Generated:</B></TD><TD>$progStartTime</TD></TR>\n";
  616     print IDX "<TR><TD><B>Lines Analyzed:</B></TD><TD>$lineCounter lines ($errorLines errors)</TD></TR>\n";
  617     print IDX "<TR><TD><B>Analysis Duration:</B></TD><TD>$duration seconds</TD></TR>\n";
  618     print IDX "<TR><TD><B>Analysis Speed:</B></TD><TD>$progSpeed lines/sec</TD></TR>\n";
  619     print IDX "<TR><TD><B>Graph Start:</B></TD><TD>$logStartTime</TD></TR>\n";
  620     print IDX "<TR><TD><B>Graph End:</B></TD><TD>$logEndTime</TD></TR>\n";
  621     print IDX "<TR><TD><B>Graph Domain:</B></TD><TD>24 hours (86400 seconds)</TD></TR>\n";
  622     print IDX "</TABLE>\n";
  623 
  624     sub generate_html_row($$$) {
  625         my $color = shift;
  626         my $key = shift;
  627         my $value = shift;
  628         my $ret;
  629 
  630         $ret = "<TR>";
  631         $ret .= "<TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=#$color><B>$key:</B></FONT></TD>";
  632         $ret .= "<TD ALIGN=LEFT><FONT SIZE=-1>$value</FONT></TD>";
  633         $ret .= "</TR>\n";
  634 
  635         undef $color;
  636         undef $key;
  637         undef $value;
  638 
  639         return $ret;
  640     }
  641 
  642     if ($have_tcp) {
  643         print IDX "<BR><HR><BR>\n";
  644         print IDX "<H3>Graph of TCP Accesses (5 minute total)</H3>\n" if (!$have_cumulative);
  645         print IDX "<H3>Cumulative graph of TCP Accesses</H3>\n" if ($have_cumulative);
  646         print IDX "<TABLE BORDER=0>\n";
  647         print IDX "<TR>\n";
  648         print IDX "<TD><IMG SRC=tcp-access.png></TD>\n";
  649         print IDX "<TD>\n";
  650         print IDX "<TABLE BORDER=0>\n";
  651         print IDX generate_html_row($grcolor,"Total Accesses",$tcpAccessTotals);
  652         print IDX generate_html_row($grcolor,"Average Accesses","$tcpAccessAverage per hour");
  653         print IDX generate_html_row($hitcolor,"Total Cache Hits",$tcpAccessHitTotals);
  654         print IDX generate_html_row($hitcolor,"Average Cache Hits","$tcpAccessHitAverage per hour");
  655         print IDX generate_html_row($hitcolor,"% Cache Hits","$tcpAccessHitPercentage %");
  656         print IDX generate_html_row($imscolor,"Total Cache IMS Hits",$tcpAccessIMSTotals);
  657         print IDX generate_html_row($imscolor,"Average Cache IMS Hits","$tcpAccessIMSAverage per hour");
  658         print IDX generate_html_row($misscolor,"Total Cache Misses",$tcpAccessMissTotals);
  659         print IDX generate_html_row($misscolor,"Average Cache Misses","$tcpAccessMissAverage per hour");
  660         print IDX generate_html_row($misscolor,"% Cache Misses","$tcpAccessMissPercentage %");
  661         print IDX "</TABLE>\n";
  662         print IDX "</TD>\n";
  663         print IDX "</TR>\n";
  664         print IDX "</TABLE>\n";
  665         print IDX "<H3>Graph of TCP Transfers (5 minute total)</H3>\n" if (!$have_cumulative);
  666         print IDX "<H3>Cumulative graph of TCP Transfers</H3>\n" if ($have_cumulative);
  667         print IDX "<TABLE BORDER=0>\n";
  668         print IDX "<TR>\n";
  669         print IDX "<TD><IMG SRC=tcp-transfer.png></TD>\n";
  670         print IDX "<TD>\n";
  671         print IDX "<TABLE BORDER=0>\n";
  672         print IDX generate_html_row($grcolor,"Total Transfers",$tcpTransferTotals);
  673         print IDX generate_html_row($grcolor,"Average Transfers","$tcpTransferAverage per hour");
  674         print IDX generate_html_row($hitcolor,"Total Cache Hits",$tcpTransferHitTotals);
  675         print IDX generate_html_row($hitcolor,"Average Cache Hits","$tcpTransferHitAverage per hour");
  676         print IDX generate_html_row($hitcolor,"% Cache Hits","$tcpTransferHitPercentage %");
  677         print IDX generate_html_row($imscolor,"Total Cache IMS Hits",$tcpTransferIMSTotals);
  678         print IDX generate_html_row($imscolor,"Average Cache IMS Hits","$tcpTransferIMSAverage per hour");
  679         print IDX generate_html_row($misscolor,"Total Cache Misses",$tcpTransferMissTotals);
  680         print IDX generate_html_row($misscolor,"Average Cache Misses","$tcpTransferMissAverage per hour");
  681         print IDX generate_html_row($misscolor,"% Cache Misses","$tcpTransferMissPercentage %");
  682         print IDX "</TABLE>\n";
  683         print IDX "</TD>\n";
  684         print IDX "</TR>\n";
  685         print IDX "</TABLE>\n";
  686         if ($have_transfer) {
  687             print IDX "<H3>Graph of Average TCP Transfer Duration</H3>\n";
  688             print IDX "<TABLE BORDER=0>\n";
  689             print IDX "<TR>\n";
  690             print IDX "<TD><IMG SRC=tcp-duration.png></TD>\n";
  691             print IDX "<TD>\n";
  692             print IDX "<TABLE BORDER=0>\n";
  693             print IDX generate_html_row($grcolor,"Avg. Transfer Duration","$tcpTimeAverage seconds");
  694             print IDX generate_html_row($hitcolor,"Avg. Cache Hit Duration","$tcpTimeHitAverage seconds");
  695             print IDX generate_html_row($misscolor,"Avg. Cache Miss Duration","$tcpTimeMissAverage seconds");
  696             print IDX "</TABLE>\n";
  697             print IDX "</TD>\n";
  698             print IDX "</TR>\n";
  699             print IDX "</TABLE>\n";
  700         }
  701     }
  702 
  703     if ($have_udp) {
  704         print IDX "<BR><HR><BR>\n";
  705         print IDX "<H3>Graph of UDP Accesses (5 minute total)</H3>\n" if (!$have_cumulative);
  706         print IDX "<H3>Cumulative graph of UDP Accesses</H3>\n" if ($have_cumulative);
  707         print IDX "<TABLE BORDER=0>\n";
  708         print IDX "<TR>\n";
  709         print IDX "<TD><IMG SRC=udp-access.png></TD>\n";
  710         print IDX "<TD>\n";
  711         print IDX "<TABLE BORDER=0>\n";
  712         print IDX generate_html_row($grcolor,"Total Accesses",$udpAccessTotals);
  713         print IDX generate_html_row($grcolor,"Average Accesses","$udpAccessAverage per hour");
  714         print IDX generate_html_row($hitcolor,"Total Cache Hits",$udpAccessHitTotals);
  715         print IDX generate_html_row($hitcolor,"Average Cache Hits","$udpAccessHitAverage per hour");
  716         print IDX generate_html_row($hitcolor,"% Cache Hits","$udpAccessHitPercentage %");
  717         print IDX generate_html_row($misscolor,"Total Cache Misses",$udpAccessMissTotals);
  718         print IDX generate_html_row($misscolor,"Average Cache Misses","$udpAccessMissAverage per hour");
  719         print IDX generate_html_row($misscolor,"% Cache Misses","$udpAccessMissPercentage %");
  720         print IDX "</TABLE>\n";
  721         print IDX "</TD>\n";
  722         print IDX "</TR>\n";
  723         print IDX "</TABLE>\n";
  724         print IDX "<H3>Graph of UDP Transfers (5 minute total)</H3>\n" if (!$have_cumulative);
  725         print IDX "<H3>Cumulative graph of UDP Transfers</H3>\n" if ($have_cumulative);
  726         print IDX "<TABLE BORDER=0>\n";
  727         print IDX "<TR>\n";
  728         print IDX "<TD><IMG SRC=udp-transfer.png></TD>\n";
  729         print IDX "<TD>\n";
  730         print IDX "<TABLE BORDER=0>\n";
  731         print IDX generate_html_row($grcolor,"Total Transfers",$udpTransferTotals);
  732         print IDX generate_html_row($grcolor,"Average Transfers","$udpTransferAverage per hour");
  733         print IDX generate_html_row($hitcolor,"Total Cache Hits",$udpTransferHitTotals);
  734         print IDX generate_html_row($hitcolor,"Average Cache Hits","$udpTransferHitAverage per hour");
  735         print IDX generate_html_row($hitcolor,"% Cache Hits","$udpTransferHitPercentage %");
  736         print IDX generate_html_row($misscolor,"Total Cache Misses",$udpTransferMissTotals);
  737         print IDX generate_html_row($misscolor,"Average Cache Misses","$udpTransferMissAverage per hour");
  738         print IDX generate_html_row($misscolor,"% Cache Misses","$udpTransferMissPercentage %");
  739         print IDX "</TABLE>\n";
  740         print IDX "</TD>\n";
  741         print IDX "</TR>\n";
  742         print IDX "</TABLE>\n";
  743         if ($have_transfer) {
  744             print IDX "<H3>Graph of Average UDP Transfer Duration</H3>\n";
  745             print IDX "<TABLE BORDER=0>\n";
  746             print IDX "<TR>\n";
  747             print IDX "<TD><IMG SRC=udp-duration.png></TD>\n";
  748             print IDX "<TD>\n";
  749             print IDX "<TABLE BORDER=0>\n";
  750             print IDX generate_html_row($grcolor,"Avg. Transfer Duration","$udpTimeAverage seconds");
  751             print IDX generate_html_row($hitcolor,"Avg. Cache Hit Duration","$udpTimeHitAverage seconds");
  752             print IDX generate_html_row($misscolor,"Avg. Cache Miss Duration","$udpTimeMissAverage seconds");
  753             print IDX "</TABLE>\n";
  754             print IDX "</TD>\n";
  755             print IDX "</TR>\n";
  756             print IDX "</TABLE>\n";
  757         }
  758     }
  759 
  760     print IDX <<EOF;
  761 
  762 <BR>
  763 <HR>
  764 <BR>
  765 
  766 <A HREF="http://squid-graph.sourceforge.net/"><IMG SRC="logo.png" BORDER="0"></A>
  767 <BR>
  768 version $VER
  769 
  770 </BODY>
  771 
  772 </HTML>
  773 EOF
  774     close(IDX);
  775 
  776     console_log("Done.");
  777     console_log("Remember to copy logo.png found in your Squid Graph images/ directory to $config{'output-dir'}!");
  778 
  779 }
  780 
  781 # Error output
  782 sub error($) {
  783     my $LOG = shift;
  784     die "ERROR: $LOG Exiting.\n";
  785 }
  786 
  787 # Warning output
  788 sub warning($) {
  789     my $LOG = shift;
  790     print STDERR "WARNING: $LOG\n";
  791     undef $LOG;
  792 }
  793 
  794 # Just for console logging
  795 sub console_log($) {
  796     if ($CONSOLELOG) {
  797         my $TIME = localtime(time());
  798         my $LOG = shift;
  799         print "[$TIME] $LOG\n";
  800         undef $LOG;
  801     }
  802 }
  803 
  804 # Help
  805 sub help() {
  806 print <<EOF;
  807 
  808 Squid Graph $VER Help ($^O, perl $])
  809 
  810 Usage examples:
  811   squid-graph [options] < logfile.log
  812   cat logfile.log | squid-graph [options]
  813   tail -n 10000 logfile.log | squid-graph [options]
  814 
  815 Command line options (options marked * are compulsary):
  816 
  817     * --output-dir=output-dir (or -o=output-dir)
  818         Specifies the directory which stores the output files.
  819 
  820       --start=start-time (or -s=start-time)
  821         Specifies the graph start time in seconds since 1970.
  822         When not specified, 24 hours before the current time is
  823         used as default.
  824 
  825       --end=end-time (or -e=end-time)
  826         Specifies the graph end time in seconds since 1970.
  827         When not specified, the current time is used as default.
  828 
  829       --title="report-title"
  830         Specifies the report title. When not specified, "Squid
  831         Graph Logfile Analysis Report" is used as default.
  832 
  833       --tcp-only
  834         Specifies that only TCP access and transfer graphs are
  835         generated. When not specified, both TCP and UDP graphs
  836         are generated.
  837 
  838       --udp-only
  839         Specifies that only UDP access and transfer graphs are
  840         generated. When not specified, both TCP and UDP graphs
  841         are generated.
  842 
  843       --cumulative (or -c)
  844         Enables generation of cumulative graphs instead of the
  845         default histograms.
  846 
  847       --no-transfer-duration (or -d)
  848         Disables plotting of average transfer duration graph(s).
  849 
  850       --no-console-log (or -n)
  851         Disables logging of messages to console.
  852 
  853       --help (or -h)
  854         Displays this help message.
  855 
  856 For more info, please visit http://squid-graph.sourceforge.net/
  857 
  858 EOF
  859 exit;
  860 }
  861 
  862 # Parse command line arguments
  863 sub parse_argv() {
  864 
  865     # no arguments?
  866     if ($#ARGV == -1) {
  867         &help;
  868     }
  869 
  870     # scan command line arguments
  871     foreach (@ARGV) {
  872         my @parms = split(/=/);
  873 
  874         if (($parms[0] eq "--help") || ($parms[0] eq "-h")) {
  875             help();
  876         }
  877         elsif (($parms[0] eq "--no-console-log") || ($parms[0] eq "-n")) {
  878             $CONSOLELOG = 0;
  879         }
  880         elsif (($parms[0] eq "--output-dir") || ($parms[0] eq "-o")) {
  881             if ($parms[1] eq "") {
  882                 error("Output directory cannot be blank.");
  883             }
  884             elsif (-e $parms[1]) {
  885                 $config{'output-dir'} = $parms[1];
  886             }
  887             else {
  888                 error("Output directory $parms[1] does not exist.");
  889             }
  890         }
  891         elsif (($parms[0] eq "--start") || ($parms[0] eq "-s")) {
  892             if ($parms[1] eq "") {
  893                 warning("Starting time cannot be blank. Using defaults.");
  894             }
  895             else {
  896                 $config{'start'} = $parms[1];
  897             }
  898         }
  899         elsif (($parms[0] eq "--end") || ($parms[0] eq "-e")) {
  900             if ($parms[1] eq "") {
  901                 warning("End time cannot be blank. Using defaults.");
  902             }
  903             else {
  904                 $config{'end'} = $parms[1];
  905             }   
  906         }
  907         elsif ($parms[0] eq "--title") {
  908             if ($parms[1] eq "") {
  909                 warning("Title cannot be blank. Using defaults.");
  910             }
  911             else {
  912                 $config{'title'} = $parms[1];
  913             }
  914         }
  915         elsif ($parms[0] eq "--tcp-only") { $config{'tcp-only'} = 1; }
  916         elsif ($parms[0] eq "--udp-only") { $config{'udp-only'} = 1; }
  917         elsif (($parms[0] eq "--cumulative") || ($parms[0] eq "-c")) { $config{'cumulative'} = 1; }
  918         elsif (($parms[0] eq "--no-transfer-duration") || ($parms[0] eq "-d")) { $config{'no-transfer-duration'} = 1; }
  919         elsif (($parms[0] eq "--no-console-log") || ($parms[0] eq "-n")) { $CONSOLELOG = 0; }
  920         else {
  921             warning("Unknown argument $_ from command line.");
  922         }
  923 
  924         undef @parms;
  925     }
  926 }
  927 
  928 # Checks configuration validity
  929 sub config_check() {
  930     my $noerror = 1;
  931 
  932     if ($config{'output-dir'} eq "") {
  933         warning("Output directory not configured.");
  934         $noerror = 0;
  935     }
  936     else {
  937         # Remove trailing slash in output dir
  938         my $tmp = $config{'output-dir'};
  939         if (chop($tmp) eq "/") {
  940             chop($config{'output-dir'});
  941         }
  942     }
  943 
  944     if ((exists $config{'start'}) && (exists $config{'end'})) {
  945         warning("Cannot specify both --start and --end values. Use either --start OR --end.");
  946         $noerror = 0;
  947     }
  948 
  949     if ((exists $config{'udp-only'}) && (exists $config{'tcp-only'})) {
  950         warning("Both --udp-only and --tcp-only specified. Are you nuts? That's the default!");
  951         $noerror = 0;
  952     }
  953 
  954     if (($config{'output-dir'} =~ /^\/tmp/) ||
  955         ($config{'output-dir'} eq '.') ||
  956         ($config{'output-dir'} =~ /^\.\//) ||
  957         ($config{'output-dir'} =~ /^\/dev/)) {
  958         warning("Are you sure you want to output your files to \"$config{'output-dir'}\"? Continuing anyway...");
  959     }
  960 
  961     return $noerror;
  962 }
  963 
  964 # Create blank GD Images
  965 sub create_gd() {
  966     my $IMG;
  967     my $width = 370;
  968     my $height = 240;
  969     
  970     $IMG = new GD::Image($width,$height);
  971     $IMG->interlaced('true');
  972     $IMG->rectangle(0,0,$width-1,$height-1,
  973         $IMG->colorAllocate(hex($color{'bg'}[0]),hex($color{'bg'}[1]),hex($color{'bg'}[2])));
  974 
  975     undef $width;
  976     undef $height;
  977 
  978     return $IMG;
  979 }
  980 
  981 # Write images
  982 sub write_img($$) {
  983     my $IMG = shift;
  984     my $filename = shift;
  985 
  986     console_log("Writing to file $config{'output-dir'}/$filename");
  987     open(GD, ">$config{'output-dir'}/$filename") ||
  988         error("Cannot write to file $config{'output-dir'}/$filename. Check directory permissions?");
  989     binmode GD;
  990     print GD $IMG->png();
  991     close(GD);
  992 }
  993 
  994 sub plot($$\$\@\@\@\@) {
  995     my $type = shift;
  996     my $logStart = shift;
  997     my $imgRef = shift;
  998     my $totalRef = shift;
  999     my $hitRef = shift;
 1000     my $missRef = shift;
 1001     my $imsRef = shift;
 1002     my ($isTCP, $isUDP) = (0,0);
 1003     my $isCum = 0;
 1004     my ($width, $height) = $$imgRef->getBounds();
 1005     my $font = gdSmallFont;
 1006     my $fontWidth = $font->width();
 1007     my $fontHeight = $font->height();
 1008 
 1009     # Check type options
 1010     $isCum = 1 if ($type =~ /C/);
 1011     $isTCP = 1 if ($type =~ /T/);
 1012     $isUDP = 1 if ($type =~ /U/);
 1013 
 1014     # Colour tables
 1015     my $fgcolor   = $$imgRef->colorAllocate(hex($color{'fg'}[0]),hex($color{'fg'}[1]),hex($color{'fg'}[2]));
 1016     my $grcolor   = $$imgRef->colorAllocate(hex($color{'gr'}[0]),hex($color{'gr'}[1]),hex($color{'gr'}[2]));
 1017     my $hitcolor  = $$imgRef->colorAllocate(hex($color{'hit'}[0]),hex($color{'hit'}[1]),hex($color{'hit'}[2]));
 1018     my $misscolor = $$imgRef->colorAllocate(hex($color{'miss'}[0]),hex($color{'miss'}[1]),hex($color{'miss'}[2]));
 1019     my $imscolor  = $$imgRef->colorAllocate(hex($color{'ims'}[0]),hex($color{'ims'}[1]),hex($color{'ims'}[2]));
 1020 
 1021     # Dotted brush
 1022     $$imgRef->setStyle($fgcolor,gdTransparent,gdTransparent);
 1023 
 1024     #
 1025     # NOTES
 1026     #
 1027     # graph area w/h = 288/200
 1028     # graph area l/t = 62/20
 1029     # graph area eff = 62,20,350,220
 1030     #
 1031 
 1032     # Draw the border
 1033     $$imgRef->rectangle(0,0,$width-1,$height-1,$fgcolor);
 1034     
 1035     # Draw the title at the left side
 1036     my $title;
 1037     $title = "Cumulative " if ($isCum);
 1038     $title = "Average " if ($type =~ /D/);
 1039     $title .= "TCP " if ($isTCP);
 1040     $title .= "UDP " if ($isUDP);
 1041     $title .= "Accesses" if ($type =~ /A/);
 1042     $title .= "Transfers (bytes)" if ($type =~ /X/);
 1043     $title .= "Transfer Duration (secs)" if ($type =~ /D/);
 1044     my $titlewidth = ($fontWidth * length($title));
 1045     my $titlestart = ((($height - $titlewidth) / 2) + $titlewidth);
 1046     $$imgRef->stringUp($font,5,$titlestart,$title,$fgcolor);
 1047     undef $titlewidth;
 1048     undef $titlestart;
 1049     undef $title;
 1050 
 1051     # Determine the maximal and per pixel size of the graph
 1052     my ($graphMax) = sort {$b <=> $a} @$totalRef;
 1053     if ((sort {$b <=> $a} @$hitRef)[0] > $graphMax) {
 1054         $graphMax = (sort {$b <=> $a} @$hitRef)[0];
 1055     }
 1056     if ((sort {$b <=> $a} @$missRef)[0] > $graphMax) {
 1057         $graphMax = (sort {$b <=> $a} @$missRef)[0];
 1058     }
 1059     # Over-estimate max by 0.5%
 1060     $graphMax = ($graphMax < 1)?1:$graphMax * 1.05;
 1061     my $dotSize = $graphMax / 200;
 1062 
 1063     # Plot the graph
 1064     my $i;
 1065     my $lastTotalPos = 0;
 1066     my $lastHitPos = 0;
 1067     my $lastMissPos = 0;
 1068     my $lastIMSPos = 0;
 1069     for ($i = 0; $i < 288; $i++) {
 1070         my $totalPos = int($$totalRef[$i] / $dotSize);
 1071         my $hitPos = int($$hitRef[$i] / $dotSize);
 1072         my $missPos = int($$missRef[$i] / $dotSize);
 1073         my $imsPos;
 1074         $imsPos = int($$imsRef[$i] / $dotSize) if ($isTCP);
 1075 
 1076         # Draw in sequence. Drawing later will make line appear "on-top"
 1077         $$imgRef->line($i + 62, 219 - $lastIMSPos, $i + 63, 219 - $imsPos, $imscolor) if ($isTCP);
 1078         $$imgRef->line($i + 62, 219 - $lastMissPos, $i + 63, 219 - $missPos, $misscolor);
 1079         $$imgRef->line($i + 62, 219 - $lastHitPos, $i + 63, 219 - $hitPos, $hitcolor);
 1080         $$imgRef->line($i + 62, 219 - $lastTotalPos, $i + 63, 219 - $totalPos, $grcolor);
 1081         
 1082         $lastTotalPos = $totalPos;
 1083         $lastHitPos = $hitPos;
 1084         $lastMissPos = $missPos;
 1085         $lastIMSPos = $imsPos if ($isTCP);
 1086         undef $totalPos;
 1087         undef $hitPos;
 1088         undef $missPos;
 1089         undef $imsPos;
 1090     }
 1091     undef $i;
 1092     undef $lastTotalPos;
 1093     undef $lastHitPos;
 1094     undef $lastMissPos;
 1095     undef $lastIMSPos;
 1096 
 1097     # Draw the graph plotting area bounding boxes and quarter markings
 1098     $$imgRef->line(62,70,350,70,gdStyled);
 1099     $$imgRef->line(62,120,350,120,gdStyled);
 1100     $$imgRef->line(62,170,350,170,gdStyled);
 1101     $$imgRef->rectangle(62,20,350,220,$fgcolor);
 1102 
 1103     # Label the vertical (Y) axis
 1104     my $Q = $graphMax/4;
 1105     my $Q1 = hr_digits($graphMax,hr_units($graphMax));
 1106     my $Q2 = hr_digits($Q * 3,hr_units($graphMax));
 1107     my $Q3 = hr_digits($Q * 2,hr_units($graphMax));
 1108     my $Q4 = hr_digits($Q * 1,hr_units($graphMax));
 1109 
 1110     $$imgRef->string($font,58-(length($Q1)*$fontWidth),20-($fontHeight/2),"$Q1",$fgcolor);
 1111     $$imgRef->string($font,58-(length($Q2)*$fontWidth),70-($fontHeight/2),"$Q2",$fgcolor);
 1112     $$imgRef->string($font,58-(length($Q3)*$fontWidth),120-($fontHeight/2),"$Q3",$fgcolor);
 1113     $$imgRef->string($font,58-(length($Q4)*$fontWidth),170-($fontHeight/2),"$Q4",$fgcolor);
 1114 
 1115     $$imgRef->line(59,20,62,20,$fgcolor);
 1116     $$imgRef->line(59,70,62,70,$fgcolor);
 1117     $$imgRef->line(59,120,62,120,$fgcolor);
 1118     $$imgRef->line(59,170,62,170,$fgcolor);
 1119 
 1120     # Write down the max value
 1121     # The max was overestimated. We shall get it again.
 1122     my ($graphMax) = sort {$b <=> $a} @$totalRef;
 1123     if ((sort {$b <=> $a} @$hitRef)[0] > $graphMax) {
 1124         $graphMax = (sort {$b <=> $a} @$hitRef)[0];
 1125     }
 1126     if ((sort {$b <=> $a} @$missRef)[0] > $graphMax) {
 1127         $graphMax = (sort {$b <=> $a} @$missRef)[0];
 1128     }
 1129     $graphMax = dec_truncate($graphMax,1);
 1130     $$imgRef->string($font,350-(length("Max: $graphMax") * $fontWidth),(20-$fontHeight)/2+1,"Max: $graphMax",$fgcolor);
 1131 
 1132     undef $Q;
 1133     undef $Q1;
 1134     undef $Q2;
 1135     undef $Q3;
 1136     undef $Q4;
 1137 
 1138     undef $dotSize; 
 1139     undef $graphMax;
 1140 
 1141     # Label the horizontal (X) axis
 1142     my $i = 0;
 1143     my $alt = 0;
 1144     for ($i = 0; $i < 288; $i++) {
 1145         my ($sec, $min, $hour) = localtime($logStart + (300 * $i));
 1146         if (($min > 57) || ($min < 3)) {
 1147             $$imgRef->line(63 + $i, 20, 63 + $i, 220, gdStyled);
 1148             $$imgRef->line(63 + $i, 220, 63 + $i, 223, $fgcolor);
 1149             if ($alt) {
 1150                 $$imgRef->string($font,63+$i-((length($hour) * $fontWidth)/2),224,"$hour",$fgcolor);
 1151                 $alt = 0;
 1152             }
 1153             else { $alt = 1; }
 1154         }
 1155         undef $sec;
 1156         undef $min;
 1157         undef $hour;
 1158 
 1159     }
 1160 
 1161     undef $i;
 1162     undef $alt;
 1163 
 1164 
 1165     # Undefine all the vars used
 1166     undef $type;
 1167     undef $logStart;
 1168     undef $imgRef;
 1169     undef $totalRef;
 1170     undef $hitRef;
 1171     undef $missRef;
 1172     undef $imsRef;
 1173     undef $isTCP;
 1174     undef $isUDP;
 1175     undef $width;
 1176     undef $height;
 1177     undef $fgcolor;
 1178     undef $grcolor;
 1179     undef $hitcolor;
 1180     undef $misscolor;
 1181     undef $imscolor;
 1182 
 1183 }
 1184 
 1185 
 1186 sub dec_truncate($$) {
 1187     my $num = shift;
 1188     my $dp = shift;
 1189     if ($dp eq '') {
 1190         $dp = 1;
 1191     }
 1192     my $power = 10;
 1193     my $i = 0;
 1194     for ($i = 1; $i < $dp; $i++) {
 1195         $power = $power * 10;
 1196     }
 1197     return int($num * $power)/$power;
 1198 }
 1199 
 1200 sub comma_sep($) {
 1201     my $num = shift;
 1202     my $len = length($num);
 1203     my @str = split('', "$num");
 1204     my $val;
 1205     my $i;
 1206     for ($i = $len - 1; $i >= 0; $i--) {
 1207         if ((($len - $i - 1)%3 == 0) && ($i > 0) && ($i < $len - 1)) {
 1208             $val = "$str[$i]\,$val"
 1209         }
 1210         else {
 1211             $val = "$str[$i]$val";
 1212         }
 1213     }
 1214     undef $i;
 1215     undef $len;
 1216     undef $num;
 1217     undef @str;
 1218     return $val;
 1219 }
 1220 
 1221 sub hr_units($) {
 1222     my $num = shift;
 1223     if ($num >= 1000000000) {
 1224         return 'G';
 1225     }
 1226     elsif ($num >= 1000000) {
 1227         return 'M';
 1228     }
 1229     elsif ($num >= 1000) {
 1230         return 'K';
 1231     }
 1232     else {
 1233         return '';
 1234     }
 1235 }
 1236 
 1237 # hr_digits(int: $num, char: $units);
 1238 sub hr_digits($$) {
 1239     my $num = shift;
 1240     my $unit = shift;
 1241     my $val = dec_truncate($num,1);
 1242 
 1243     $val = dec_truncate($num/1000000000,1) if ($unit eq 'G');
 1244     $val = dec_truncate($num/1000000,1) if ($unit eq 'M');
 1245     $val = dec_truncate($num/1000,1) if ($unit eq 'K');
 1246 
 1247     return "$val$unit";
 1248 }
 1249 
 1250 sub hr_bytes($) {
 1251     my $num = shift;
 1252     my $val;
 1253     if ($num > 1000000000) {
 1254         $val = dec_truncate($num/1000000000,1);
 1255         return "$val Gb";
 1256     }
 1257     elsif ($num > 1000000) {
 1258         $val = dec_truncate($num/1000000,1);
 1259         return "$val Mb";
 1260     }
 1261     elsif ($num > 1000) {
 1262         $val = dec_truncate($num/1000,1);
 1263         return "$val Kb";
 1264     }
 1265     else {
 1266         $val = dec_truncate($num,1);
 1267         return "$val bytes";
 1268     }
 1269 }
 1270 
 1271 # Undefine "global" vars
 1272 undef %config;
 1273 undef %color;
 1274 undef $CONSOLELOG;
 1275 undef $VER;