while ( $line = <> ) #### use Data::Dumper; sub process_record { my $record = join q[], @{+shift}; warn "Malformed record: $record" unless $record =~ /^ \[ (.+?) \] \s+ \[ (.+?) \] \s+ (.+) $/xs; local $Data::Dumper::Terse = 1; print "Got record ", Dumper +{ datetime => $1, status => $2, info => $3, }; } my $current_record; while () { # we have hit a new record if (/^ \[ \d{4}-\d{2}-\d{2} /x) { process_record($current_record) if $current_record; $current_record = []; # start a new record } push @$current_record, $_; } # don't forget to process the final record process_record($current_record) if $current_record; __DATA__ [2012-09-14 16:55:22,498] [ACTIVE] INFO - this is a single line [2012-09-14 16:55:22,498] [ACTIVE] INFO - this is a multi line record [2012-09-14 16:55:22,500] [ACTIVE] INFO - this is another single line [2012-09-14 16:55:22,500] [ACTIVE] INFO - this is yet single line [2012-09-14 16:55:22,500] [ACTIVE] INFO - this one is on two lines [2012-09-14 16:55:22,500] [ACTIVE] INFO - one last record