File Coverage

blib/lib/App/dategrep.pm
Criterion Covered Total %
statement 99 106 93.4
branch 49 56 87.5
condition 7 12 58.3
subroutine 13 13 100.0
pod 0 3 0.0
total 168 190 88.4


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