NAME

Mail::Exim::MainLogParser - Parse log lines from the Exim Main Log

SYNOPSIS

use Mail::Exim::MainLogParser;
use Data::Dumper;
my $exlog = new Mail::Exim::MainLogParser;

my $logline = "2017-06-08 11:17:56 1dJ08B-0003oP-5i <= do-not-reply@nowhere.com H=realmail.server.example.com (ehlo-name.example.com) [192.168.250.101] P=esmtp S=1364 id=266785270.3.2385849643852@peerhost.server.example.com";
$logLineHashStructure = $exlog->parse($logline);

print Dumper($logLineHashStructure);
$VAR1 = {
        'eximid' => '1dJ08B-0003oP-5i',
        'time' => '11:17:56',
        'date' => '2017-06-08',
        'args' => [
                    {
                      'H' => 'realmail.server.example.com (ehlo-name.example.com) [192.168.250.101]'
                    },
                    {
                      'P' => 'esmtp'
                    },
                    {
                      'S' => '1364'
                    },
                    {
                      'id' => '266785270.3.2385849643852@peerhost.server.example.com'
                    }
                  ],
        'address' => 'do-not-reply@nowhere.com',
        'flag' => '<='
      };

DESCRIPTION

This module will parse log lines from Exim version 4, according to the source http://www.exim.org/exim-html-current/doc/html/spec_html/ch-log_files.html as of 2017-06-08

REQUIREMENTS

This module is pure perl and does not depend on other modules. But does depend on a log file from Exim version 4 main log output.

IMPORTED METHODS

When the calling application invokes this module in a use clause, the following method can be imported into its space.

METHODS

new

Create a new object instances of this module. It is not necessary to create an object for this module, as the methods can be called outside of OO style programming.

EximMainLoglineParse

See parse().

parse

Parse a line from the Exim main log file and return a hash structure.

$exim_log_line_hash = $exlog->parse($exim_log_line_string);

This method returns a hash structure of the parsed log line.

print Dumper($exim_log_line_hash);
$VAR1 = {
      'eximid' => '1dJ08B-0003oP-5i',
      'time' => '11:17:56',
      'date' => '2017-06-08',
      'args' => [
                  {
                    'H' => 'realmail.server.example.com (ehlo-name.example.com) [192.168.250.101]'
                  },
                  {
                    'P' => 'esmtp'
                  },
                  {
                    'S' => '1364'
                  },
                  {
                    'id' => '266785270.3.2385849643852@peerhost.server.example.com'
                  }
                ],
      'address' => 'do-not-reply@nowhere.com',
      'flag' => '<='
    };

EximMainLoglineCompose

See compose().

compose

Compose a log line from a parsed main log line hash and return as a string.

$exim_log_line_composed = $exlog->compose($exim_log_line_hash)

This method returns a string composition of the parsed log line HASH structure. It is intended that the composed string matches the original log line that was parsed, minus trailing white space.

print "$LoglineComposed";
2017-06-08 11:17:56 1dJ08B-0003oP-5i <= do-not-reply@nowhere.com
    H=realmail.server.example.com (ehlo-name.example.com) [192.168.250.101]
    P=esmtp S=1364 id=266785270.3.2385849643852@peerhost.server.example.com

EXAMPLES

Show exim mail transactions for a particular email address

use Mail::Exim::MainLogParser;
$exilog = new Mail::Exim::MainLogParser();
my $emailaddress='me@example.com';
my $index = {};
my @mine_queued = ();
my $line_count = 0;
# open(EXIMLOG,"tail -f /var/log/exim/main.log |");  # Use `tail -f` to watch logs in real time
open(EXIMLOG,"cat /var/log/exim/main.log |");
while (my $line = <EXIMLOG>) {
    $line_count++;
    chomp($line);
    my $parsed = $exilog->parse($line) || (warn "Warn: Could not parse line $line_count.\n" && next);
    # Add each transaction to an eximid index
    if (exists $parsed->{'eximid'}) {
        push(@{$index->{$parsed->{'eximid'}}}, $parsed);
    }
    # Track the exim transactions that send or deliver via my email address
    if ((exists $parsed->{'address'}) && ($parsed->{'address'} =~ /$emailaddress/i)) {
        push(@mine_queued,$parsed->{'eximid'});
    }
    # Once a queued message is completed, print out transactions if mine, delete it
    if ((exists $parsed->{'message'}) && ($parsed->{'message'} =~ /Completed/i)) {
        my $eximid = $parsed->{'eximid'};
        if (grep /$eximid/, @mine_queued) {
            foreach my $eximtransaction (@{$index->{$eximid}}) {
                print $exilog->compose($eximtransaction),"\n";
            }
            @mine_queued = grep ! /$eximid/, @mine_queued;
        }
        delete $index->{$eximid};
    }
}
if (scalar @mine_queued >= 1) {
    # Once we reach the end of the log, there may still be messages that have not completed yet
    print "#"x10," My Uncompleted Messages ","#"x10,"\n";
    foreach my $eximid (@mine_queued) {
        foreach my $eximtransaction (@{$index->{$eximid}}) {
            print $exilog->compose($eximtransaction),"\n";
        }
    }
}
close(EXIMLOG);

Output

2020-05-25 10:25:34 1jdEyr-0003IG-QE <= somelist-users-bounces@example10.com H=lists.example10.com [10.10.12.136] P=esmtp S=2761 id=159999925705.99.3666999992664571474@mailman-web
2020-05-25 10:25:34 1jdEyr-0003IG-QE => me@example.com R=relay_user_to_gate1 T=remote_smtp H=smtp.example.com [10.100.200.27] X=TLSv1:AES128-SHA:128
2020-05-25 10:25:34 1jdEyr-0003IG-QE Completed
2020-05-25 11:19:42 1jdFpE-0003Xt-1L <= mailalias@example20.com H=mail.example20.com [10.20.12.168] P=esmtps X=TLSv1:AES256-SHA:256 S=50040 id=49fd3f1f7cab999999951cba1aab8cdc@example20.com
2020-05-25 11:19:43 1jdFpE-0003Xt-1L => me@example.com R=relay_user_to_gate1 T=remote_smtp H=smtp.example.com [10.100.200.27] X=TLSv1:AES128-SHA:128
2020-05-25 11:19:43 1jdFpE-0003Xt-1L Completed

AUTHOR

Russell Glaue, http://russ.glaue.org

SEE ALSO

Exim4 log documentation: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-log_files.html

COPYRIGHT

Copyright (c) 2017-2020 Russell E Glaue, Center for the Application of Information Technologies, Western Illinois University All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.