From: Don Armstrong Date: Thu, 2 May 2013 01:07:22 +0000 (-0700) Subject: add postfix grep X-Git-Url: https://git.donarmstrong.com/?p=bin.git;a=commitdiff_plain;h=76dc2e201f8a01f088a4476897fc0a9c3d7326a2 add postfix grep --- diff --git a/postfix_grep b/postfix_grep new file mode 100755 index 0000000..da659bc --- /dev/null +++ b/postfix_grep @@ -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 . + + +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 +# \s(?\S+)# hostname +# \spostfix\/(?[^[]+) #process +# \[(?[^\]]+)\]:\s #pid +# (?[A-F0-9]+)\:\s +# (?.+) +# /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__