The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Log::Any::Progress - log incremental progress using Log::Any

VERSION

Version 1.00

SYNOPSIS

  use Log::Any::Progress;

  use Log::Any::Adapter 'Stderr';

  my $progress = Log::Any::Progress->new(
      count  => $num_things_to_do,
      prefix => 'Processing widgets',
  );

  foreach my $thing_to_do (@things_to_do) {
      do_the_thing($thing_to_do);
      $progress->update;
  }

DESCRIPTION

This module makes it easy to use Log::Any to log incremental progress, similar in concept to Term::ProgressBar. It can be useful for monitoring the progress of a long-running process and to get an idea of how long that process might take to finish.

It is generally applied to a processing loop. In the typical case where the expected number of iterations is known in advance, it produces output containing the iteration count, percent completion, elapsed time, average time per iteration, and estimated time remaining. For example:

  Progress: Iteration:0/5 0% STARTING
  Progress: Iteration:1/5 20% Elapsed:2.000s Avg:2.000s Remaining:8.001s
  Progress: Iteration:2/5 40% Elapsed:4.001s Avg:2.000s Remaining:6.001s
  Progress: Iteration:3/5 60% Elapsed:6.001s Avg:2.000s Remaining:4.001s
  Progress: Iteration:4/5 80% Elapsed:8.001s Avg:2.000s Remaining:2.000s
  Progress: Iteration:5/5 100% FINISHED Elapsed:10.002s Avg:2.000s

The remaining time estimate as of any particular iteration is a simple linear calculation based on the average time per iteration up to that point, and the number of remaining iterations.

If the expected number of iterations is not known in advance, it still reports on incremental progress, but cannot compute either percent completion or estimated remaining time. For example:

  Progress: Iteration:0 STARTING
  Progress: Iteration:1 Elapsed:2.000s Avg:2.000s
  Progress: Iteration:2 Elapsed:4.001s Avg:2.000s
  Progress: Iteration:3 Elapsed:6.001s Avg:2.000s
  Progress: Iteration:4 Elapsed:8.001s Avg:2.000s
  Progress: Iteration:5 Elapsed:10.001s Avg:2.000s

METHODS

new

  my $progress = Log::Any::Progress->new(

      count => $num_things_to_do,    # mandatory

      delayed_start            => 1,
      logger                   => $logger,
      log_level                => 'info',
      log_level_start_finish   => 'notice',
      min_sec_between_messages => 10,
      prefix                   => 'Processing widgets',
  );

Create a new object for logging incremental progress. Options include:

count

A mandatory non-zero count of the expected number of iterations for progress tracking.

Specifying -1 indicates that the expected number of iterations is unknown, in which case abbreviated statistics will be logged for each iteration (percent completion and estimated finish time cannot be computed without knowing the expected number of iterations in advance).

delayed_start

An optional boolean value controlling whether or not "start" should be automatically called at time of object construction. It defaults to false, in which case "start" is automatically called, assuming that progress tracking will commence immediately after.

Specifying a true value for delayed_start will prevent "start" from being automatically called, in which case it should be explicitly called just before progress iteration begins.

logger

An optional Log::Any logger object to use for logging.

If not specified, a logger object will be obtained via Log::Any->get_logger(), which will in turn use whatever Log::Any::Adapter might be configured.

If not specifying a logger object, you will want to make sure that some adapter other than the default Log::Any::Adapter::Null adapter is configured (for example, Log::Any::Adapter::Stderr), otherwise no log messages will be emitted.

log_level

An optional Log::Any log level for the incremental progress lines. It defaults to info.

Valid log levels include:

  trace
  debug
  info (inform)
  notice
  warning (warn)
  error (err)
  critical (crit, fatal)
  alert
  emergency
log_level_start_finish

An optional Log::Any log level for the start and finish progress lines. It defaults to notice.

Valid log levels include:

  trace
  debug
  info (inform)
  notice
  warning (warn)
  error (err)
  critical (crit, fatal)
  alert
  emergency
min_sec_between_messages

An optional value for the minimum number of seconds to wait before emitting the next incremental progress log message (as a result of calling "update"). Values specifying fractional seconds are allowed (e.g. 0.5). It defaults to 10 seconds.

Setting min_sec_between_messages appropriately can be used to control log verbosity in cases where many hundreds or thousands of iterations are being processed and it's not necessary to report after each iteration. Setting it to 0 will result in every incremental progress message will be emitted.

prefix

An optional string which will be used to prefix each logged message. It defaults to Progress.

start

  my $progress = Log::Any::Progress->new(
      count => $num_things_to_do,
      delayed_start => 1,  # don't start the timer yet
  );

  # Do some other work here that might take some time...

  $progress->start;

  foreach my $thing_to_do (@things_to_do) {
      do_the_thing($thing_to_do);
      $progress->update;
  }

Initialize (or reinitialize) the progress object by resetting the start time, elapsed time, etc.

This is normally called automatically at object construction time unless "delayed_start" is specified, in which case it should be called explicitly at the appropriate time.

Initializing the progress object (whether done automatically or manually) causes the first log message to be emitted.

update

  my $progress = Log::Any::Progress->new(
      count => $num_things_to_do,
  );

  foreach my $thing_to_do (@things_to_do) {
      do_the_thing($thing_to_do);
      $progress->update;
  }

Update the iteration count within the progress object and maybe emit a corresponding log message showing the current progress statistics (depending on timing and the value of "min_sec_between_messages").

Calling update with no arguments increments the internal iteration count by one. A positive interger may be passed as an argument to explicitly update the iteration count to a particular value.

Once the iteration count reaches the specified "count" value, the progress is considered to be complete and a final log message is emitted with summary statistics, and subsequent calls to update will have no effect.

format_seconds

  my $string = $progress->format_seconds($elapsed_seconds);

This methods formats the elapsed time, average time, and remaining time values from seconds into something more easily readable. For example, 10000 seconds is formatted as 2h46m40.000s.

It can be overridden in a subclass if desired.

AUTHOR

Larry Leszczynski, <larryl at cpan.org>

BUGS

Please report any bugs or feature requests through the web interface at https://github.com/larryl/Log-Any-Progress.

I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

  perldoc Log::Any::Progress

You can also look for information at:

LICENSE AND COPYRIGHT

This software is Copyright (c) 2023 by Larry Leszczynski.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)