Mail::Exim::MainLogParser
============================

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


Build and install this module:

perl Makefile.PL
make
make test
make install



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.ht
    ml 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.

    *   Exim 4

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

    *   "EximMainLoglineParse"

    *   "EximMainLoglineCompose"

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.

    *   *returns*

        An object instance of this module.

        my $eximlog = new Mail::Exim::MainLogParser();

  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);

    *   exim_log_line_string

        This is a single line from the Exim main log output. The below
        example log line is split over several lines in order to fit it on
        the page.

            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

    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->compoe($exim_log_line_hash)

    *   exim_log_line_hash

        This is a single parsed line from the Exim main log output
        represented as a HASH.

            $exim_parsed_main_log_line = {
                  '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' => '<='
                };

    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);

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.ht
    ml

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.