#!/usr/bin/perl -w # Load modules use Switch; use IO::Seekable; use IO::Handle; # Init vars %logs = ('mx','/sonic-logs/mail/maillog.mx', 'mail','/sonic-logs/mail/maillog.mail', 'rad','/sonic-logs/radmon/today', 'dhcp','/sonic-logs/dhcpd/dhcpd.log', 'pop','/sonic-logs/mail/popper', 'pwd','/sonic-info/passwd-withgcos'); $match = 0; $lines = 0; $help = " Usage: dst [OPTIONS] [LOG] STRING Description: Looks through [LOG] for lines that contain STRING Behavior: -t Given log is tailed -f Follows the end of the file -w Searches for exact word matches -i Case insensitive search -v Display verbose options on script initiation -n [LINES] Implies tail, set number to lines to [LINES] LOG may include any of the following... mail(default) Parse $logs{'mail'} mx Parse $logs{'mx'} pop Parse $logs{'pop'} rad Parse $logs{'rad'} pwd Parse $logs{'pwd'} dhcp Parse $logs{'dhcp'} Miscellaneous: --help Displays this help \n\n\n"; # By default we will match anything $string = 'ANY'; # By default we don't tail the log $tail = 0; # By default we don't follow a growing log $follow = 0; # By default search is case sensitive $case = 1; # Default string (will be replaced by $string) $pattern = 'STRING'; # Do not show verbose output by default $verbose = 0; # Number of lines we're shooting to tail $tlines = 10000; # Our default log file $log = 'mail'; # Set our line length for default log $seek = -250; # As we go through arguments lets pay attention to which one we're looking at $key = 0; # Parse arguments if ($#ARGV > -1) { foreach (@ARGV) { switch ($_) { case '--help' { die($help) } # Parse flags case m/^-/ { if($_ =~ m/f/) { $follow = 1; } if($_ =~ m/n/) { if($ARGV[($key+1)] =~ m/[0-9]+/) { $tlines = $ARGV[($key+1)]; $tail = 1; } } if($_ =~ m/v/) { $verbose = 1; } if($_ =~ m/t/) { $tail = 1; } if($_ =~ m/i/) { $case = 0; } if($_ =~ m/v/) { $verbose = 1; } if($_ =~ m/w/) { $pattern = '[^a-zA-Z0-9_]STRING[^a-zA-Z0-9_]'; } } case /^mail$|^mx$|^rad$|^dhcp$|^pop$|^pwd$/ { # Pick a log to parse $log = $_; # Set byte value for a line in each log so we can seek back for our tail switch($_) { case 'mail' { $seek = -250; } case 'mx' { $seek = -250; } case 'rad' { $seek = -100; } case 'dhcp' { $seek = -200; } case 'pop' { $seek = -100; } case 'pwd' { $seek = -100; } } } # If the last argument isn't an option we'll search for it else { if($_ eq $ARGV[-1] & $_ ne $tlines) { $string = $_; } } } $key++; } } $pattern =~ s/STRING/$string/; if($string ne 'ANY') { print 'Checking for instances of "'.$string.'" in file "'.$logs{$log}.'"'; } if($verbose | $string ne 'ANY') { print "\nMatch Case: ".($case ? 'TRUE' : 'FALSE')."\nTailing log: ".($tail ? 'TRUE' : 'FALSE')."\nFollows log: ".($follow ? 'TRUE' : 'FALSE')."\nExact Match: ".($pattern eq $string ? 'FALSE' : 'TRUE'); } print "\n\n"; # Open log for parsing open(LOGF, $logs{$log}) || die 'Didn\'t work.'; # If we're tailing, go to tail position if($tail) { seek(LOGF,$seek*$tlines,SEEK_END) } FOLLOW: while () { if($tail) { $lines++; } if($string ne 'ANY') { if($case == 0) { if($_ =~ m/$pattern/i) { $match++; print $_; } } else { if($_ =~ m/$pattern/) { $match++; print $_; } } } else { print $_; } } # If we're following the file let's wait a couple seconds then clear EOF before continuing if($follow) { sleep(5); LOGF->clearer(); goto FOLLOW; } close(LOGF); if($string ne 'ANY') { print "\n\n".'Found '.$match.' instances of "'.$string.'" in file "'.$logs{$log}.'"'; } if($verbose | $string ne 'ANY') { print "\n\nMatch Case: ".($case ? 'TRUE' : 'FALSE')."\nTailing log: ".($tail ? $lines.' lines' : 'FALSE')."\nExact Match: ".($pattern eq $string ? 'FALSE' : 'TRUE')."\n\n"; } print "\n";