#!/usr/local/bin/perl # # NAME # dtgrep # # # SYNOPSIS # dtgrep [-v] [-b time] [-e time] [file] # # # DESCRIPTION # This script greps entries out of a Mon downtime log, according to # criteria that you specify. It is meant as an aid for pruning and # rotating downtime logs, although it might also have other uses, # e.g., querying a downtime log for failures over a certain period. # The returned results are sent to STDOUT. # # The format of a downtime log is a header consisting of comment lines, # which serves to tell the format of the dtlog as well as when the dtlog # was (re)started. The most recent comment string is preserved along with # all of the log entries from that time. If no matching log entries are # found, nothing is printed. # # If no input file is specified, dtgrep reads from STDIN. # # # OPTIONS # -v Writes information about what dtgrep is doing to STDERR. # # # -b Time, counting back from the present, to BEGIN retrieving # downtime log entries. # # Time must be specified as {number}[dhms], e.g. "3m" (3 minutes), # "2.5h" (2.5 hours), or "5d" (5 days) are all valid formats. # If no -b option is specified, the default time to go back in # the log is "30d" (30 days). # # # -e Time, counting back from the present, to END retrieving # downtime log entries. # # Time must be specified as {number}[dhms], e.g. "3m" (3 minutes), # "2.5h" (2.5 hours), or "5d" (5 days) are all valid formats. # If no -e option is specified, the default time to stop going # back in the log is "0s" (0 seconds, i.e. "the time at which # the script is run"). # # # EXIT STATUS # 0 The command completed successfully. # # 1 The specified input file could not be opened for reading. # # # SEE ALSO # Mon, by Jim Trocki . # http://www.kernel.org/software/mon/ # # # EXAMPLES # The following 2 commands are identical ways of bringing back the # last 2 days' downtime log from a file called "dt.log": # dtgrep -b 2d -e0s dt.log # dtgrep -b 2d dt.log # # Grab the downtime log for the time period beginning 30 days ago # and ending 48 hours ago, and print some more verbose information # about what is being returned: # dtgrep -b 30d -e48h dt.log # # Here is an example of "rotating" a dtlog file, by invoking dtgrep # twice, once to grab all downtimes between some arbitrarily large amount # of time (1000 days in this case) and the last 60 days ; and another # dtgrep job to put the last 60 days in another file. Finally we move # the "last 60 days" log file to dt.log so it becomes the new default dtlog. # dtgrep -b1000d -e60d dt.log > dt.allbutlast60d # dtgrep -b60d dt.log > dt.last60d # mv dt.last60d dt.log # # # NOTES # # # # AUTHORS # Andrew Ryan # $Id: dtgrep,v 1.7 2000/05/04 03:22:28 andrewr Exp $ # # # BUGS # Report bugs to the author. # # # COPYRIGHT # Copyright (C) 2000 Andrew Ryan # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # use vars qw /$opt_v $opt_b $opt_e/; use strict; use Getopt::Std; Getopt::Std::getopts('b:e:v'); my ($dtlogfile) = (@ARGV); $dtlogfile = "-" if $dtlogfile eq ""; #Use STDIN if no filename specified my $time_now = time; my $time_younger_than = &dhmstos($opt_b) || &dhmstos("30d") ; #default time younger than is 30 days my $time_younger_than_min = $time_now - $time_younger_than; my $time_older_than = &dhmstos($opt_e) || &dhmstos("0s") ; #default time older than is 0 seconds my $time_older_than_max = $time_now - $time_older_than; my $found_oldest = 0; my $found_youngest = 0; my $last_line_was_comment = 0; my (@comment_lines, @line, @new_dtlog); if ($opt_v) { print STDERR "Will look for all downtime events between $time_younger_than_min "; print STDERR "(", &format_date($time_younger_than_min) , ")"; print STDERR " and $time_older_than_max "; print STDERR "(", &format_date($time_older_than_max) , ")"; print STDERR "\n"; } if ( open(DTLOG, "$dtlogfile") ) { while () { chomp; if (/^\#/) { #line is a comment, gather these separately undef @comment_lines if $last_line_was_comment == 0; push(@comment_lines, $_); $last_line_was_comment = 1; next; } else { $last_line_was_comment = 0; } @line = split(' ' , $_); if ( ($line[0] >= $time_younger_than_min) && ($line[0] <= $time_older_than_max) ) { #line is in the specified time range, grab it print STDERR "Found dtlog entry exceeding youngest requested time at $line[0] (", &format_date($line[0]) , ")\n" if $opt_v && $found_oldest == 0; $found_oldest = 1; push(@new_dtlog, $_); } if ($line[0] > $time_older_than_max) { #we've exceeded the end time, quit looking print STDERR "Found dtlog entry exceeding oldest requested time at $line[0] (", &format_date($line[0]) , ")\n" if $opt_v && $found_youngest == 0; $found_youngest = 1; last; } } if ($opt_v) { @line = split(' ', $new_dtlog[-1]); #grab last entry in dtlog print STDERR "Last matching downtime event found at ", $line[0], " (", &format_date($line[0]) , ") \n"; } } else { die "ERROR: Unable to open dtlogfile $dtlogfile: $!"; exit 1; } if (scalar(@new_dtlog) > 0) { print join("\n", @comment_lines) , "\n" ; print join("\n", @new_dtlog) , "\n"; } exit 0; # # convert a string like "20m" into 20*60 seconds # stolen from Jim Trocki's mon # (http://www.kernel.org/pub/software/admin/mon/html/) sub dhmstos { my ($str) = @_; my ($s); if ($str =~ /^\s*(\d+(?:\.\d+)?)([dhms])\s*$/i) { if ($2 eq "m") { $s = $1 * 60; } elsif ($2 eq "h") { $s = $1 * 60 * 60; } elsif ($2 eq "d") { $s = $1 * 60 * 60 * 24; } else { $s = $1; } } else { return undef; } $s; } sub format_date { # takes a time() and returns a formatted date string # no error checking or input validation! my @localtime = localtime($_[0]); my @year_months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); my @days_of_week = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); return sprintf ("%s, %.2d-%s-%d %.2d:%.2d:%.2d", @days_of_week[$localtime[6]], $localtime[3], @year_months[$localtime[4]], $localtime[5] + 1900, @localtime[2,1,0]); }