[ABE.pm] maillog threading

Ricardo SIGNES rjbs-perl-abe at lists.manxome.org
Mon Aug 13 12:02:08 PDT 2007


* "Faber J. Fedor" <faber at linuxnj.com> [2007-08-13T13:09:34]
> On 13/08/07 12:18 -0400, John Cappiello wrote:
> > I was under the impression he was looking for a tool like the one I
> > wrote for Jenn that could grep the log for $foo, and return a list of
> > ids that you could pick from and review the path in the logs, but I'm
> > just speculating.
> 
> That sounds like what I want.  The program would generate a tree of $foo
> message-ids, find the corresponding queuids and the actio(s) taken on
> the email message.
> 
> Is Jenn's program available for hacking?

Attached.  ICG::CLI is basically Getopt::Long::Descriptive.  say/whisper/yell
are basically "print"


-- 
rjbs
-------------- next part --------------
#!/icg/bin/perl

use ICG::CLI;
use IPC::Open2;
use Time::TAI64 qw(:tai64n);
use Text::Table;
use strict;

my ($opts, $usage) = describe_options(
  "%c -o pobox\@pobox.com -m message_id",
  [ "to|t=s"          => "message was to"                            ],
  [ "from|f=s"        => "message was from"                          ],
  [ "to-or-from|o=s"  => "message was to / from"                     ],
  [ "message-id|m=s"  => "message-id"                                ],
  [ "date|d=s@"       => "date of message YYYYMMDD; default: today", {default => ['current']}  ],
  [ "hour|h=s@"       => "hour of message; default: any",            {default => ['*']}             ],
  [ "dump"            => "dump all QID data"                         ],
  [ "dump-all"        => "dump everything including non QID data"    ]
);

unless ( $opts->{to} 
      or $opts->{from}
      or $opts->{to_or_from}
      or $opts->{message_id}
       ) {
  &$usage();
}

if ($opts->{hour} < 10 and $opts->{hour} !~ /^0/) { $opts->{hour} = "0$opts->{hour}" }

foreach (["to", "from", "to_or_from"]) {
  $opts->{$_} =~ s/(^<|>$)//g;
}

my $pattern = '\(';
my $modified = 0;
if ($opts->{to_or_from}) {
  $pattern .=  "to=<\Q$opts->{to_or_from}\E>\\|from=<\Q$opts->{to_or_from}\E>";
  $modified = 1;
} else {
  if ($opts->{to}) {
    $pattern .= '\|' if $modified;
    $pattern .= "to=<\Q$opts->{to}\E>";
    $modified = 1;
  } 
  if ($opts->{from}) {
    $pattern .= '\|' if $modified;
    $pattern .= "from=<\Q$opts->{from}\E>";
    $modified = 1;
  }
}
if ($opts->{message_id}) {
  $pattern .= '\|' if $modified;
  $pattern .= "message-id=<\Q$opts->{message_id}\E>";
  $modified = 1;
}
$pattern .= '\)';
if ( not $modified ) { die "No valid pattern: $pattern\n" }

my $qids = [];
my @misc_results;
my $date_search;
if (scalar @{$opts->{date}} > 1) {
  $date_search = join ',', @{$opts->{date}};
  $date_search = "{$date_search}";
} else {
  $date_search = $opts->{date}[0];
}

my $hour_search;
if (scalar @{$opts->{hour}} > 1) {
  $hour_search = join ',', @{$opts->{hour}};
  $hour_search = "{$hour_search}";
} else {
  $hour_search = $opts->{hour}[0];
}

say("Searching /nfs/logs/syslog/maillogs/$date_search/$hour_search");
whisper("lgrep -i '$pattern' /nfs/logs/syslog/maillogs/$date_search/$hour_search");
my @results = `lgrep -i '$pattern' /nfs/logs/syslog/maillogs/$date_search/$hour_search`;
#whisper($_) foreach @results;
my %seen;
foreach (@results) {
  my ($qid) = /\b([A-F\d]{6,16})\b/; 
  if ($qid and not $seen{$qid}) {
    push @$qids, { qid => $qid};
    $seen{$qid}++;
  }
  if (not $qid) { push @misc_results, $_ }
}

my $num_qids = scalar(@$qids);
say("Found $num_qids QID.");

foreach my $qid (@$qids) {
  whisper("lfgrep -i '$qid->{qid}' /nfs/logs/syslog/maillogs/$date_search/$hour_search");
  my @results = `lfgrep -i '$qid->{qid}' /nfs/logs/syslog/maillogs/$date_search/$hour_search`;
  foreach my $result (@results) {
    my $timestamp = $result;
    $timestamp =~ /^(.+?)\s/ and $timestamp = $1;
    if ( not $qid->{timestamp} ) {
      if ($timestamp =~ /:/) { $timestamp =~ s/^.+?:// }
      $qid->{timestamp} = tai64nlocal($timestamp)
      and $qid->{timestamp} =~ s/\.\d+$//g;
    }
    $result =~ s/^[^\s]*\s//g;
    if ($result !~ / filter: /) {
      $qid->{raw} .= $result;
    }
    $result =~ /^(.+?):/
      and $qid->{host} ||= $1;
    $result =~ /\bto=<(.+?)>/
      and $qid->{to} ||= $1;
    $result =~ /from=<(.+?)>/
      and $qid->{from} ||= $1;
    $result =~ /message-id=<(.+?)>/
      and $qid->{message_id} ||= $1;
    $result =~ /\bstatus=(.+?)\b/
      and $qid->{status} ||= $1;
  }
}

my $number = 0;
my $tb = Text::Table->new( "", "Host", "To", "From", "Timestamp", "Status");
foreach my $qid (@$qids) {
  $tb->load( [$number,
              $qid->{host},
              $qid->{to},
              $qid->{from},
              $qid->{timestamp},
              $qid->{status}]
           );
  $number++;
} 

if ($opts->{dump} or $opts->{dump_all}) {
   foreach (@$qids) {
     print $_->{raw};
     print "\n";
   }
   if ($opts->{dump_all}) { print "$_" foreach @misc_results }
} else {
  my $ur = '';
  while ($ur !~ /^q(uit)?$/) {
    print "\n", $tb;
    my $choices = "#,m#,all,quit";
    if (scalar(@misc_results)) {
      print scalar(@misc_results), " results without a QID.\n";
      $choices = "#,m#,all,nonqid,quit";
    }
    if ($opts->{message_id}) { $choices =~ s/m#,//g }
    print "\n";
    $ur = prompt_str("View", { choices => $choices });
    $ur = lc($ur);
    print "\n";
    print "\n";
    
    if ($ur =~ /^\d+$/) {
      print $qids->[$ur]{raw};
      print "\n";
    } elsif ($ur =~ /^m(\d+)$/) {
      my $id = $1;
      my $args = '';
      foreach (@{$opts->{date}}) {
        $args .= " -d $_ ";
      }
      foreach (@{$opts->{hour}}) {
        $args .= " -h $_ ";
      }
      if ($opts->{verbose}) {
        $args .= " -v ";
      }
      whisper(qq|$0 -m '$qids->[$id]{message_id}' $args|);
      system(qq|$0 -m '$qids->[$id]{message_id}' $args|);
    } elsif ($ur eq 'all') {
      foreach (@$qids) {
        print $_->{raw};
        print "\n";
      }
    } elsif ($ur eq 'nonqid') {
      print "$_" foreach @misc_results;
    } else {
      print "Invalid Option.";
    }
  }
}


More information about the ABE-pm mailing list