2 # postfix_grep greps postfix logs and returns all lines matching pattern and queueid from matching lines
3 # and is released under the terms of the GNU GPL version 3, or any
4 # later version, at your option. See the file README and COPYING for
6 # Copyright 2013 by Don Armstrong <don@donarmstrong.com>.
17 postfix_grep - greps postfix logs and returns all lines matching pattern and queueid from matching lines
21 postfix_grep [options] [regex] [mailfile]
24 --regex, -e regular expression to match
25 --debug, -d debugging level (Default 0)
26 --help, -h display this help
27 --man, -m display manual
35 Regular expression to match. May be specified multiple times, in which
36 case a message must match all of them.
38 If given, all remaining options are considered to be mail files.
42 Debug verbosity. (Default 0)
46 Display brief usage information.
63 my %options = (debug => 0,
70 'debug|d+','help|h|?','man|m');
72 pod2usage() if $options{help};
73 pod2usage({verbose=>2}) if $options{man};
75 $DEBUG = $options{debug};
77 if (not exists $options{regex}) {
78 $options{regex} = shift @ARGV if @ARGV;
80 $options{regex} = ref($options{regex})?$options{regex}:[$options{regex}];
83 if (not $options{regex}) {
84 push @USAGE_ERRORS,"You must supply a regex using -e or the command line";
87 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
90 for my $regex (@{$options{regex}}) {
91 $regexes{$regex} = qr/\Q$regex\E/;
96 my $buffer_size=10000;
99 # use undef as a special stdin holder
103 sub open_compressed_file {
104 my ($file,$encoding) = @_;
105 $encoding //= ':encoding(UTF-8)';
107 if (not defined $file) {
109 binmode($fh,':encoding(UTF-8)');
112 my $mode = "<$encoding";
114 if ($file =~ /\.gz$/) {
115 $mode = "-|$encoding";
116 push @opts,'gzip','-dc';
118 if ($file =~ /\.xz$/) {
119 $mode = "-|$encoding";
120 push @opts,'xz','-dc';
122 if ($file =~ /\.bz2$/) {
123 $mode = "-|$encoding";
124 push @opts,'bzip2','-dc';
126 open($fh,$mode,@opts,$file);
131 for my $file (@ARGV) {
132 my $fh = open_compressed_file($file);
137 for my $regex (keys %regexes) {
138 if ($line !~ $regexes{$regex}) {
143 my $queue_id = parse_queue_id($line);
144 $postfix_ids{$queue_id} = 1 if defined $queue_id;
146 output_and_update_buffer(\%regexes,\%postfix_ids,\@line_buffer,$buffer_size,$line);
148 while (@line_buffer) {
149 output_if_match(\%regexes,\%postfix_ids,\@line_buffer);
152 print Dumper(\%postfix_ids);
159 # /^(?<date>.+?) # date
160 # \s(?<hostname>\S+)# hostname
161 # \spostfix\/(?<process_name>[^[]+) #process
162 # \[(?<pid>[^\]]+)\]:\s #pid
163 # (?<queue_id>[A-F0-9]+)\:\s
166 # return $+{queue_id}
171 \spostfix\/([^[]+) #process
173 ([A-F0-9]+)\:\s # queue_id
179 # Apr 28 07:18:43 golf postfix/cleanup[27095]: 94E4F27038:
182 sub output_and_update_buffer{
183 my ($regexes,$postfix_ids,$lb,$lb_max_size,$line) = @_;
184 if (@{$lb} > $lb_max_size) {
185 output_if_match($regexes,$postfix_ids,$lb);
190 sub output_if_match {
191 my ($regexes,$postfix_ids,$lb) = @_;
193 my $line = shift @{$lb};
194 return unless defined $line;
195 my $queue_id = parse_queue_id($line);
196 if (defined $queue_id and $postfix_ids->{$queue_id}) {
198 for my $regex (keys %{$regexes}) {
199 if ($line !~ $regexes->{$regex}) {