File Coverage

blib/lib/App/dategrep.pm
Criterion Covered Total %
statement 98 105 93.3
branch 49 56 87.5
condition 11 18 61.1
subroutine 13 13 100.0
pod 0 3 0.0
total 171 195 87.6


line stmt bran cond sub pod time code
1 9     9   445998 use strict;
  9         15  
  9         252  
2 9     9   37 use warnings;
  9         12  
  9         308  
3              
4             package App::dategrep;
5 9     9   3168 use App::dategrep::Date qw(intervall_to_epoch date_to_epoch minutes_ago);
  9         22  
  9         768  
6 9     9   4225 use App::dategrep::Iterators;
  9         31  
  9         259  
7 9     9   4432 use Config::Tiny;
  9         6780  
  9         228  
8 9     9   4239 use Pod::Usage;
  9         228850  
  9         1026  
9 9     9   6367 use Getopt::Long;
  9         67287  
  9         34  
10 9     9   1109 use File::Basename qw(basename);
  9         10  
  9         560  
11 9     9   45 use base 'Exporter';
  9         15  
  9         1083  
12             our @EXPORT_OK = qw(run);
13              
14             our $VERSION = '0.58';
15              
16             our $app;
17              
18             BEGIN {
19 9     9   6532 $app = basename($0);
20             }
21              
22             sub error {
23 7     7 0 16 my ( $msg, $rc ) = @_;
24 7 50       20 $rc = defined $rc ? $rc : 1;
25 7         18 chomp($msg);
26 7         275 warn "$app: $msg\n";
27 7         64 return $rc;
28             }
29              
30             sub run {
31 37     37 0 63356 my %options;
32 37 100       133 if ( $ENV{DATEGREP_DEFAULT_FORMAT} ) {
33 19         56 $options{format} = $ENV{DATEGREP_DEFAULT_FORMAT};
34             }
35              
36 37         203 my $rc = GetOptions(
37             \%options, 'start|from=s',
38             'end|to=s', 'format=s',
39             'last-minutes=i', 'multiline!',
40             'blocksize=i', 'help|?',
41             'sort-files', 'man',
42             'configfile=s', 'interleave',
43             'byte-offsets', 'debug=s',
44             'version!', 'skip-unparsable!',
45             );
46 37 100       29661 if ( !$rc ) {
47 1         6 pod2usage( -exitstatus => "NOEXIT", -verbose => 0 );
48 1         4099 return 2;
49             }
50              
51 36 50       125 if ( $options{version} ) {
52 0         0 print "$VERSION\n";
53 0         0 return 0;
54             }
55              
56 36 50       94 if ( $options{help} ) {
57 0         0 pod2usage( -verbose => 1, -exitstatus => 'NOEXIT' );
58 0         0 return 0;
59             }
60 36 50       88 if ( $options{man} ) {
61 0         0 pod2usage( -exitstatus => "NOEXIT", -verbose => 2 );
62 0         0 return 0;
63             }
64              
65 36         133 my $config = loadconfig( $options{configfile} );
66              
67 36         179 my %named_formats = (
68             'iso8601' => "%O%Z",
69             'rsyslog' => "%b %e %H:%M:%S",
70             'apache' => "%d/%b/%Y:%T %z",
71             );
72              
73 36 100       100 if ( exists $config->{formats} ) {
74 1         3 %named_formats = ( %named_formats, %{ $config->{formats} } );
  1         5  
75             }
76              
77 36 100       88 if ( not defined $options{'format'} ) {
78 1         3 return error("--format is a required parameter");
79             }
80              
81 35 100       92 if ( exists $named_formats{ $options{'format'} } ) {
82 12         28 $options{'format'} = $named_formats{ $options{'format'} };
83             }
84              
85 35 100       107 if ( $options{'skip-unparsable'} ) {
86 1         2 $options{'multiline'} = 0;
87             }
88              
89 35         97 my ( $start, $end ) = ( 0, time() );
90              
91 35 100       167 if ( defined $options{'start'} ) {
92 25         250 ($start) = intervall_to_epoch( $options{'start'}, $options{'format'} );
93 25 100       12394 return error("Illegal start time.") if not defined $start;
94             }
95              
96 33 100       122 if ( defined $options{'end'} ) {
97 22         76 ($end) = intervall_to_epoch( $options{'end'}, $options{'format'} );
98 22 100       4443 return error("Illegal end time.") if not defined $end;
99             }
100              
101 32 100       88 if ( defined $options{'last-minutes'} ) {
102 1         7 ( $start, $end ) = minutes_ago( $options{'last-minutes'} );
103             }
104              
105 32 100       625 if ( $end < $start ) {
106 5         8 ( $start, $end ) = ( $end, $start );
107             }
108              
109 32 100 66     106 if ( defined $options{'debug'} && $options{'debug'} eq 'time' ) {
110 1         29 print "Start: $start End: $end\n";
111 1         7 return 0;
112             }
113              
114 31 100       75 if ( !@ARGV ) {
115 2         4 push @ARGV, '-';
116             }
117              
118 31         45 eval {
119              
120 31 100       85 if ( $options{'byte-offsets'} ) {
121 2 50 33     45 if ( @ARGV == 1 and -f $ARGV[0] ) {
122 2         43 my $iter = App::dategrep::Iterator::File->new(
123             %options,
124             filename => $ARGV[0],
125             start => $start,
126             end => $end,
127             );
128 2         13 my ( $byte_beg, $byte_end ) = $iter->byte_offsets();
129 2 100       6 if ( not defined $byte_end ) {
130 1         15 $byte_end = ( stat( $iter->fh ) )[7];
131             }
132 2         95 print "$byte_beg $byte_end\n";
133 2         32 return 0;
134             }
135             }
136              
137 29         745 my $iterators = App::dategrep::Iterators->new(
138             %options,
139             filenames => \@ARGV,
140             start => $start,
141             end => $end,
142             );
143              
144 27 100 66     425 if ( $options{'interleave'} && @ARGV > 1 ) {
145 1         4 $iterators->interleave();
146 1         6 return 0;
147             }
148              
149 26 100 66     91 if ( $options{'sort-files'} && @ARGV > 1 ) {
150 1         5 $iterators->sort;
151             }
152              
153 26         91 for my $iter ( $iterators->as_array ) {
154 28 50       58 if ($iter) {
155 28         110 $iter->print;
156             }
157             }
158             };
159 31 100       433 return error($@) if $@;
160 28         460 return 0;
161             }
162              
163             sub loadconfig {
164 36     36 0 75 my $configfile = shift;
165 36 100 66     172 if ( not $configfile and $ENV{HOME} ) {
166 34         67 $configfile = "$ENV{HOME}/.dategreprc";
167             }
168 36 100 66     554 if ( not defined $configfile or not -e $configfile ) {
169 35         95 return;
170             }
171              
172 1         11 my $config = Config::Tiny->read($configfile);
173 1 50       115 if ( not defined $config ) {
174 0         0 die "Error while parsing configfile: " . Config::Tiny->errstr() . "\n";
175             }
176 1         3 return $config;
177             }
178              
179             1;
180              
181             =pod
182              
183             =for stopwords dategrep DATESPEC datespec syslog apache blocksize zcat bzcat rsyslog timestamped logrotate ARGV Domgoergen merchantability configfile !syslog
184              
185             =head1 NAME
186              
187             App::dategrep - grep for dates
188              
189             =head1 DESCRIPTION
190              
191             Please read the usage and document of L.
192              
193             =head1 SEE ALSO
194              
195             L
196              
197             =head1 COPYRIGHT AND LICENSE
198              
199             Copyright 2014 Mario Domgoergen C<< >>
200              
201             This program is free software: you can redistribute it and/or modify
202             it under the terms of the GNU General Public License as published by
203             the Free Software Foundation, either version 3 of the License, or
204             (at your option) any later version.
205              
206             This program is distributed in the hope that it will be useful,
207             but WITHOUT ANY WARRANTY; without even the implied warranty of
208             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
209             GNU General Public License for more details.
210              
211             You should have received a copy of the GNU General Public License
212             along with this program. If not, see .
213              
214             =cut