tfredett has asked for the wisdom of the Perl Monks concerning the following question:

Hello, so I have been trying for the past few days to understand how to use Win32::Eventlog. I am trying to get the script I am writing to continuously monitor the system to look for specific error codes. However I am running into issues, specifically, it doesn't appear to be monitoring it at all, and it ends prematurely. I know the code may not be pretty, but if someone could take a quick look and point me in the right direction, I would very much appreciate it.
while (1) { my $Errorlog = Win32::EventLog::new(System) or die "Can't Read the + Error Log\n"; $Errorlog -> Read(EVENTLOG_FORWARDS_READ, 0); &ErrorCheck; my %event = ( EventID => $ErrorCode, EventType => EVENTLOG_ERROR_TYPE, Computer => NULL, Source => "System", Strings => $Description ); $Errorlog -> Report(\%event); close $Errorlog; } sub ErrorCheck { if ($Errorlog == '0x683') { $ErrorCode = '0x683'; $Description = "Insert Error Description Here"; }

Replies are listed 'Best First'.
Re: Help understanding Win32::Eventlog
by Anonymous Monk on Aug 02, 2011 at 14:04 UTC

    I know the code may not be pretty

    You know, copy/paste-ing from the documentation should work flawlessly :) methods are called using ->, this is important

    Report puts a report in the Eventlog, it doesn't read one

    Try http://search.cpan.org/dist/Win32-EventLog/EventLog.pm#Example_1

    #!/usr/bin/perl -- use strict; use warnings; Main( @ARGV ); exit( 0 ); sub Main { while(1){ eval { FiddleEventLog("System") ; 1 } or warn "Oooops: $@"; } } sub FiddleEventLog { my( $eventLog , $computerName ) = @_; $computerName ||= $ENV{ComputerName}; my $handle=Win32::EventLog->new($eventLog, $computerName) or die "Can't open Application EventLog\n"; my $recs; $handle->GetNumber($recs) or die "Can't get number of EventLog records\n"; my $base; $handle->GetOldest($base) or die "Can't get number of oldest EventLog record\n"; while ($x < $recs) { my $hashRef = {}; $handle->Read( EVENTLOG_FORWARDS_READ|EVENTLOG_SEEK_READ, $base+$x, $hashRef ) or die "Can't read EventLog entry #$x\n"; if ( $hashRef->{Source} eq "EventLog" ) { Win32::EventLog::GetMessageText($hashRef); print "Entry $x: $hashRef->{Message}\n"; } $x++; } }
      to clarify some things, I had used report to attempt to test to see if the code was working correctly, but it appears I did that incorrectly, and I am unsure of how to do it correctly. Also I have already done several google searchs, looked in the perldocs, and checked out cpan, and I am just not understanding what its trying to say. I understand the function calls and such, but I don't understand how it works well enough to implement them.

      Update: Sorry it took me awhile to even remotely understand your code and I have several questions regarding it.

      $handle appears to be a variable that is retrieving the eventlog records and then later on, is being read in your second while loop. am I incorrect in this observation?

      Is there a way I could go about when reading these, looking for a specific string or integer and upon finding one of these do some action foo?

      In the second while loop, you have EVENTLOG_FORWARDS_READ|EVENTLOG_SEEK_READ as part of your hash, wouldn't these need to be passed parameters in order to function correctly?

      Again thanks for your help, I really appreciate it.

        $handle appears to be a variable that is retrieving the eventlog records and then later on, is being read in your second while loop. am I incorrect in this observation?

        Kinda sorta :) almost not really :D

        Yes, $handle is a (scalar) variable, a special kind, an object (aka reference), which is an instance of the class Win32::EventLog , which is just very thin sugar around the number returned by OpenEventLog Function (Windows)

        So instead of doing

        or in perl terms
        Win32::EventLog::Read( $handle, ... ); Win32::EventLog::Close( $handle );
        you do
        $handle->Read(...); $handle->Close;

        Win32::EventLog follows the c-interface too closely, I would write a wrapper that avoids pass-by-reference

        Is there a way I could go about when reading these, looking for a specific string or integer and upon finding one of these do some action foo?

        In the same way as the example demonstrates :) for example, instead of printing Message, you could perform additional checks, perhaps using the match operator, then call some other function

        In the second while loop, you have EVENTLOG_FORWARDS_READ|EVENTLOG_SEEK_READ as part of your hash, wouldn't these need to be passed parameters in order to function correctly?

        No, they are not part of the hash, they are indeed arguments to the Read method

        Perhaps you need a syntax highlighting editor like http://padre.perlide.org/ or kephra ....

        Here is another example

        #!/usr/bin/perl -- use strict; use warnings; use Win32::EventLog(); use Data::Dump qw[ pp ]; Main( @ARGV ); exit( 0 ); sub Main { FiddleEventLog("System"); FiddleEventLog("Application"); } sub Ebola { my( $eventLog , $computerName ) = @_; my $handle = Win32::EventLog->new($eventLog, $computerName) or die "Can't open Application EventLog\n"; my $recs; $handle->GetNumber($recs) or die "Can't get number of EventLog records\n"; my $base; $handle->GetOldest($base) or die "Can't get number of oldest EventLog record\n"; return $handle, $base, $recs; } sub FiddleEventLog { my( $handle, $base, $recs ) = Ebola(@_); my $flags = Win32::EventLog::EVENTLOG_FORWARDS_READ() | Win32::EventLog::EVENTLOG_SEEK_READ(); local $Win32::EventLog::GetMessageText = 1; # autocall GetMessageT +ext my $x = 0; while( $x < $recs ) { my $hashRef; $handle->Read( $flags , $base + $x, $hashRef ) or die "Can't read EventLog entry #$x\n"; DoTheVirus( $hashRef ); $x++; } print "\nRead $x records\n"; } sub DoTheVirus { my %hash = %{shift @_ }; if ( $hash{Message} and $hash{Message} =~ /die/ ){ die "dumb but hey, I've yet to see die in my event log"; } elsif( $hash{Source} eq 'Application Error' ){ if( $hash{Strings} =~ /\Qperl.exe\E/i ){ printf "\nUh oh $hash{RecordNumber} %s\n", pp($hash{St +rings}) if $hash{Strings} =~ /perl58.dll/; } } else { WinAppExploder( \%hash ); } } sub WinAppExploder { my( $ref ) = @_; if( $hash{Source} =~ /WinApp/ and $ref->{Strings} =~ /Windows is g +ood/ ) { if( $ref->{Category} == 50 ) { die 666; } } elsif( $ref->{Data} eq 'unix' ) { die 666; } } __END__ $ perl pm.918065.pl Read 2544 records Uh oh 8 "perl.exe\x005.8.9.825\0perl58.dll\x005.8.9.825\x000008725a\0" Uh oh 12 "perl.exe\x005.8.9.825\0perl58.dll\x005.8.9.825\x000008725a\0 +" Uh oh 45 "perl.exe\x005.8.9.825\0perl58.dll\x005.8.9.825\x000008725a\0 +" Uh oh 49 "perl.exe\x005.8.9.825\0perl58.dll\x005.8.9.825\x000008725a\0 +" Uh oh 125 "perl.exe\x005.8.9.825\0perl58.dll\x005.8.9.825\x000008725a\ +0" 666 at pm.918065.pl line 67.