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

Hi everybody,
I failed this morning trying to filter a log that has "two line entries" like this:
... 2001-01-28-20:39:16.604+01:00I----- AuthAPI 0x00003e3f\n Could not create socket (24)\n 2001-01-29-11:31:03.973+01:00I----- AuthAPI WARNING\n An unknown user "" was presented to the app.\n ... ...
I´d like to filter it by day-and-message (i.e /2001-01-28.*0x00003e3f$/) --- AND --- type of message (i.e Could not create socket (24))
I begun trying with $/, /xxx/m, /ddd/s ....but at this time I´m lock. Apreciate any help..

Edited 2001-03-14 by mirod: added code and br tags

Replies are listed 'Best First'.
Re: I know...again multiline match!
by Trimbach (Curate) on Mar 14, 2001 at 18:24 UTC
    You didn't say what kind of filtering you're doing, but if it were me I'd slurp in 2 lines at a time instead of the normal 1. For example:
    open (F, "log.txt") or die "Couldn't open: $!"; while (1) { my $line1 = <F>; # Get a line my $line2 = <F>; # Get another line last unless defined($line1); # bail if there's no data #... now you can filter what you want here, # match, print, push whatever. All the data you # care about is in $line1 and $line2 }

    Gary Blackburn
    Trained Killer

    Edited: Cleaned up the code a bit

Re: I know...again multiline match!
by Masem (Monsignor) on Mar 14, 2001 at 19:40 UTC
    Something like this, possibly...
    while( my $line = <FILE> . <FILE> ) { chomp $line; # gets rid of the trailing \n # on second line to allow $ on # the regex below. $line =~ /^(\d{4}-\d{2}-\d{2}).*-{5}\s\S*?\s(\S*)\s(.*)$/; my ( $day, $message, $type ) = ( $1, $2, $3 ); # do what you need to with these }
    This assumes that the '-----' and 'AuthAPI' are fixed words in your log file, since, at least in the case of '-----', that helps to skip past the date and other information at the start of line 1. If AuthAPI is not necessarily fixed, but the message (0x00003e3f in this case) is the last thing on line 1, then the following will work...
    while( ( $line1 = <FILE> ) && ( $line2 = <FILE> ) ) { chomp $line1; chomp $line2; $line1 =~ /^(\d{4}-\d{2}-\d{2}).*\s(.*)$/; my ( $date, $message, $type ) = ( $1, $2, $line2 ); # continue on... }

    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: I know...again multiline match!
by Anonymous Monk on Mar 14, 2001 at 19:18 UTC
    to complete what's been said...and with the type of lines you submitted: I'd try:
    ... $date = substr($line1, 0, 30); $message = chomp(substr($line1, 44, length($line1)); $msg = chomp($line2); # that's the type of message here ...
Re: I know...again multiline match!
by gregor42 (Parson) on Mar 15, 2001 at 03:36 UTC
    Use /m, /s, or both as pattern modifiers.

    /s lets . match newline
    /m lets ^ and $ match NEXT TO a newline
    This is straight out of the PERL Cookbook, by Tom Christiansen & Nathan Torkington (O'Reilly).
    You also might look at the format of the log file more closely.
    If EVERY entry is 2 lines then it's a simple matter of changing the iteration & then replacing the \n's with whitespace.
    If it varies, then you want to test for the pattern that Starts the next line.
    It looks like you have a datestamp there that you could match against. Of course when you're done, you may want to:
    for $entry(@logentries) { $ entry =~ tr/(\n|\r)//g; }
    I hope that helps & isn't too obvious.



    Hey! This isn't a parachute, it's a backpack!!!