From 7bdc4fdbf61c87064e58bf0417bf5e540c43d27c Mon Sep 17 00:00:00 2001 From: Stephen L Johnson Date: Wed, 19 May 1999 16:07:39 +0000 Subject: [PATCH] Initial import --- src/lib/Spong/Client/logmon.pm | 200 +++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100755 src/lib/Spong/Client/logmon.pm diff --git a/src/lib/Spong/Client/logmon.pm b/src/lib/Spong/Client/logmon.pm new file mode 100755 index 0000000..e5ed118 --- /dev/null +++ b/src/lib/Spong/Client/logmon.pm @@ -0,0 +1,200 @@ +# Package monitors a log file in syslog format for one or more +# regular expressions that are classed as warnings or errors +# The package monitors the last 20 minutes or the the last 8KB up +# start up. +# +# logfile - the name of the log file that is being monitored +# checks - list of regexp's to check for along with alert level +# +# procedures +# +add_check - add a expression to check for +# +logfile - Returns the name of a log file being checked +# +# 03/22/99 - Stephen L Johnson +# Package initially created. +# 05/19/99 - Stephen L Johnson +# Fixed a couple of bugs in the &new_file() which cause +# routine to not open the new file. + + +package Spong::Client::logmon; + +use Carp; +use IO::File; +use POSIX qw(mktime); + +# Constructor + +sub new { + my ( $class, $file ) = @_; + my $self = {}; + my ( $pos, $time, $daytime ); + + $self->{'checks'} = (); + $self->{'logfile'} = $file; + + my ( $inode, $size, $mtime ) = (stat($file))[1,7,9]; + + $self->{'inode'} = $inode; + $self->{'size'} = $size; + $self->{'mtime'} = $mtime; + + my ( $scantime ) = 2400; + my ( $scansize ) = $size < 8000 ? $size : 8000; + + # Create a file handle and open the file + $fh = IO::File->new(); + $self->{'fh'} = $fh; + $self->{'open'} = $fh->open("<$file"); + + # If the file was opened + if ($self->{'open'}) { + # Seek to the last scansize bytes of the file + $fh->seek(-$scansize,2); + # If not a beginning of file, read to start of next line + if ( $fh->tell() ) { <$fh>; } + + # Position file cursor until it is within the $scantime time frame + while (1) { + $pos = $fh->tell(); + ($_ = <$fh>) || last; + last unless /^([A-Z][a-z]{2})\s+(\d+)\s+([\d:]+)/; + $ltime = logdate_to_time($1,$2,$3); + last if ($ltime >= (time-$scantime)); + } + $self->{'pos'} = $pos; + } + + $self->{'stati'} = {}; + + bless $self; + return $self; +} + + +# Get methods, events() returns a list rather then just the list reference + +sub logfile { + return $_[0]->{'logfile'} } +sub checks { + return @{$_[0]->{'checks'}} } +sub stati { + return $_[0]->{'stati'} } + +# add_check() is used to add checks to the check list. + +sub add_check { + my( $self, $chk, $status, $duration, $text, $id ) = @_; + + if ( ref($chk) eq "SCALAR" ) { + + my $pattern = $chk; + + $status =~ tr/A-Z/a-z/; + if ($status ne 'green' && $status ne 'yellow' && $status ne 'red') { + croak "status must be green, yellow or red"; + } + + push @{$self->{'checks'}}, + { pattern=>"$pattern", status=>"$status", + duration=>"$duration", text=>"$text", id=>"$id" }; + } elsif ( ref($chk) eq "HASH" ) { + if ( ! ( defined $chk->{'pattern'} && defined $chk->{'status'} && + defined $chk->{'duration'} && defined $chk->{'text'} ) ) { + croak "invalid hash. It must have pattern, status, duration and text entries"; + } + + push @{$self->{'checks'}}, $chk; + + } else { + croak "invalid parameters"; + } + +} + +# check() - This procedure does the line by line checks of the logfile + +sub check { + my( $self ) = @_; + + $fh = $self->{'fh'}; + + if ($self->{'open'}) { + my ($rep,$text); + + $fh->seek($self->{'pos'},0); + while (<$fh>) { + foreach $rep (@{$self->{'checks'}}) { + $pattern = $rep->{'pattern'}; + if (/$pattern/i) { + $text = eval '"' . $rep->{'text'} . '"'; + $id = $text if ! $rep->{'id'}; + $self->{'stati'}->{$id} = { item=>'logs', + status=>$rep->{'status'}, + endtime=>time+($rep->{'duration'}*60), + text=>"$text" }; + } + } + } + $self->{'pos'} = $fh->tell(); + } + + + my $key; + my $rep; + my $stati = $self->{'stati'}; + + # Scan all report for duration and remove the old ones + foreach $key (keys %$stati) { + $rep = $stati->{$key}; + $endtime = $rep->{'endtime'}; + if ($endtime <= time) { + delete $$self{'stati'}->{$key}; + } + } + + # If there is a new log file, continue the continue th check + if ( $self->new_file() ) { $self->check() } + +} + + +# Miscellaneous internal routines + +sub logdate_to_time { + my ($lmon,$lday,$ltime) = @_; + my (@MON) = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep", + "Oct","Nov","Dec"); + my ($mon,); + foreach ( 0..11 ) { if ($MON[$_] eq $lmon) {$mon = $_; last;} } + + my($yr) = (localtime())[5]; + + my($hr,$min,$sec) = (split(/:/,$ltime)); + + return (mktime($sec,$min,$hr,$lday,$mon,$yr)) +} + +# Check to see if the log file has been rotated + +sub new_file { + my ( $self ) = @_; + + # Stat the filie + my ( $inode, $size, $mtime ) = (stat($self->{'logfile'}))[1,7,9]; + + if ( $inode != $self->{'inode'} || ( ! $self->{'open'}) ) { + $self->{'fh'}->close(); + $self->{'inode'} = $inode; + $self->{'size'} = $size; + $self->{'mtime'} = $mtime; + $self->{'pos'} = 0; + $self->{'open'} = $self->{'fh'}->open("<" . $self->{'logfile'} ); + return $self->{'open'}; + } + return 0; +} + + +# Return a return result because I'm a Perl module +1; -- 2.30.2