Log::Progress::Parser - Parse progress data from a file


version 0.12


  open my $fh, "<", $logfile or die;
  my $parser= Log::Progress::Parser->new(input => $fh);

A practical application:

  # Display a 40-character progress bar at 1-second intervals
  $|= 1;
  while (1) {
    printf "\r%3d%%  [%-40s] ",
      "#" x int($parser->state->{progress}*40);
    last if $parser->state->{progress} >= 1;
    sleep 1;
  print "\n";


This module parses progress messages from a file handle or string. Repeated calls to the "parse" method will continue parsing the file where it left off, making it relatively efficient to repeatedly call "parse" on a live log file.



This is a seekable file handle or scalar of log text from which the progress data will be parsed. Make sure to set the utf-8 layer on the file handle if you want to read progress messages that are more than just ascii.


Each call to parse makes a note of the start of the final un-finished line, so that the next call can pick up where it left off, assuming the file is growing and the file handle is seekable.


This is a hashref of data describing the progress found in the input.

    progress => $number_between_0_and_1,
    message  => $current_progress_messsage,  # empty string if no message
    current  => $numerator,   # only present if progress was a fraction
    total    => $denominator, #
    step     => { $step_id => \%step_state, ... },
    data     => \%data,       # most recent JSON data payload, decoded

Substeps may additionally have the keys:

    idx          => $order_of_declaration,   # useful for sorting
    title        => $name_of_this_step,
    contribution => $percent_of_parent_task, # can be undef


Defaults to false. If set to true, then progress lines lacking a message will not clear the message of a previous progress line.


Optional coderef to handle JSON data discovered on input. The return value of this coderef will be stored in the "data" field of the current step.

For example, you might want to combine all the data instead of overwriting it:

  my $parser= Log::Progress::Parser->new(
    on_data => sub {
      my ($parser, $step_id, $data)= @_;
      my $prev_data= $parser->step_state($step_id)->{data} || {};
      return Hash::Merge::merge( $prev_data, $data );



Read (any additional) "input", and return the "state" field, or die trying.

  my $state= $parser->parse;

Sets "input_pos" just beyond the end of the final complete line of text, so that the next call to "parse" can follow a growing log file.


  my $state= $parser->step_state($step_id, $create_if_missing);
  my $state= $parser->step_state($step_id, $create_if_missing, \@path_out);

Convenience method to traverse "state" to get the data for a step. If the second paramter is false, this returns undef if the step is not yet defined. Else it creates a new state node, with idx initialized.

If you pass the third parameter @path_out it will receive a list of the parent nodes of the returned state node.


Michael Conrad <>


This software is copyright (c) 2020 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.