#! perl -w
# check_elwatch.pl: checks whether certain events happend or not
#  return values/exit codes for Nagios interaction over NRPE.
#
# Author: Hannes Schulz 2003

=head1 NAME

check_elwatch.pl - parses F<elwatch.log> for events defined in F<elwatch.cfg>.

=head1 VERSION

Version 1.0

=head1 AUTHOR

(c) 2003 Hannes Schulz <mail@hannes-schulz.de>

=head1 SYNOPSIS

./check_elwatch.pl [--help|-h] --elwID <EventID> --backtime <Minutes>

where C<elwID> is the EventID from C<elwatch.cfg>, B<not> the event ID from the
Event log!

C<Minutes> is the time to look back for... all older entries B<will be
deleted>, so the log file C<elwatch.log> will not become overaged.

=head1 DESCRIPTION

This will go through F<elwatch.log> and output the I<first> message it finds
that matches C<EventID>. Generally, F<elwatch.log> should be written by
L<elwatch.pl> running as a W2K-Service.

The log is written head first, so newest messages I<will> come first.

This B<needs> the F<elwatch.cfg> definition file!

This needs L<CfgParse.pm> to read the config file.

=head1 CONFIGURATION

=head2 BASIC CONFIG

If paths change, please change the variables at the beginning of the script
accordingly.

=head2 THE CONFIG FILE

There may be more than one definition for every EventID, so that you can define
events that for example turn an ID to green, even if something rather bad
happened before: Service shuts down: RED, Service back up: GREEN.

Every definition looks like this:

 define testevent {
  [ __found              {OK|Warning|Critical} ]
  [ __notfound           {OK|Warning|Critical} ]
  [ __number             <number> ] 
  [ __logging            {True|False}  ] 
  [ [!]Category          <regex> ]
  [ [!]CategoryString    <regex> ]
  [ [!]ComputerName      <regex> ]
  [ [!]Data              <regex> ]
  [ [!]EventCode         <regex> ]
  [ [!]EventIdentifier   <regex> ]
  [ [!]EventType         <regex> ]
  [ [!]InsertionStrings  <regex> ]
  [ [!]Logfile           <regex> ]
  [ [!]Message           <regex> ]
  [ [!]RecordNumber      <regex> ]
  [ [!]SourceName        <regex> ]
  [ [!]TimeGenerated     <regex> ]
  [ [!]TimeWritten       <regex> ]
  [ [!]Type              <regex> ]
  [ [!]User              <regex> ]
 }

One line, one entry.

Lines starting with C<#> are ignored.

Everything in [] is optional, an exclamation mark negates the condition.
C<testevent> would, in this case, be the event ID that you can look for in
elwatch.log by supplying the parameter --elwID to this script.

B<If you define more than one Events for one ID>, you B<must> choose different
values for C<__number>. Else, C<__number> defaults to 0.

=cut

BEGIN{
	push @INC, 'c:/adm/nagios'
}

use strict;
use CfgParse;
use Getopt::Long;
my $cfgfile = 'c:\adm\nagios\elwatch.cfg';
my @config;

# get options
my ($help,$eId,$backtime) = ('' x 3);
GetOptions(
	"help|h"  => \$help,                    # help
	"elwid|e=s" => \$eId,                   # elwatch-ID
	"backtime|b=i" => \$backtime);          # minutes backwards from now

# print usage if --help
printUsage() if($help or (!$eId) or (!$backtime));

# calculate earliest time for event to occur
$backtime = time() - ($backtime*60);

# read config file
readConfig();

# do the parsing
parseLogFile();

sub returnNagios{
	my $matched = shift();
	my $time    = shift();
	my $num     = shift();
	exit 0 unless($matched and $time and $num);

	my @lookfor = grep{ $_->{"__blockname"} eq $eId and 
	                    $_->{"__number"}    eq $num} @config;
	my %elwIDhash = %{$lookfor[0]};    # should be unique

	# do output and exit with correct return code.
	if($matched && $elwIDhash{__found}){
		print $elwIDhash{__found} . " at localtime ". localtime $time."\n";
		exit 0 if($elwIDhash{__found} =~ /OK/i);
		exit 1 if($elwIDhash{__found} =~ /Warning/i);
		exit 2 if($elwIDhash{__found} =~ /Critical/i);
		exit 3;                         # Unknown
	}
	elsif(!$matched && $elwIDhash{__notfound}){
		print $elwIDhash{__notfound}.": not found.";
		exit 0 if($elwIDhash{__notfound} =~ /OK/i);
		exit 1 if($elwIDhash{__notfound} =~ /Warning/i);
		exit 2 if($elwIDhash{__notfound} =~ /Critical/i);
		exit 3;                            # Unknown
	}else{
		print "Unknown"; exit 3
	}
}

# print usage
sub printUsage{
	print <<EOT
check_elwatch.pl -- Version 1.0
Copyright (c) Hannes Schulz 2003\n
Usage: $0 [--help|-h] --elwID <EventID> --backtime <Minutes>\n
EOT
	; exit();
}

# read in config file
sub readConfig{
	my $c = new CfgParse($cfgfile);
	unless(@config = @{$c->parse()}){
		warn "error while parsing cfg-file: $!";
		exit 3;   # Nagios: unknown
	}
	@config = map{$_->{__number}=0 unless($_->{__number});$_}@config;
}

# parse the logfile
sub parseLogFile {
	my ($elwID,$elwTime,$num,@lookin);
	my $match = 0;

	# open the elwatch-Logfile
	my @cfg = grep{$_->{"__blockname"} eq "elwatch"}@config;
	my $logfile = $cfg[0]->{"log"};
	unless(open(LOG, "<$logfile")){
		warn "Could not open log file '$logfile': $!\n";
		exit(3)   # Nagios: unknown!
	}

	# get infos for destination elwID:
	my @lookfor = grep{ $_->{"__blockname"} eq $eId }@config;
	if($#lookfor<0){
		warn "Could not find infos for specified ID '$eId'!\n";
		exit(3);   # Nagios: unknown!
	}

	# do the actual parsing
	while(<LOG>){
		chomp;
		($elwTime,$elwID,$num) = split /;;/;     # split line in three
		next unless($elwTime and $elwID and $num);
		last if($elwTime<$backtime);             # dont look further if age > $b.t.
		if($elwID eq $eId){
			@lookin = grep{$_->{__number} eq $num}@lookfor;
			if($#lookin<0){
				warn "Error: could not correlate log entry with config file.\n";
				exit 3 # Nagios unknown
			}
			$match = 1 if($lookin[0]->{__found});  # should be unique
			last
		}
	}
	close(LOG);
	returnNagios($match,$elwTime,$num)
}
