# # This software is Copyright 2005 by Elsevier Inc. You may use it # under the terms of the license at http://perl.plover.com/hop/LICENSE.txt . # ### ### logfile-process ### ## Chapter 6 section 5.3.1 sub _devino { my $f = shift; my ($dev, $ino) = stat($f); return unless defined $dev; "$dev;$ino"; } sub _next_record { while (1) { my ($fh, $filename, $devino, $wait) = @_; $wait = 1 unless defined $wait; my $rec = <$fh>; return $rec if defined $rec; if (_devino($filename) eq $devino) { # File has not moved sleep $wait; } else { # $filename refers to a different file open $_[0], "<", $filename or return; $_[2] = _devino($_[0]); } } } sub follow_file { my $filename = shift; my ($devino, $fh); tail(iterate_function(sub { _next_record($fh, $filename, $devino) })); } my $raw_mail_log = follow_file('/service/qmail/log/main/current'); sub tai64n_to_unix_time { my $rec = shift; return [undef, $rec] unless s/^\@([a-f0-9]{24})\s+//; [hex(substr($1, 8, 8)) + 10, $rec]; } my $mail_log = &transform(\&tai64n_to_unix_time, $raw_mail_log); ## Chapter 6 section 5.3.1 sub digest_maillog { my ($s, $msg, $del) = @_; for ($msg, $del) { $_ = {} unless $_ } while ($s) { my ($date, $rec) = @{drop($s)}; next unless defined $date; if ($rec =~ /^new msg (\d+)/) { $msg->{$1} = {start => $date, id => $1, success => 0, failure => 0, deferral => 0}; } elsif ($rec =~ /^info msg (\d+): bytes (\d+) from (<[^\>]*>)/) { next unless exists $msg->{$1}; $msg->{$1}{bytes} = $2; $msg->{$1}{from} = $3; } elsif ($rec =~ /^starting delivery (\d+): msg (\d+)/) { next unless exists $msg->{$2}; $del->{$1} = $2; push @{$msg->{$2}{deliveries}}, $1; } elsif ($rec =~ /^delivery (\d+): (success|failure|deferral)/) { next unless exists $del->{$1} && exists $msg->{$del->{$1}}; $msg->{$del->{$1}}{$2}++; } elsif ($rec =~ /^end msg (\d+)/) { next unless exists $msg->{$1}; my $m = delete $msg->{$1}; $m->{total_deliveries} = @{$m->{deliveries}}; for (qw(success failure deferral)) { $m->{$_} += 0 } for (@{$m->{deliveries}}) { delete $del->{$_} }; $m->{end} = $date; return node($m, promise { digest_maillog($s, $msg, $del) }); } } return; } use POSIX 'strftime'; sub format_digest { my $h = shift; join " ", $h->{id}, strftime("%d/%b/%Y:%T", localtime($h->{start})), strftime("%d/%b/%Y:%T", localtime($h->{end})), $h->{from}, $h->{total_deliveries}, $h->{success}, $h->{failure}, $h->{deferral}, ; } show(&transform(\&format_digest, digest_maillog($mail_log)));