]> git.donarmstrong.com Git - bin.git/commitdiff
add postfix grep
authorDon Armstrong <don@donarmstrong.com>
Thu, 2 May 2013 01:07:22 +0000 (18:07 -0700)
committerDon Armstrong <don@donarmstrong.com>
Thu, 2 May 2013 01:07:22 +0000 (18:07 -0700)
postfix_grep [new file with mode: 0755]

diff --git a/postfix_grep b/postfix_grep
new file mode 100755 (executable)
index 0000000..da659bc
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+# postfix_grep greps postfix logs and returns all lines matching pattern and queueid from matching lines
+# and is released under the terms of the GNU GPL version 3, or any
+# later version, at your option. See the file README and COPYING for
+# more information.
+# Copyright 2013 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long;
+use Pod::Usage;
+
+=head1 NAME
+
+postfix_grep - greps postfix logs and returns all lines matching pattern and queueid from matching lines
+
+=head1 SYNOPSIS
+
+postfix_grep [options] [regex] [mailfile]
+
+ Options:
+  --regex, -e regular expression to match
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--regex, -e>
+
+Regular expression to match. May be specified multiple times, in which
+case a message must match all of them.
+
+If given, all remaining options are considered to be mail files.
+
+=item B<--debug, -d>
+
+Debug verbosity. (Default 0)
+
+=item B<--help, -h>
+
+Display brief usage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+=head1 EXAMPLES
+
+postfix_grep
+
+=cut
+
+
+use vars qw($DEBUG);
+
+my %options = (debug           => 0,
+              help            => 0,
+              man             => 0,
+              );
+
+GetOptions(\%options,
+           'regex|e=s@',
+          'debug|d+','help|h|?','man|m');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+use IO::Uncompress::Gunzip;
+
+$DEBUG = $options{debug};
+
+if (not exists $options{regex}) {
+    $options{regex} = shift @ARGV if @ARGV;
+}
+$options{regex} = ref($options{regex})?$options{regex}:[$options{regex}];
+
+my @USAGE_ERRORS;
+if (not $options{regex}) {
+     push @USAGE_ERRORS,"You must supply a regex using -e or the command line";
+}
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+my %regexes;
+for my $regex (@{$options{regex}}) {
+    $regexes{$regex} = qr/\Q$regex\E/;
+}
+
+
+my @line_buffer;
+my $buffer_size=10000;
+
+if (not @ARGV) {
+    # use undef as a special stdin holder
+    push @ARGV,undef;
+}
+
+my %postfix_ids;
+for my $file (@ARGV) {
+    my $fh = IO::Uncompress::Gunzip->new(defined $file ? $file:\*STDIN,
+                                         MultiStream => 1,
+                                         Transparent => 1,)
+        or die "IO::Uncompress::Gunzip failed: $IO::Uncompress::Gunzip::GunzipError";
+    while (<$fh>) {
+        chomp;
+        my $line = $_;
+        my $keep = 1;
+        for my $regex (keys %regexes) {
+            if ($line !~ $regexes{$regex}) {
+                $keep = 0;
+            }
+        }
+        if ($keep) {
+            my $queue_id = parse_queue_id($line);
+            $postfix_ids{$queue_id} = 1 if defined $queue_id;
+        }
+        output_and_update_buffer(\%regexes,\%postfix_ids,\@line_buffer,$buffer_size,$line);
+    }
+    while (@line_buffer) {
+        output_if_match(\%regexes,\%postfix_ids,\@line_buffer);
+    }
+    use Data::Dumper;
+    print Dumper(\%postfix_ids);
+    %postfix_ids = ();
+}
+
+sub parse_queue_id {
+    my ($line) = @_;
+#     if ($line =~
+#         /^(?<date>.+?) # date
+#          \s(?<hostname>\S+)# hostname
+#          \spostfix\/(?<process_name>[^[]+) #process
+#          \[(?<pid>[^\]]+)\]:\s #pid
+#          (?<queue_id>[A-F0-9]+)\:\s
+#          (?<rest>.+)
+#         /x) {
+#         return $+{queue_id}
+#     }
+    if ($line =~
+        /^(.+?) # date
+         \s(\S+)# hostname
+         \spostfix\/([^[]+) #process
+         \[([^\]]+)\]:\s #pid
+         ([A-F0-9]+)\:\s # queue_id
+         (.+) # rest
+        /x) {
+        return $5;
+    }
+    return undef;
+    # Apr 28 07:18:43 golf postfix/cleanup[27095]: 94E4F27038:
+}
+
+sub output_and_update_buffer{
+    my ($regexes,$postfix_ids,$lb,$lb_max_size,$line) = @_;
+    if (@{$lb} > $lb_max_size) {
+        output_if_match($regexes,$postfix_ids,$lb);
+    }
+    push @{$lb},$line;
+}
+
+sub output_if_match {
+    my ($regexes,$postfix_ids,$lb) = @_;
+
+    my $line = shift @{$lb};
+    return unless defined $line;
+    my $queue_id = parse_queue_id($line);
+    if (defined $queue_id and $postfix_ids->{$queue_id}) {
+    } else {
+        for my $regex (keys %{$regexes}) {
+            if ($line !~ $regexes->{$regex}) {
+                return;
+            }
+        }
+    }
+    print $line."\n";
+}
+
+__END__