1 2######################################################## 3# Please file all bug reports, patches, and feature 4# requests under: 5# https://sourceforge.net/p/logwatch/_list/tickets 6# and copy: 7# Stefan Jakobs <logwatch at localside.net> 8# Help requests and discusion can be filed under: 9# https://sourceforge.net/p/logwatch/discussion/ 10######################################################## 11 12########################################################################### 13# This was written and is maintained by: 14# Stefan Jakobs <logwatch at localside.net> 15# 16# Please send all comments, suggestions, bug reports, 17# etc, to logwatch at localside.net. 18########################################################################### 19 20########################################################################### 21## Copyright (c) 2008-2013 Stefan Jakobs 22## Covered under the included MIT/X-Consortium License: 23## http://www.opensource.org/licenses/mit-license.php 24## All modifications and contributions by other persons to 25## this script are assumed to have been donated to the 26## Logwatch project and thus assume the above copyright 27## and licensing terms. If you want to make contributions 28## under your own copyright or a different license this 29## must be explicitly stated in the contribution an the 30## Logwatch project reserves the right to not accept such 31## contributions. If you have made significant 32## contributions to this script and want to claim 33## copyright please contact logwatch-devel@lists.sourceforge.net. 34######################################################### 35 36#use warnings; 37use strict; 38 39my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; 40my $Version = "1.4-20130219"; 41 42# initialize logwatch variables 43my $ThisLine = ""; 44my %OtherList = (); 45 46# initialize variables which save the stats 47my ($Starts,$Stops,$Reloads) = ( 0, 0, 0); 48my ($Perms,$FileOpenErrors) = ( 0, 0); 49my ($Drops, $WriteErrsSum) = ( 0, 0); 50my ($ExceedConns) = ( 0); 51my (%PermFiles, %OpenFiles) = ( (), ()); 52my (%WriteErrs, %Connections) = ( (), ()); 53my (%Conns, %ConnsSum) = (); 54my (%Stats_center, %Stats_source, %Stats_dest) = ( (), (), ()); 55my (%Stats_dropped, %Stats_supp, %Stats_global) = ( (), (), ()); 56my (%Stats_program, %Stats_stored, %Stats_net) = ( (), (), ()); 57my (%Stats_dropped_program, %Stats_supp_program) = ( (), ()); 58my (%Stats_dropped_net, %Stats_supp_net) = ( (), ()); 59my (%Warnings, %IntErrors) = ( (), ()); 60 61### Parse the lines ### 62 63while (defined($ThisLine = <STDIN>)) { 64 chomp($ThisLine); 65 66 #TD syslog-ng[2351]: New configuration initialized; 67 if ( ($ThisLine =~ /^[Nn]ew configuration initialized/ ) || 68 ($ThisLine =~ /^EOF on control channel, closing connection;/ ) || 69 ($ThisLine =~ /^(?:POLLERR|EOF) occurred while idle;/ ) 70 ) { 71 #ignore 72 } 73 74 #TD syslog-ng[9754]: Changing permissions on special file /dev/xconsole 75 elsif ($ThisLine =~ /^Changing permissions on special file ((\/[a-zA-Z0-9_]*)*)$/) { 76 %PermFiles = (%PermFiles, $1 => $PermFiles{$1}+1); 77 $Perms++; 78 } 79 80 #TD syslog-ng[9754]: Cannot open file /tmp/.adir/afile for writing (No such file or directory) 81 elsif ($ThisLine =~ /^Cannot open file ((\/[a-zA-Z0-9_.]*)*) .*/) { 82 # $1 fq file name, $2 only filename 83 %OpenFiles = (%OpenFiles, $1 => $OpenFiles{$1}+1); 84 $FileOpenErrors++; 85 } 86 87 #TD syslog-ng[9754]: SIGHUP received, restarting syslog-ng 88 #TD syslog-ng[4027]: Configuration reload request received, reloading configuration; 89 elsif ($ThisLine =~ /^SIGHUP received, restarting syslog-ng$/ || 90 $ThisLine =~ /^Configuration reload request received, reloading configuration;/) { 91 $Reloads++; 92 } 93 94 #TD syslog-ng[9754]: syslog-ng version 1.6.2 starting 95 #TD syslog-ng[3956]: syslog-ng starting up; version='2.0.9' 96 elsif ($ThisLine =~ /^syslog-ng version [\d.]+ starting$/ || 97 $ThisLine =~ /^syslog-ng starting up; version='[\d.]+'$/) { 98 $Starts++; 99 } 100 101 #TD syslog-ng[9754]: syslog-ng version 1.6.2 going down 102 #TD syslog-ng[20043]: syslog-ng shutting down; version='2.0.9' 103 elsif ($ThisLine =~ /^syslog-ng version [\d.]+ going down$/ || 104 $ThisLine =~ /^syslog-ng shutting down; version='[\d.]+'$/) { 105 $Stops++; 106 } 107 108 #TD syslog-ng[20043]: Termination requested via signal, terminating; 109 elsif ($ThisLine =~ /^Termination requested via signal, terminating;/) { 110 # happens with shutdown, but it's not for extra accounting 111 } 112 113 # syslog-ng v1.X 114 #TD syslog-ng[4833]: STATS: dropped 0 115 elsif ($ThisLine =~ /^STATS: dropped ([0-9]*)$/) { 116 if ($1 != 0) { $Drops = $Drops + $1; } 117 } 118 119 #TD syslog-ng[4833]: Syslog connection closed; fd='45', client='AF_INET(192.168.1.1:40280)', local='AF_INET(192.168.1.10:625)' 120 #TD syslog-ng[4833]: Syslog connection accepted; fd='52', client='AF_INET(192.168.1.1:40280)', local='AF_INET(192.168.1.10:625)' 121 # syslog-ng v3.X 122 #TD Syslog connection broken; fd='63', server='AF_INET(192.169.1.1:514)', time_reopen='60' : 44 Time(s) 123 #TD Syslog connection established; fd='48', server='AF_INET(192.168.1.1:514)', local='AF_INET(0.0.0.0:0)' 124 elsif ($ThisLine =~ /^Syslog connection (\S+); fd='\d+', (server|client)='AF_INET\(([.\d]+):\d+\)', (?:local='AF_INET\(([.\d]+:\d+)\)'|time_reopen='\d+')?$/) { 125 my $loc = defined($4) ? $4 : '0.0.0.0'; 126 $Connections{"$1 ($2)"}{$loc}{$3}++; 127 } 128 129 #TD syslog-ng[4833]: Connection broken to AF_INET(XXX.YYY.ZZZ.AAA:BBB), reopening in 60 seconds 130 elsif ($ThisLine =~ /^Connection broken to [A-Z_]*\((([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5})\), reopening in [0-9]* seconds$/) { 131 $Conns{'Connection broken'}{$1}++; 132 $ConnsSum{'Connection broken'}++; 133 } 134 135 # syslog-ng v2.X 136 #TD syslog-ng[4833]: Connection failed; error='Connection timed out (110)', time_reopen='60' 137 #TD syslog-ng[4833]: Connection failed; error='Connection refused (111)', time_reopen='60' 138 #TD syslog-ng[4833]: Connection broken; time_reopen='60' 139 elsif ($ThisLine =~ /^(Connection \w+); (?:error='([^\(']+) \(\d+\)', )?time_reopen='\d+'/ ) { 140 $Conns{$1}{$2}++; 141 $ConnsSum{$1}++; 142 } 143 144 #TD syslog-ng[4869]: io.c: do_write: write() failed (errno 111), Connection refused 145 #TD syslog-ng[4869]: I/O error occurred while writing; fd='66', error='Connection refused (111)' 146 elsif ( ($ThisLine =~ /^io\.c: do_write: write\(\) failed \(errno ([\d]+)\)/) or 147 ($ThisLine =~ /I\/O error occurred while writing; fd='\d+', error='[^'(]+ \((\d+)\)'/) 148 ) { 149 $WriteErrs{$1}++; 150 $WriteErrsSum++; 151 } 152 153 # Log statistics from syslog-ng v2.X 154 #TD syslog-ng[4883]: Log statistics; dropped='program(/path/to/p)=12', 155 # processed='center(queued)=1717', processed='center(received)=916', ... 156 # suppressed='program(/path/to/p)=0' 157 # Log statisctics from syslog-ng v3.X 158 #TD syslog-ng[1625]: Log statistics; processed='destination(newsnotice)=0', 159 # processed='center(queued)=0', processed='src.internal(src#0)=7', 160 # stamp='src.internal(src#0)=1283808150', processed='global(msg_clones)=0', ... 161 elsif ($ThisLine =~ /^Log statistics; /) { 162 my @processed = 163 $ThisLine =~ /processed='([a-z.]*)\((\S*)\)=([0-9]*)'/g; 164 for (my $i=0; $i<@processed; $i=$i+3) 165 { 166 if ($processed[$i] eq "center") { 167 $Stats_center{$processed[$i+1]} = 168 $Stats_center{$processed[$i+1]} + $processed[$i+2]; 169 } elsif ($processed[$i] eq "destination") { 170 $Stats_dest{$processed[$i+1]} = 171 $Stats_dest{$processed[$i+1]} + $processed[$i+2]; 172 } elsif ($processed[$i] eq "source" || $processed[$i] eq "src.internal" || 173 $processed[$i] eq 'src.none' || $processed[$i] eq 'src.journald') { 174 $Stats_source{$processed[$i+1]} = 175 $Stats_source{$processed[$i+1]} + $processed[$i+2]; 176 } elsif ($processed[$i] eq "global") { 177 $Stats_global{$processed[$i+1]} = 178 $Stats_global{$processed[$i+1]} + $processed[$i+2]; 179 } elsif ($processed[$i] eq "dst.program") { 180 $Stats_program{$processed[$i+1]} = 181 $Stats_program{$processed[$i+1]} + $processed[$i+2]; 182 } elsif ($processed[$i] =~ /(?:dst\.)?(?:udp|tcp)/) { 183 $Stats_net{$processed[$i+1]} = 184 $Stats_net{$processed[$i+1]} + $processed[$i+2]; 185 } else { chomp($ThisLine); $OtherList{$ThisLine}++; } 186 } 187 my @dropped = 188 $ThisLine =~ /dropped='([a-z.]*)\((\S*)\)=([0-9]*)'/g; 189 for (my $i=0; $i<@dropped; $i=$i+3) 190 { 191 if ($dropped[$i] eq "program" || $dropped[$i] eq "pipe") { 192 if ($dropped[$i+2] > 0) { 193 $Stats_dropped{$dropped[$i+1]} = 194 $Stats_dropped{$dropped[$i+1]} + $dropped[$i+2]; 195 } 196 } elsif ($dropped[$i] =~ /(?:dst\.)?(?:tcp|udp)/) { 197 if ($dropped[$i+2] > 0) { 198 $Stats_dropped_net{$dropped[$i+1]} = 199 $Stats_dropped_net{$dropped[$i+1]} + $dropped[$i+2]; 200 } 201 } elsif ($dropped[$i] eq "dst.program") { 202 if ($dropped[$i+2] > 0) { 203 $Stats_dropped_program{$dropped[$i+1]} = 204 $Stats_dropped_program{$dropped[$i+1]} + $dropped[$i+2]; 205 } 206 } else { chomp($ThisLine); $OtherList{$ThisLine}++; } 207 } 208 my @suppressed = 209 $ThisLine =~ /suppressed='([a-z.]*)\((\S*)\)=([0-9]*)'/g; 210 for (my $i=0; $i<@suppressed; $i=$i+3) 211 { 212 if ($suppressed[$i] eq "program" || $suppressed[$i] eq "pipe") { 213 if ($suppressed[$i+2] > 0) { 214 $Stats_supp{$suppressed[$i+1]} = 215 $Stats_supp{$suppressed[$i+1]} + $suppressed[$i+2]; 216 } 217 } elsif ($suppressed[$i] =~ /(?:dst\.)?(?:tcp|udp)/) { 218 if ($suppressed[$i+2] > 0) { 219 $Stats_supp_net{$suppressed[$i+1]} = 220 $Stats_supp_net{$suppressed[$i+1]} + $suppressed[$i+2]; 221 } 222 } elsif ($suppressed[$i] eq "dst.program") { 223 if ($suppressed[$i+2] > 0) { 224 $Stats_supp_program{$suppressed[$i+1]} = 225 $Stats_supp_program{$suppressed[$i+1]} + $suppressed[$i+2]; 226 } 227 } else { chomp($ThisLine); $OtherList{$ThisLine}++; } 228 } 229 my @stored = 230 $ThisLine =~ /stored='([a-z.]*)\((\S*)\)=([0-9]*)'/g; 231 for (my $i=0; $i<@stored; $i=$i+3) 232 { 233 if ($stored[$i] =~ "(?:dst\.)?(?:program|tcp|udp)" || $stored[$i] eq "pipe") { 234 if ($stored[$i+2] > 0) { 235 $Stats_stored{$stored[$i+1]} = 236 $Stats_stored{$stored[$i+1]} + $stored[$i+2]; 237 } 238 } else { chomp($ThisLine); $OtherList{$ThisLine}++; } 239 } 240 } 241 242 # syslog-ng v2.X 243 #TD syslog-ng[1796]: Number of allowed concurrent connections exceeded; num='10', max='10' 244 elsif ($ThisLine =~ /^Number of allowed concurrent connections exceeded/) { 245 $ExceedConns++; 246 } 247 248 # syslog-ng v3.X 249 #TD syslog-ng[1601]: WARNING: global: the default value of chain_hostnames is changing to 250 # 'no' in version 3.0, please update your configuration accordingly; 251 #TD syslog-ng[1601]: WARNING: you are using the pipe driver, underlying file is not a 252 # FIFO, it should be used by file(); filename='/dev/tty10' 253 elsif ($ThisLine =~ /^WARNING: (.*)$/) { 254 $Warnings{$1}++; 255 } 256 # syslog-ng v3.X 257 #TD syslog-ng[1601]: Configuration file has no version number, assuming ... 258 elsif ($ThisLine =~ /(Configuration file has no version number)/) { 259 $Warnings{$1}++; 260 } 261 262 # syslog-ng v2.X 263 #TD syslog-ng[1602]: Error initializing new configuration, reverting to old config; 264 elsif ($ThisLine =~ /^Error initializing new configuration, reverting to old config;/) { 265 $IntErrors{"Error initializing new configuration"}{"reverting to old config"}++; 266 } 267 268 #TD syslog-ng[2550]: Internal error, duplicate configuration elements refer to 269 # the same persistent config; name='afsocket_sd_connections(dgram,AF_INET(0.0.0.0:514))' 270 elsif ($ThisLine =~ /Internal error, ([^;]*); name='([^']*)'/) { 271 $IntErrors{$1}{$2}++; 272 } 273 274 # syslog-ng v2.X 275 #TD syslog-ng[20709]: Referenced filter rule not found; rule='f_dhcpd' 276 elsif ($ThisLine =~ /(Referenced filter rule not found); (.+)/) { 277 $IntErrors{$1}{$2}++ 278 } 279 280 # syslog-ng v2.X 281 #TD syslog-ng[2000]: Error in configuration, unresolved filter reference; filter='f_host_dhcp_dns0' 282 elsif ($ThisLine =~ /^Error in configuration, ([^;]+); (.+)/) { 283 $IntErrors{$1}{$2}++; 284 } 285 286 else { 287 # Report any unmatched entries... 288 chomp($ThisLine); 289 $OtherList{$ThisLine}++; 290 } 291} 292 293### generate the output ### 294 295if ($Starts) { 296 printf "\n%-48s %5i Time(s)", "Syslog-ng started:", $Starts; 297} 298 299if ($Stops) { 300 printf "\n%-48s %5i Time(s)", "Syslog-ng stopped:", $Stops; 301} 302 303if ($Reloads) { 304 printf "\n%-48s %5i Time(s)", "Syslog-ng reloaded:", $Reloads; 305} 306if ($Starts || $Stops || $Reloads) { print "\n"; } 307 308if ($Perms) { 309 if ($Detail >= 5) { 310 print "\nSyslog-ng changed the permission on the file(s):"; 311 foreach my $file (keys %PermFiles) { 312 printf "\n\t%-41s %5i Time(s)", $file, $PermFiles{$file}; 313 } 314 print "\n"; 315 } else { 316 printf "\n$-48s %5i Time(s)\n", "Syslog-ng changed permission on file(s):", $Perms; 317 } 318} 319 320if ($FileOpenErrors) { 321 if ($Detail >= 5) { 322 print "\nSyslog-ng could not open the file(s):"; 323 foreach my $file (keys %OpenFiles) { 324 printf "\n\t%-41s %5i Time(s)", $file, $OpenFiles{$file}; 325 } 326 print "\n"; 327 } else { 328 printf "\n%-48s %5i Time(s)\n", "Syslog-ng could not open file:", $FileOpenErrors; 329 } 330} 331 332if (keys %Conns) { 333 foreach my $cat (keys %Conns) { 334 if ($Detail >= 5) { 335 print "\n$cat:"; 336 foreach my $IP (keys %{$Conns{$cat}}) { 337 printf "\n\t%-41s %5i Time(s)", $IP, $Conns{$cat}{$IP}; 338 } 339 print "\n"; 340 } else { 341 printf "\n%-48s %5i Time(s)\n", "$cat:", $ConnsSum{$cat}; 342 } 343 } 344} 345 346if (keys %WriteErrs) { 347 if ($Detail >= 5) { 348 print "\nWrite Error(s):"; 349 foreach my $err (keys %WriteErrs) { 350 printf "\n\t%-41s %5i Time(s)", "Error Number $err:", $WriteErrs{$err}; 351 } 352 print "\n"; 353 } else { 354 printf "\n%-48s %5i Time(s)\n", "Write Error(s):", $WriteErrsSum; 355 } 356} 357 358if ($ExceedConns && $Detail >= 5) { 359 printf "\n%-48s %5i Time(s)\n", "Concurrent Connections Exceeded:", $ExceedConns; 360} 361 362if (keys %Stats_center || keys %Stats_dest || keys %Stats_source || 363 keys %Stats_dropped || keys %Stats_supp || keys %Stats_global || 364 keys %Stats_stored || keys %Stats_program || keys %Stats_net) { 365 my ($lost_rcvd, $lost_dest) = ( 0, 0); 366 367 if ($Stats_center{received} && %Stats_source) { 368 $lost_rcvd = 0 - $Stats_center{received}; 369 map { 370 # skip 'src#X' as this seams to be aggregated into 'src' 371 # skip 'journal' as this is not counted. 372 $lost_rcvd = $lost_rcvd + $Stats_source{$_} unless ($_ =~ /(?:src#\d+|journal)/); 373 } keys %Stats_source; 374 } 375 if ($Stats_center{queued} && %Stats_dest) { 376 $lost_dest = $Stats_center{queued}; 377 map { $lost_dest = $lost_dest - $Stats_dest{$_} } keys %Stats_dest; 378 } 379 380 if ($Detail >= 6) { print "\nLog Statistics:"; } 381 if ($lost_rcvd != 0 || $lost_dest != 0) { 382 if ($lost_rcvd != 0) { 383 if ($Detail >= 5) { 384 print "\n- Failed to receive $lost_rcvd message(s)!"; 385 } 386 } 387 if ($lost_dest != 0) { 388 if ($Detail >= 5 ) { 389 print "\n- Failed to save $lost_dest message(s) in logfile(s)!"; 390 } else { $Drops = $Drops + $lost_dest; } 391 } 392 if ($Detail >= 5) { print "\n"; } 393 } 394 395 if ($Detail >= 6) { 396 if (keys %Stats_center) { 397 print "\nCenter:"; 398 foreach my $center (sort {$a cmp $b} keys %Stats_center) { 399 printf "\n\t%-34s %12i", $center, $Stats_center{$center}; 400 } 401 } 402 if (keys %Stats_dest) { 403 print "\nDestination:"; 404 foreach my $dest (sort {$a cmp $b} keys %Stats_dest) { 405 printf "\n\t%-34s %12i", $dest, $Stats_dest{$dest}; 406 } 407 } 408 if (keys %Stats_source) { 409 print "\nSource:"; 410 foreach my $source (sort {$a cmp $b} keys %Stats_source) { 411 printf "\n\t%-34s %12i", $source, $Stats_source{$source}; 412 } 413 } 414 if (keys %Stats_net) { 415 print "\nNetwork:"; 416 foreach my $source (sort {$a cmp $b} keys %Stats_net) { 417 (my $short_source) = ($source =~ /,?([^,]*)/); 418 printf "\n\t%-34s %12i", $short_source, $Stats_net{$source}; 419 } 420 } 421 if (keys %Stats_program) { 422 print "\nProgram:"; 423 foreach my $source (sort {$a cmp $b} keys %Stats_program) { 424 (my $short_source) = ($source =~ /,?([^,]*)/); 425 printf "\n\t%-34s %12i", $short_source, $Stats_program{$source}; 426 } 427 } 428 if (keys %Stats_supp) { 429 print "\nSuppressed:"; 430 foreach my $source (sort {$a cmp $b} keys %Stats_supp) { 431 printf "\n\t%-34s %12i", $source, $Stats_supp{$source}; 432 } 433 } 434 if (keys %Stats_supp_net) { 435 print "\nSuppressed(net):"; 436 foreach my $source (sort {$a cmp $b} keys %Stats_supp_net) { 437 printf "\n\t%-34s %12i", $source, $Stats_supp_net{$source}; 438 } 439 } 440 if (keys %Stats_supp_program) { 441 print "\nSuppressed(program):"; 442 foreach my $source (sort {$a cmp $b} keys %Stats_supp_program) { 443 printf "\n\t%-34s %12i", $source, $Stats_supp_program{$source}; 444 } 445 } 446 if (keys %Stats_stored) { 447 print "\nStored:"; 448 foreach my $source (sort {$a cmp $b} keys %Stats_stored) { 449 (my $short_source) = ($source =~ /,?([^,]*)/); 450 printf "\n\t%-34s %12i", $short_source, $Stats_stored{$source}; 451 } 452 } 453 if (keys %Stats_global) { 454 print "\nGlobal:"; 455 foreach my $source (sort {$a cmp $b} keys %Stats_global) { 456 printf "\n\t%-34s %12i", $source, $Stats_global{$source}; 457 } 458 } 459 } 460 if (keys %Stats_dropped) { 461 print "\nDropped:"; 462 foreach my $source (sort {$a cmp $b} keys %Stats_dropped) { 463 printf "\n\t%-34s %12i", $source, $Stats_dropped{$source}; 464 } 465 } 466 if (keys %Stats_dropped_net) { 467 print "\nDropped(net):"; 468 foreach my $source (sort {$a cmp $b} keys %Stats_dropped_net) { 469 printf "\n\t%-34s %12i", $source, $Stats_dropped_net{$source}; 470 } 471 } 472 if (keys %Stats_dropped_program) { 473 print "\nDropped(program):"; 474 foreach my $source (sort {$a cmp $b} keys %Stats_dropped_program) { 475 printf "\n\t%-34s %12i", $source, $Stats_dropped_program{$source}; 476 } 477 } 478 if (keys %Stats_center or keys %Stats_dropped or keys %Stats_dropped_net or 479 keys %Stats_dropped_program) { 480 print "\n"; 481 } 482} 483 484if (keys %Connections) { 485 foreach my $state (sort {$a cmp $b} keys %Connections) { 486 my $sum = 0; 487 print "\nConnections $state: "; 488 print "\n" if $Detail > 2; 489 foreach my $localip (sort {$a cmp $b} keys %{$Connections{$state}}) { 490 print " $localip: " if $Detail > 2; 491 print "\n" if $Detail > 5; 492 my $sum_pro_ip = 0; 493 foreach my $extip (sort {$a cmp $b} keys %{$Connections{$state}{$localip}}) { 494 print "\t$extip : $Connections{$state}{$localip}{$extip} Time(s)\n" if $Detail > 5; 495 $sum = $sum + $Connections{$state}{$localip}{$extip}; 496 $sum_pro_ip = $sum_pro_ip + $Connections{$state}{$localip}{$extip}; 497 } 498 print "$sum_pro_ip\n" if $Detail > 2 and $Detail <= 5; 499 } 500 print "$sum\n" if $Detail <= 2; 501 } 502} 503 504if ($Drops) { 505 print "\nSyslog-ng dropped " . $Drops ." line(s)\n"; 506} 507 508if (keys %IntErrors) { 509 print "\nInternal Errors:"; 510 foreach my $class (sort {$a cmp $b} keys %IntErrors) { 511 print "\n $class"; 512 foreach my $error (sort {$a cmp $b} keys %{$IntErrors{$class}}) { 513 printf "\n\t%-41s %5i Time(s)", "$error:", $IntErrors{$class}{$error}; 514 } 515 } 516 print "\n"; 517} 518 519if (keys %Warnings) { 520 print "\nWarnings:"; 521 foreach my $warning (keys %Warnings) { 522 printf "\n\t%-41s %5i Time(s)", "$warning:", $Warnings{$warning}; 523 } 524 print "\n"; 525} 526 527if (keys %OtherList) { 528 print "\n**** Unmatched entries ****\n"; 529 foreach my $Error (keys %OtherList) { 530 print " $Error : $OtherList{$Error} Time(s)\n"; 531 } 532} 533 534### return without a failure ### 535exit(0); 536 537# vi: shiftwidth=3 tabstop=3 syntax=perl et 538 539