|
#!/usr/bin/env perl |
|
|
|
=pod |
|
|
|
=head1 SYNOPSIS |
|
|
|
print_last_start_entry --help |
|
print_last_start_entry [OPTIONS] [FILES] |
|
|
|
=head1 DESCRIPTION |
|
|
|
This is a C<grep>-like script to find and display last starting entry per |
|
every log file. |
|
|
|
By default, it passes through log files and looks for the strings |
|
containing C<Starting> or C<Started> and prints the last one that has |
|
happened since yesterday. |
|
|
|
It's assumed that each log entry starts with a date of one of the |
|
following formats: C<MM-DD-YYYY> or C<MM/DD/YYYY>. |
|
|
|
=head1 OPTIONS |
|
|
|
=over |
|
|
|
=item B<--help> |
|
|
|
Print this help and exit. |
|
|
|
=item B<-d> C<DAYS>, B<--days-ago>=C<DAYS> |
|
|
|
Print the latest starting entry for C<DAYS> days ago and later. |
|
|
|
=item B<-D> C<DATE>, B<--since-date>=C<DATE> |
|
|
|
Print the latest starting entries since C<DATE>. The C<DATE> can be one |
|
of C<YYYYMMDD>, C<YYYY-MM-DD> or C<YYYY/MM/DD>. |
|
|
|
=item B<-e> C<REGEXP>, B<--expr>=C<REGEXP> |
|
|
|
Pattern to match the starting entry. The default value is C<Starting> or |
|
C<Started>. |
|
|
|
=item B<-i>, B<--ignore-case> |
|
|
|
Case insensitive search. |
|
|
|
=item B<-w>, B<--word-regexp> |
|
|
|
Match whole words only. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
# ========================================================================= |
|
|
|
use strict; |
|
use warnings; |
|
|
|
no warnings "utf8"; |
|
use open qw( :std :utf8 ); |
|
|
|
use Pod::Usage; |
|
use Getopt::Long qw( :config no_ignore_case bundling auto_version ); |
|
|
|
my $ONE_DAY = 24 * 60 * 60; |
|
|
|
my $days_ago = 1; |
|
my $check_date; |
|
|
|
my $pattern = "Start(ing|ed)"; |
|
my $ignore_case; |
|
my $word_regexp; |
|
my $start_pattern; |
|
|
|
# ========================================================================= |
|
|
|
pod2usage unless @ARGV and GetOptions( |
|
"help" => sub { pod2usage({ -verbose => 2, -noperldoc => 1 }); }, |
|
|
|
"d|days-ago=i" => \$days_ago, |
|
"D|since-date=s" => sub { |
|
$_[1] =~ m#^ (\d{4}) ([-/]?) (\d\d) \2 (\d\d) $#x |
|
or die "Unable to recognize date: $_[1]\n"; |
|
|
|
$check_date = "$1$3$4"; |
|
}, |
|
|
|
"e|regexp=s" => \$pattern, |
|
"i|ignore-case" => \$ignore_case, |
|
"w|word-regexp" => \$word_regexp, |
|
); |
|
|
|
# ========================================================================= |
|
|
|
$check_date or $check_date = do { |
|
use integer; |
|
$days_ago > 0 or die "Positive integer required: $days_ago\n"; |
|
my $t = (time / $ONE_DAY - $days_ago) * $ONE_DAY; |
|
my @t = localtime($t); |
|
sprintf "%04d%02d%02d", $t[5] + 1900, $t[4] + 1, $t[3]; |
|
}; |
|
|
|
$start_pattern = do { |
|
my $re = $pattern; |
|
$re = "\\b$re\\b" if $word_regexp; |
|
eval { $ignore_case ? qr/$re/i : qr/$re/ } |
|
or die "Bad regexp: $pattern:\n"; |
|
}; |
|
|
|
# ========================================================================= |
|
|
|
sub print_last_start_entry { |
|
my $filename = $_[0]; |
|
|
|
open my $FILE, $filename or do { |
|
warn "Unable to read the file: $filename: $!\n"; |
|
return; |
|
}; |
|
|
|
my $last_start_entry; |
|
while ( <$FILE> ) { |
|
next unless m#$start_pattern#; |
|
$last_start_entry = $_; |
|
} |
|
|
|
close $FILE; |
|
|
|
return unless $last_start_entry; |
|
|
|
$last_start_entry =~ m#^(\d+)[/-](\d+)[/-](\d+)#; |
|
my $entry_date = "$3$1$2"; |
|
|
|
return unless $entry_date ge $check_date; |
|
|
|
print "$filename $last_start_entry"; |
|
} |
|
|
|
# ========================================================================= |
|
|
|
print_last_start_entry($_) for @ARGV; |
|
|
|
# ========================================================================= |
|
|
|
# EOF |