"Fossies" - the Fresh Open Source Software Archive 
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;