File Coverage

blib/lib/App/dategrep.pm
Criterion Covered Total %
statement 102 109 93.5
branch 49 56 87.5
condition 7 12 58.3
subroutine 14 14 100.0
pod 0 3 0.0
total 172 194 88.6


line stmt bran cond sub pod time code
1 8     8   384268 use strict;
  8         9  
  8         189  
2 8     8   27 use warnings;
  8         9  
  8         244  
3              
4             package App::dategrep;
5 8     8   2480 use App::dategrep::Date qw(intervall_to_epoch date_to_epoch minutes_ago);
  8         19  
  8         665  
6 8     8   3736 use App::dategrep::Iterators;
  8         22  
  8         213  
7 8     8   3537 use Config::Tiny;
  8         5815  
  8         211  
8 8     8   3609 use Pod::Usage;
  8         219211  
  8         1009  
9 8     8   5775 use Getopt::Long;
  8         63033  
  8         30  
10 8     8   1240 use Fcntl ":seek";
  8         14  
  8         877  
11 8     8   41 use File::Basename qw(basename);
  8         9  
  8         485  
12 8     8   38 use base 'Exporter';
  8         12  
  8         949  
13             our @EXPORT_OK = qw(run);
14              
15             our $VERSION = '0.56';
16              
17             our $app;
18              
19             BEGIN {
20 8     8   5660 $app = basename($0);
21             }
22              
23             sub error {
24 7     7 0 13 my ( $msg, $rc ) = @_;
25 7 50       21 $rc = defined $rc ? $rc : 1;
26 7         15 chomp($msg);
27 7         311 warn "$app: $msg\n";
28 7         71 return $rc;
29             }
30              
31             sub run {
32 35     35 0 60693 my %options;
33 35 100       125 if ( $ENV{DATEGREP_DEFAULT_FORMAT} ) {
34 17         53 $options{format} = $ENV{DATEGREP_DEFAULT_FORMAT};
35             }
36              
37 35         209 my $rc = GetOptions(
38             \%options, 'start|from=s', 'end|to=s', 'format=s',
39             'last-minutes=i', 'multiline!', 'blocksize=i', 'help|?',
40             'sort-files', 'man', 'configfile=s', 'interleave',
41             'byte-offsets', 'debug=s', 'version!', 'skip-unparsable!',
42             );
43 35 100       29480 if ( !$rc ) {
44 1         10 pod2usage( -exitstatus => "NOEXIT", -verbose => 0 );
45 1         3631 return 2;
46             }
47              
48 34 50       114 if ( $options{version} ) {
49 0         0 print "$VERSION\n";
50 0         0 return 0;
51             }
52              
53 34 50       93 if ( $options{help} ) {
54 0         0 pod2usage( -verbose => 1, -exitstatus => 'NOEXIT' );
55 0         0 return 0;
56             }
57 34 50       84 if ( $options{man} ) {
58 0         0 pod2usage( -exitstatus => "NOEXIT", -verbose => 2 );
59 0         0 return 0;
60             }
61              
62 34         118 my $config = loadconfig( $options{configfile} );
63              
64 34         164 my %named_formats = (
65             'iso8601' => "%O%Z",
66             'rsyslog' => "%b %e %H:%M:%S",
67             'apache' => "%d/%b/%Y:%T %z",
68             );
69              
70 34 100       80 if ( exists $config->{formats} ) {
71 1         3 %named_formats = ( %named_formats, %{ $config->{formats} } );
  1         4  
72             }
73              
74 34 100       81 if ( not defined $options{'format'} ) {
75 1         3 return error("--format is a required parameter");
76             }
77              
78 33 100       89 if ( exists $named_formats{ $options{'format'} } ) {
79 12         30 $options{'format'} = $named_formats{ $options{'format'} };
80             }
81              
82 33 100       71 if ( $options{'skip-unparsable'} ) {
83 1         3 $options{'multiline'} = 0;
84             }
85              
86 33         147 my ( $start, $end ) = ( 0, time() );
87              
88 33 100       87 if ( defined $options{'start'} ) {
89 23         140 ($start) = intervall_to_epoch( $options{'start'}, $options{'format'} );
90 23 100       10617 return error("Illegal start time.") if not defined $start;
91             }
92              
93 31 100       88 if ( defined $options{'end'} ) {
94 20         74 ($end) = intervall_to_epoch( $options{'end'}, $options{'format'} );
95 20 100       3677 return error("Illegal end time.") if not defined $end;
96             }
97              
98 30 100       73 if ( defined $options{'last-minutes'} ) {
99 1         6 ( $start, $end ) = minutes_ago( $options{'last-minutes'} );
100             }
101              
102 30 100       530 if ( $end < $start ) {
103 5         8 ( $start, $end ) = ( $end, $start );
104             }
105              
106 30 100 66     104 if ( defined $options{'debug'} && $options{'debug'} eq 'time' ) {
107 1         27 print "Start: $start End: $end\n";
108 1         7 return 0;
109             }
110              
111 29 100       74 if ( !@ARGV ) {
112 2         5 push @ARGV, '-';
113             }
114              
115 29         45 eval {
116              
117 29 100       74 if ( $options{'byte-offsets'} ) {
118 2 50 33     49 if ( @ARGV == 1 and -f $ARGV[0] ) {
119             my $iter = App::dategrep::Iterator::File->new(
120             filename => $ARGV[0],
121             start => $start,
122             end => $end,
123             multiline => $options{multiline},
124             format => $options{format},
125 2         48 );
126 2         25 my ( $fh, $byte_beg, $byte_end ) = $iter->byte_offsets();
127 2 100       6 if ( not defined $byte_end ) {
128 1         9 $byte_end = ( stat($fh) )[7];
129             }
130 2         122 print "$byte_beg $byte_end\n";
131 2         38 return 0;
132             }
133             }
134              
135 27         702 my $iterators = App::dategrep::Iterators->new(
136             %options,
137             filenames => \@ARGV,
138             start => $start,
139             end => $end,
140             );
141              
142 27 100       269 if ( $options{'interleave'} ) {
143 1         4 $iterators->interleave();
144 1         7 return 0;
145             }
146              
147 26 100       62 if ( $options{'sort-files'} ) {
148 1         4 $iterators->sort();
149             }
150              
151 26         94 for my $iter ($iterators->as_array) {
152 28 50       57 if ($iter) {
153 28         121 while ( my $entry = $iter->get_entry ) {
154 71         1586 print $entry;
155             }
156             }
157             }
158             };
159 29 100       626 return error($@) if $@;
160 26         408 return 0;
161             }
162              
163             sub loadconfig {
164 34     34 0 68 my $configfile = shift;
165 34 100 66     161 if ( not $configfile and $ENV{HOME} ) {
166 32         56 $configfile = "$ENV{HOME}/.dategreprc";
167             }
168 34 100 66     495 if ( not defined $configfile or not -e $configfile ) {
169 33         55 return;
170             }
171              
172 1         13 my $config = Config::Tiny->read( $configfile );
173 1 50       104 if ( not defined $config ) {
174 0         0 die "Error while parsing configfile: " . Config::Tiny->errstr() . "\n";
175             }
176 1         1 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