fredo2906 has asked for the wisdom of the Perl Monks concerning the following question:

Hi!, I am trying to parse log4j date time and check the time difference between line in realtime. If somebody has a better idea to make the below line shorter i would love to see it.
tail -f mylog.log | perl -e 'use POSIX qw( mktime );$l=0;$t=0;while(<S +TDIN>){if(/^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}),(\d{3})/){ $o="$1 +$2"; @a = reverse split( "[-: ]", $1);$a[3]-=1;$a[4]-=1;$a[5]-=1900; +if(!$l){$t=mktime(@a,0,0,0)*1000+$2; $l=1;} else { $t2=mktime(@a,0,0, +0)*1000+$2;$e=$t2-$t;$t=$t2;$l=0;print "$o $e\n";}}}'
Thanks a lot

Replies are listed 'Best First'.
Re: One long liner to make it short
by Corion (Patriarch) on Feb 17, 2014 at 12:34 UTC

    I would peruse perlrun and use some switches to eliminate much of your setup. Also, I'd use timelocal instead of mktime.

    perl -MTime::Local -nle 'if(/^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}),( +\d{3})/){ $o="$1$2"; @a = reverse split( "[-: ]", $1);$a[3]-=1;$a[4]- +=1;$a[5]-=1900; if(!$l){$t=localtime(@a,0,0,0)*1000+$2; $l=1;} else { + $t2=localtime(@a,0,0,0)*1000+$2;$e=$t2-$t;$t=$t2;$l=0;print "$o $e\n +";}}'

    This makes your code a bit shorter. Personally it still feels too long and I would put the code into a script.

    Update: I first had localtime instead of timelocal...

Re: One long liner to make it short
by hdb (Monsignor) on Feb 17, 2014 at 14:51 UTC

    I'll leave it to you to turn it back into a one-liner:

    use POSIX 'mktime'; while(<DATA>){ if(/^((\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2}),(\d{3}) +)/){ $t2=mktime($7,$6,$5,$4-1,$3-1,$2-1900,0,0,0)*1000+$8-$ +t; if($t){print "$1 $t2\n";$t=0}else{$t=$t2} } } __DATA__ 2010-11-04 11:20:04,101 2010-11-04 11:23:10,110 2010-11-05 11:20:04,101 2010-11-05 11:23:10,102

    And I am not saying it is a better way to write this. Just shorter.

      Nice, it is actually better & shorter.
Re: One long liner to make it short
by Bloodnok (Vicar) on Feb 17, 2014 at 14:45 UTC
    Wouldn't it be easier to just let the logger take the strain - use the Log::Log4perl::Layout::PatternLayout log layout configuration and then use either of the %r (mS since program start) or %R (mS since last log event) format specifiers in the appenders' config line ?

    Again, just my 10 penn'orth...

    A user level that continues to overstate my experience :-))
Re: One long liner to make it short
by Anonymous Monk on Feb 17, 2014 at 14:46 UTC
    I expanded it (well, Corion's version) to have multiple lines so the other monks can more easily have a stab at it if they want to.
    while (<STDIN>) { if(/^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}),(\d{3})/) { $o="$1$2"; @a = reverse split( "[-: ]", $1); $a[3]-=1; $a[4]-=1; $a[5]-=1900; if(!$l){ # does this ever happen? $t=localtime(@a,0,0,0)*1000+$2; $l=1; } else { $t2=localtime(@a,0,0,0)*1000+$2; $e=$t2-$t; $t=$t2; $l=0; say "$o $e"; } } }
    I don't think the first if() branch is ever executed.
Re: One long liner to make it short
by Anonymous Monk on Feb 17, 2014 at 16:30 UTC
    And in any sort of real production setting, you would find a CPAN module that incorporates the logic that you need to do, and your one-liner would use that. These approaches are interesting as "golf," but even the time spent redundantly doing as little as this could be considered waste. If "it" has been done (and done well ...) before, by anyone, don't do "it" again.
      Anonymous Monk, Dont really agree, in a REAL production env you do not have an internet access, do not have a local cpan repo and you cant insert any anonymous modules or code without approval which will take you a lot of time to get. You do not have any other way to do it yourself on the spot. That said, it does not help anybody adding such kind of comment.