#!/usr/bin/perl -w # Logregate # Artem Litvinovich, 2001-08-02 # an aggregate log analyzer # aims to provide output from various log sources in a time syncronized manner # logregate utility by Artem Litvinovich use strict; use Config::General; use Getopt::Std; use Time::Local; use POSIX; my %logtable = (); my @sections = (); my ($interval) = (""); &main(); exit 1; sub main { my (%months_3ltr,%months_full) = (); @months_3ltr{ qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) } = @months_full{ qw(January February March April May June July August September October November December) } = (0..11); my %reserved = ( 'default_timestamp' => [ qw( ^($M=\w+)\b($D=\d+)\b($h=\d+):($m=\d+):($s=\d+)\b($data=.*)$ )], # timestamp works on syslog files 'default_interval' => ["1m"], 'default_maxlines' => ["-1"], 'default_nostamp' => ["log"], 'default_fromtime' => ["00,00,00,12,02,1982"], 'default_totime' => ["59,59,23,30,11,2020"] ); # get command line options my %options = (); getopt('c:',\%options); my $conFile = exists($options{c}) ? $options{c} : "./logregate.conf"; die "Unable to find config file ($conFile).\nUsage: logregate [-c config_file]\n" unless(-f $conFile); # load config file my $conf = new Config::General($conFile); my %config = $conf->getall; # get grouping interval $interval = exists($config{default_interval}) ? interval2sec($config{default_interval}) : interval2sec($reserved{default_interval}); foreach my $section (keys %config) { next if(exists $reserved{$section}); # check with path, then without, store if found, next if doubt my ($logfile) = exists($config{$section}{path}) ? (-f $config{$section}{path}."/".$section ? ($config{$section}{path}."/".$section) : next) : (-f $section ? ($section) : next); # conf must have a way to get the timestamp, use default if regex omitted my ($stampRegex,@elements) = exists($config{$section}{timestamp}) ? stamp2regex($config{$section}{timestamp}) : (exists($config{default_timestamp}) ? stamp2regex($config{default_timestamp}) : $reserved{default_timestamp}); # get maxlines read from logfile my $maxlines = exists($config{$section}{maxlines}) ? $config{$section}{maxlines} : (exists($config{default_maxlines}) ? $config{default_maxlines} : $reserved{default_maxlines}); # get nostamp action my $nostamp = exists($config{$section}{nostamp}) ? $config{$section}{nostamp} : (exists($config{default_nostamp}) ? $config{default_nostamp} : $reserved{default_nostamp}); # get from time limit my $fromTime = exists($config{$section}{fromtime}) ? $config{$section}{fromtime} : (exists($config{default_fromtime}) ? $config{default_fromtime} : $reserved{default_fromtime}); $fromTime = timelocal(split(",",$fromTime)); # get to time limit my $toTime = exists($config{$section}{totime}) ? $config{$section}{totime} : (exists($config{default_totime}) ? $config{default_totime} : $reserved{default_totime}); $toTime = timelocal(split(",",$toTime)); open LOGDATA, $logfile; my %logline = ('Y'=>'2001'); my $epochSeconds = 0; # main log-reading loop while(my $line = ) { chomp($line); $maxlines--; # if maxlines was set >0, loop until it is 0. if( $line =~ m/$stampRegex/ ) { # extract timestamp # record each timestamp element (+data) into logline hash for(my $ecount=0;$ecount=$fromTime && $epochSeconds<=$toTime); last unless($maxlines); } close LOGDATA; push @sections, $section; } &displayHTML(); } sub display { my $mark = -1; foreach my $entrytime (sort keys %logtable) { if($entrytime-$mark > $interval) { print "time: ".localtime($entrytime)."\n"; $mark = $entrytime; } foreach my $section (keys %{$logtable{$entrytime}}) { print "section: $section\n"; foreach (@{$logtable{$entrytime}{$section}}) { print "entry: $_\n"; } } } } sub displayHTML { my $mark = -1; my $colWidth = "300"; my $minColorDiv = "00"; my $maxColorDiv = "5"; my $baseColor = "9933"; my $colorStep = "51"; my $colorOpr = "+"; my $colorMod = $minColorDiv; print "\n"; print "Interval is $interval seconds.
\n"; # display deviation spectrum print "\n"; print "\n"; for ($minColorDiv..$maxColorDiv) { print "\n"; } print "
\n\n"; for ($minColorDiv..$maxColorDiv) { print "\n"; } print "
Interval separation color spectrum in seconds:
". sqr($_)*$interval. "
".sqr($maxColorDiv+$minColorDiv-$_)*$interval."

\n"; # main agregate log table print "\n"; foreach my $entrytime (sort keys %logtable) { if($entrytime-$mark > $interval) { # if interval reached, reprint heading my $intDiff = POSIX::floor(sqrt(($entrytime-$mark)/$interval)-1); if($colorMod >= $minColorDiv+$colorStep*$maxColorDiv) { $colorOpr = "-"; } elsif ($colorMod <= $colorStep*$minColorDiv) { $colorOpr = "+"; } $colorMod += ($colorOpr.$colorStep * $intDiff); if($colorMod>$minColorDiv+$colorStep*$maxColorDiv) { $colorMod = $minColorDiv+$colorStep*$maxColorDiv; } elsif($colorMod<$colorStep*$minColorDiv) { $colorMod = $colorStep*$minColorDiv; } my $color = $baseColor . ($colorMod ? dec2hex($colorMod) : "00"); print "\n"; $mark = $entrytime; print ""; foreach (sort @sections) { print "\n"; } print ""; } print ""; foreach my $section (sort @sections) { print "\n"; } print ""; } print "
time: ".localtime($entrytime)."
$_
"; foreach (exists($logtable{$entrytime}{$section}) ? @{$logtable{$entrytime}{$section}} : ()) { print localtime($entrytime)." $_
\n"; } print "
\n"; print "\n"; } sub stamp2regex { # s - sec, m - min, h - hour, D - day, W - week, M - month, Y - year # Ex: # "^($M=\w+)\b($D=\d+)\b($h=\d+):($m=\d+):($s=\d+)\b($data=.*)$" for syslog # Aug 2 16:57:59 artemz1 su(pam_unix)[18581]: session closed for user root my ($str) = @_; my @orderedElements = (); # drop encapsulating quotes $str =~ s/^"(.*)"$/$1/; # compile the time_stamp elements in order while($str =~ m/\(\$(.+?)=.+?\)/g) { push @orderedElements, $1; } # convert into a real regex $str =~ s/\(\$.+?=(.+?)\)/\($1\)/g; return ($str,@orderedElements); } sub dec2hex($) { my($dec) = @_; return sprintf("%lx ", $dec ); } sub sqr($) { my($num) = @_; return $num*$num; } sub interval2sec($) { # convert interval to seconds # s - sec, m - min, h - hour, D - day, W - week, M - month, Y - year my ($interval) = @_; $interval =~ s/^(\d+)(\w)$/$1/; for ($2) { /s/ and last; $interval *= 60; /m/ and last; $interval *= 60; /h/ and last; $interval *= 24; /D/ and last; $interval *= 7; /W/ and last; $interval *= 4; /M/ and last; $interval *= 12; /Y/ and last; $interval = $1; # wierd denomination, assuming seconds. } return $interval; }