In the past I've often written small special-purpose scripts to search
for specific data in qpsmtpd logs. It was time to factor out the common
code and create a more generalized tool for these tasks. So here it is.

        hp

-- 
   _  | Peter J. Holzer    | Schlagfertigkeit ist das, was einem
|_|_) | Sysadmin WSR       | auf dem Nachhauseweg einfällt.
| |   | [EMAIL PROTECTED]         |    -- Lars 'Cebewee' Noschinski in dasr.
__/   | http://www.hjp.at/ |
#!/usr/bin/perl

=head1 NAME 

qgrep - grep through qpsmtpd logs

=head1 SYNOPSIS

qgrep -g code -m code ... files ...

=head1 DESCRIPTION

qpsmtpd writes very detailed log files. Each connection creates many
lines of log output. This script simplifies searching through qpsmtpd
logs by treating all the lines for a single connection (identified by
the second field of each line) as a single string which is then filtered
through perl grep (option -g) and map (option -m) operations.

=head2 EXAMPLES

    qgrep logfile

Dump all log entries to stdout ordered by connection.
All lines for a connection will be dumped before the next connection
starts. Connections will be in the same order as their first lines in
the logfile. This is already quite a bit more readable if you have many
parallel connections.

    qgrep -g '/Queued/' logfile

Dump only lines from connections where at least one mail was queued.

    qgrep -g '/Queued/' \         
    -m '"."'  logfile | wc -c

As above, but replace all lines of of a connection with a single dot and
count the dots: This gives you the number of connections which deliverd
mail.

    qgrep -g '/Queued/' -g '/RCPT TO: /i' \
    -m 'join "\n", grep /  (dispatching|\d{3}) /, split /\n/, $_' \
    -m '"$_\n\n"' \
    logfile

Select all connections which match both /Queued/ and /RCPT TO: /i, then
select only the SMTP dialogue from them (actually, all lines which
contain either the word "dispatching" or a three-digit number) and add
an empty line to each connection.

=head1 TODO

Identify complex but generally useful patterns (like the one to extract
the SMTP dialogue in the example above) and turn them into options.

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2006 Peter J. Holzer <[EMAIL PROTECTED]>.

This plugin is licensed under the same terms as the qpsmtpd package
itself.
Please see the LICENSE file included with qpsmtpd for details.

=cut 

use warnings;
use strict;
use Getopt::Long;

my @ops;

sub make_op {
    my $sub = eval "sub { $_[1] }";
    die "cannot eval sub { $_[1] }: [EMAIL PROTECTED]" unless $sub;
    push @ops, [ $_[0], $sub ]
}
GetOptions("g=s" => \&make_op,
           "m=s" => \&make_op,
          );

for my $f (@ARGV) {
    open (my $fh, "<", $f) or die "cannot open $f: $!";
    my @conns;
    my %conns;
    while (<$fh>) {
        if (/^\S+ ([0-9a-f.]+) /) {
            my $cid = $1;
            if ($conns{$cid}) {
                ${ $conns{$cid} } .= $_;
            } else {
                push @conns, $_;
                $conns{$cid} = \$conns[-1];
            }
        }
    }
    close($fh);
    %conns = ();
    for my $op (@ops) {
        if ($op->[0] eq 'g') {
            @conns = grep { $op->[1]($_) } @conns;
        } elsif ($op->[0] eq 'm') {
            @conns = map { $op->[1]($_) } @conns;
        } else {
            die "op $op->[0] not implemented\n";
        }
    }
    print @conns; 
}

Attachment: signature.asc
Description: Digital signature

Reply via email to