#!/opt/bin/perl # Josh's Log Processor by josh@hitchhiker.org # (C) 1998 Josh Wilmes, all rights reserved # Note: Need to handle "last message repeated n times" messages! $|=1; $domain="sky.net"; my ($configfile)=@ARGV; my $syslogpid="/etc/syslog.pid"; print ":: Loggo Logfile Processor (version 1.2) by Josh Wilmes\n"; print ":: " . localtime(time) . "\n\n"; open (C,"<$configfile") || die "can't open $configfile"; print ":: Reading $configfile\n"; while (!eof(C)) { $_=; # Ignore comments s/#.*$//g; # Ignore blank lines if (/^\s*$/) { next; } ($logfile)=/\s*(\S+)/; # remove the token from the $_ s/$logfile//; # OK, we have the block start token, we now scan for the beginning {. while(!eof(C)) { # Ignore comments s/#.*$//g; # Skip blank lines if (/^\s*$/) { $_=;next; } # Have we found the {? if (/{/) { s/{//g; last; } $_=; } while (!eof(C)) { # Ignore comments s/#.*$//g; # Skip blank lines if (/^\s*$/) { $_=; next; } $done=0; if (/}/) { $done=1; s/}//g; } if (/^\s*discard/) { s/discard//; ($regexp)=/^\s*(\S.*)$/; $regexp =~ s/\s*$//g; push (@{$code{$logfile}},"if (/$regexp/) { next; }\n"); } if (/^\s*alert/) { s/alert//; ($regexp)=/^\s*(\S.*)$/; $regexp =~ s/\s*$//g; push (@{$code{$logfile}},"if (/$regexp/) { alert(\$_); next; }\n"); } if (/^\s*groupcount\s+/) { s/groupcount//; ($countthing,$regexp)=/^\s*(\S+)\s+(\S.*)$/; $regexp =~ s/\s*$//g; push (@{$code{$logfile}},"if (/$regexp/) {\n "); push (@{$code{$logfile}}," (\$countre)=/$regexp/; if (\$countre =~ /$domain/) { \$countre=\"Inside $domain\"; }\n"); push (@{$code{$logfile}}," \$groupcount{\"$logfile\"}{\"\$host/\$service $countthing \$countre\"}++; next;\n}\n"); } if (/^\s*name\s+/) { s/name//; ($name)=/^\s*(\S.*)$/; $name =~ s/\s*$//g; $name{$logfile} = $name; } if (/^\s*archive\s+/) { s/archive//; $numdays=$_+0; } if (/^\s*count\s+/) { s/count//; ($regexp)=/^\s*(\S.*)$/; $regexp =~ s/\s*$//g; ($countthing)=/($regexp)/; push (@{$code{$logfile}},"if (/$regexp/) { \$count{\"$logfile\"}{\"\$host/\$service $countthing\"}++; next; }\n"); } if ($done==1) { last; } $_=; } } close(C); foreach $file (sort keys %code) { print ":: $file: code.."; $prog = q[ open (F,"<$file"); foreach () { $num{$file}++; ($date,$host,$service,$message)=/(.*[0-9][0-9]:[0-9][0-9])\s+(\S+)\s+([^\[]+)\]?.*:(.*)$/; next unless $message; ]; foreach (@{$code{$file}}) { $prog .= "\t$_"; } $prog .= q[ push @{$unknown{$file}},"$date $host/$service: $message"; } close(F); ]; #print "\n$prog\n"; print "processing.."; eval($prog); warn $@ if $@; print "archiving.."; $pid = &stop_process($syslogpid); &shuffle_logs($file,$numdays); &archive_log($file); &cont_process($pid); print "\n"; } foreach $file (sort keys %code) { $num{$file} = 0 unless defined($num{$file}); $xtra = $name{$file} ? " - ($name{$file})" : ""; print "=" x 70 . "\n:: $file ($num{$file} lines)$xtra ::\n"; if ($count{$file}) { print "The following counts were found:\n"; foreach (sort keys %{$count{$file}}) { print "$_: $count{$file}{$_}\n"; } print "\n"; } if ($groupcount{$file}) { print "The following groupcounts were found: (>5)\n"; foreach (sort keys %{$groupcount{$file}}) { if ($groupcount{$file}{$_} > 5) { print "$_: $groupcount{$file}{$_}\n"; } } print "\n"; } if ($unknown{$file}) { print "The following unknown messages were found:\n"; foreach (@{$unknown{$file}}) { print "$_\n"; } } } ### The following code was lifted from chklogs. # AUTHOR: D. Emilio Grimaldo T. root@panama.iaehv.nl # Gotta say, I dont think much of someone whose email address is "root". # Also this code is really crude. Can you say "first perl script"? # I am just using it becuase I am lazy.. # --Josh # # Shuffles logs, when the maximum number of archived logs (per log name) # is reached we remove the oldest so that we don't waste disk space with # too many archived logs # sub shuffle_logs { local($fullpath,$f_max) = @_; local($logcnt,@LogList); $logcnt = 0; $dname = &dirname($fullpath); $bname = &basename($fullpath); chdir($dname); open(ARCHLIST,"ls $bname.*.gz 2> /dev/null |") || warn "Could not pipe shuffle"; while () { chop($_); @LogList[$logcnt] = $_; $logcnt += 1; } close(ARCHLIST); if ($logcnt >= $f_max) { unlink(@LogList[0]); # Remove oldest archived log } } sub basename { local($fpath) = @_; $fpath =~ s/[a-zA-Z0-9_.\/-]*\///; return $fpath; } sub dirname { local($fpath) = @_; $fpath =~ s/[a-zA-Z0-9._-]*$//; return $fpath; } # # Archives the log by compressing it and adding a timestamp in # the filename. No new log is created if it already exists. # sub archive_log { local($logname) = @_; local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); local($archiveName,$zipArchive); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $ArchiveSuffix = sprintf(".%2d%02d%02d",$year,$mon+1,$mday); $archiveName = $logname . $ArchiveSuffix; $zipArchive = $archiveName . ".gz"; if ( ! -e $zipArchive) { if (! system("/opt/bin/gzip < $logname > $zipArchive && : > $logname")) { chown $UID,$GID,$zipArchive; # Set correct ownership chmod $mode, $zipArchive; # Set correct permissions print STDOUT "archived"; } else { print STDOUT "Could not create $zipArchive!\n"; } } else { print STDOUT "$zipArchive already exists!"; # give a warning } } # STOP_PROCESS(path_of_pid_file) sub stop_process { local($pid_file) = @_; local($itsPID); open(PID,"$pid_file"); read(PID,$itsPID,10); kill 'STOP', $itsPID; close(PID); return $itsPID; } # CONT_PROCESS(pid) sub cont_process { local($itsPID) = @_; kill 'CONT', $itsPID; }