#!/usr/bin/perl # $Id$ # http://poe.perl.org/?POE_Cookbook/Watching_Logs use warnings; use strict; use POE qw( Wheel::FollowTail ); my %logs_to_watch; # new stuff my %filter_lookup; # new stuff my %record_hash; # new stuff # Read list of things to watch and filter to use # # my %logs_to_watch = | fileidx fullpath # { | -------- -------------------- # cron =>"/var/log/cron", | file0000 => '/var/log/cron' # mail =>"/var/log/maillog", | file0001 => '/var/log/maillog' # ppp =>"/var/log/ppp.log", | file0002 => '/var/log/ppp.log' # httpd=>"/var/log/httpd.log", | file0003 => '/var/log/httpd.log' # msg =>"/var/log/message", | file0004 => '/var/log/message' # myfilter=>"mylogfile1", | file0005 => 'mylogfile1' # }; | &read_watchlist(\%logs_to_watch, \%filter_lookup); # Start a session to watch the logs. POE::Session->create ( inline_states => { _start => \&begin_watchers, # Handle records from each log differently. # cron_record => \&cron_got_record, # old stuff # mail_record => \&mail_got_record, # old stuff # ppp_record => \&ppp_got_record, # old stuff # httpd_record => \&httpd_got_record, # old stuff # msg_record => \&msg_got_record, # old stuff %record_hash, # new stuff # Handle log resets and errors the same way for each file. log_reset => \&generic_log_reset, log_error => \&generic_log_error, alarm_reset => \&alarm_reset, } ); sub alarm_reset { my ($kernel, $heap) = @_[KERNEL, HEAP]; print "alarm reset ...\n"; if ( exists $heap->{'alarm'} ) { delete $heap->{'services'}; delete $heap->{'watchers'}; $kernel->delay_add("alarm_reset", 10); $kernel->yield('start'); } else { $kernel->delay("alarm_reset", 10); } } sub begin_watchers { my ($kernel, $heap) = @_[KERNEL, HEAP]; while ( my ( $service, $log_file ) = each %logs_to_watch ) { my $log_watcher = POE::Wheel::FollowTail->new ( Filename => $log_file, InputEvent => $service . "_record", ResetEvent => "log_reset", ErrorEvent => "log_error", ); $heap->{services}->{ $log_watcher->ID } = $service; $heap->{watchers}->{ $log_watcher->ID } = $log_watcher; } $kernel->yield('alarm_reset'); } # Handle log resets the same way for each file. Simply recognize that # the log file was reset. sub generic_log_reset { my ( $heap, $wheel_id ) = @_[ HEAP, ARG0 ]; my $service = $heap->{services}->{$wheel_id}; print "--- $service log reset at ", scalar(gmtime), " GMT\n"; } # Handle log errors the same way for each file. Recognize that an # error occurred while watching the file, and shut the watcher down. # If this were a real log watcher, it would periodically try to resume # watching the log file. sub generic_log_error { my ( $heap, $operation, $errno, $error_string, $wheel_id ) = @_[ HEAP, ARG0, ARG1, ARG2, ARG3 ]; my $service = $heap->{services}->{$wheel_id}; print "--- $service log $operation error $errno: $error_string\n"; print "--- Shutting down $service log watcher.\n"; delete $heap->{services}->{$wheel_id}; delete $heap->{watchers}->{$wheel_id}; } sub read_watchlist # new stuff { # new stuff my $paths_hash = shift; # \%logs_to_watch # new stuff my $filters_hash = shift; # \%filter_lookup # new stuff # new stuff open FH, "watchlist" or die "Cannot find watchlist"; # new stuff my $fnum = 0; # new stuff while ( ) # new stuff # while ( ) # new stuff { # new stuff chomp; # new stuff next if ! /\S/ || /^#/; # new stuff my $fileindex = sprintf "file%04d", $fnum++; # new stuff my ($fullpath, $filter) = (split ' ')[0..1]; # new stuff print "$fileindex : $fullpath : $filter\n"; # new stuff # new stuff $$paths_hash {$fileindex} = $fullpath; # new stuff $$filters_hash{$fileindex} = $filter; # new stuff } # new stuff close FH; # new stuff # Save entries to %record_hash for use in POE::Session->create foreach ( keys %$paths_hash ) # new stuff { # new stuff my $key = $_ . "_record"; # new stuff my $data = '\&' . $$filters_hash{$_} . "_got_record"; # new stuff # new stuff $record_hash{$key} = eval($data); # new stuff } # new stuff } # new stuff # Filters for each log file ( shortened to save space ) sub cron_got_record { my $log_record = $_[ARG0]; print "cron: "; print "$log_record\n"; } sub mail_got_record { my $log_record = $_[ARG0]; print "mail: "; print "$log_record\n"; } sub ppp_got_record { my $log_record = $_[ARG0]; print "ppp: "; print "$log_record\n"; } sub httpd_got_record { my $log_record = $_[ARG0]; print "http: "; print "$log_record\n"; } sub msg_got_record { my $log_record = $_[ARG0]; print "msg: "; print "$log_record\n"; } sub myfilter_got_record { my $log_record = $_[ARG0]; print "myfilter: "; print "$log_record\n"; } sub reread_got_record { my $log_record = $_[ARG0]; print "reread: "; print "$log_record\n"; &read_watchlist (\%logs_to_watch, \%filter_lookup); } # Run the watchers. The run() method will return after all the # watchers end. $poe_kernel->run(); __DATA__ # copy following into file "watchlist" # fullpath filter # ------------------------ --------- /var/log/cron cron /var/log/maillog mail /var/log/ppp.log ppp /var/log/httpd-access.log httpd /var/log/messages msg mylogfile myfilter configfile.log reread