LovelyGeek
LovelyGeek

Reputation: 39

How to print lines from log file which occurs after some particular time

I want to print all the lines which lets say occur after a time whose value is returned by localtime function of perl inside a perl script. I tried something like below:

my $timestamp = localtime();
open(CMD,'-|','cat xyz.log | grep -A1000 \$timestamp' || die ('Could not open');
while (defined(my $line=<CMD>)){
    print $line;
}

If I replace the $timestamp in cat command with actaul time component from xyz.log then it print lines but its not printing with $timestamp variable.

Is there any alternative way I can print lines that occurs after current time in log files or how i can improve above command?

Upvotes: 4

Views: 894

Answers (4)

zdim
zdim

Reputation: 66883

Your $timestamp is never evaluated in Perl as it appears only in single quotes. But why go out to shell in order to match a string and process a file? Perl is far better for that.

Here is a direct way first, then a basic approach. A full script is shown in the second example.

Read the file until you get to the line with the pattern, and exit the loop at that point. The next time you access that filehandle you'll be on the next line and can start printing, in another loop.

while (<$fh>) { last if /$timestamp/ }

print while <$fh>;

This prints out the part of the file starting with the line following the one which has the $timestamp anywhere in it. Adjust how exactly to match the timestamp if it is more specific.

Or -- set a flag when a line matches the timestamp, print if flag is set.

use warnings 'all';
use strict;

my $timestamp = localtime();

my $logile = 'xyz.log';
open my $fh, '<', $logfile or die "Can't open $logfile: $!";

my $mark = 0;
while (<$fh>) 
{
    if (not $mark) { 
        $mark = 1 if /$timestamp/;
    }
    else { print }
}
close $fh;

Upvotes: 2

Sanjay
Sanjay

Reputation: 11

You may also try this approach:

In this case, I tried to open /var/log/messages then convert each line timestamp to epoch and finding all the lines which has occurred after time()

use Date::Parse;
my $epoch_now = time(); # print epoch current time.
open (my $fh, "</var/log/messages") || die "error: $!\n";

while (<$fh>) {
    chomp;
    # one log line - looks like this
    # Sep  9 08:17:01 localhost rsyslogd: rsyslogd was HUPed
    my ($mon, $day, $hour, $min, $sec) = ($_ =~ /(\S+)\s*(\d+)\s*(\d+):(\d+):(\d+)/);

    # date string part shouldn't be empty
    if (defined($mon) && defined($day)
        && defined($hour) && defined($min)
        && defined($sec)) {
        my $epoch_log = str2time("$mon $day $hour:$min:$sec");
        if ($epoch_log > $epoch_now) {
            print, "\n";
        }
    }
}

Upvotes: 0

mbethke
mbethke

Reputation: 935

If you're doing the grepping in Shell anyway you might as well do it the other way round and call perl only to give you the result of localtime:

 sed <xyz.log -ne"/^$(perl -E'say scalar localtime')/,\$p"

This uses sed's range addressing: first keep it from printing lines unless explicitly told so using -n, the select everything between the first occurrence of the timestamp (I added a ^ for good measure, just in case log lines could contain time stamps in plain text) and the end of file ($) and print it (p).

A pure Perl solution could look like this:

my $timestamp = localtime();
my $found;
open(my $fh, '<', 'xyz.log') or die ('Could not open xyz.log: $!');
while (<$fh>) {
    if($found) {
        print;
    } else {
        $found = 1 if /^$timestamp/;
    }
}

Upvotes: 1

Chankey Pathak
Chankey Pathak

Reputation: 21666

I would suggest a Perlish approach like below:

open (my $cmd, "<", "xyz.log") or die $!;
#get all lines in an array with each index containing each line
my @log_lines = <$cmd>;

my $index = 0;

foreach my $line (@log_lines){
    #write regex to capture time from line
    my $rex = qr/regex_for_time_as_per_logline/is;
    if ($line =~ /$rex/){
        #found the line with expected time
        last;
    }
    $index++;
}

#At this point we have got the index of array from where our expected time starts.
#So all indexes after that have desired lines, which you can write as below

foreach ($index..$#log_lines){
    print $log_lines[$_];
}

If you share one of your logline, I could help with the regex.

Upvotes: 0

Related Questions