The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Dist::Zilla::Role::ErrorLogger - Have error logging capabilities in your Dist::Zilla plugin

VERSION

Version v0.9.0, released on 2015-10-26 21:04 UTC.

WHAT?

Dist-Zilla-Role-ErrorLogger is a Dist::Zilla role. It provides log_error, abort, and abort_if_errors methods to consuming plugins.

This is Dist::Zilla::Role::ErrorLogger role documentation. Read this if you want to have error logging capabilities in your Dist::Zilla plugin.

SYNOPSIS

    package Dist::Zilla::Plugin::YourPlugin;
    use Moose;
    use namespace::autoclean;
    with 'Dist::Zilla::Role::Plugin';
    with 'Dist::Zilla::Role::ErrorLogger';

    sub method {
        my $self = shift( @_ );

        if ( $cond ) { $self->log_error( 'error message' ); };

        do_something or $self->log_error( 'another error message' );

        while ( $cond ) {
            do_something_else or $self->log_error( 'error message' ) and next;
            ...;
        };

        $self->log_errors_in_file(
            $file,
            1 => 'error message',           # Error at file line 1.
            5 => 'another error message',   # Error at file line 5.
        );

        $self->abort_if_errors( 'errors found' );
    };

    __PACKAGE__->meta->make_immutable;
    1;

DESCRIPTION

The role extends standard Dist::Zilla logging capabilities with few methods a bit more convenient for reporting (multiple) errors than brutal log_fatal. See "WHY?" for more details.

The role requires log method in the consumer.

OBJECT ATTRIBUTES

error_count

    $int = $self->error_count;

Int, read-only. Number of logged errors (i. e. number of made log_error calls).

OBJECT METHODS

log_error

    $self->log_error( @items );
    $self->log_error( \%args, @items );

This method calls log method, passing all the arguments, and increments value of error_count attribute. The method returns true value, so can be used in following constructs:

    while ( ... ) {
        do_something or $self->log_error( 'message' ) and next;
        ...
    };

abort

    $self->abort( @items );
    $self->abort( \%args, @items );

This is an attempt to workaround log_fatal drawback: in contrast to log_fatal, abort guarantees the message (which can be quite long) appears on the screen only once.

The method log the message (via log), then flush STDOUT, then throws an exception of Dist::Zilla::Role::ErrorLogger::Exception::Abort class (which being stringified gives short message "Aborting...\n").

abort_if_error

abort_if_errors

    $self->abort_if_errors( @items );
    $self->abort_if_errors( \%args, @items );

If there was any errors (i. e. error_count is greater than zero), the logs all the arguments and aborts execution. Both actions (logging and aborting) are implemented by calling abort.

abort_if_error is an alias for abort_if_errors.

log_errors_in_file

The method intended to report errors against a file. It prints file name (and colon after it), then prints line-numbered file content annotated by error messages. The method does not print entire file content, but only error lines with surrounding context (2 lines above and below each error line).

    $self->log_errors_in_file(
        $file,
        $linenum1 => $message1,
        $linenum2 => $message2,
        $linenum3 => [ $message3a, $message3b, ... ],
        ...
    );

$file should be a Dist::Zilla file (e. g. Dist::Zilla::File::OnDisk, Dist::Zilla::File::InMemory, or does role Dist::Zilla::Role::File).

Errors are specified by pairs $linenum => $message, where $linenum is a number of problem line (one-based), and $message is an error message (Str) or array of messages (ArrayRef[Str]). Order of errors does not matter usually. However, if errors are associated with the same line (the same line number may appear multiple times), they will be printed in order of appearance.

Zero or negative line numbers, or line numbers beyond the last line are invalid. Messages associated with invalid line numbers are reported in unspecified way.

Normally, the method prints all the information by calling log_error method and returns a positive integer. However, If any invalid line numbers are specified, the method returns negative integer. If no errors are specified, the method prints "No errors found at file." by calling log (not log_error!) and returns zero.

TODO: Example.

WHY?

Dist::Zilla limits logging capabilities with 3 logging levels available in plugins through log_debug, log, and log_fatal methods. Debug level messages are turned off by default, the first fatal message terminates Dist::Zilla. This is simple, but sometimes you may want to report all the errors, instead of stopping at the first found one. In such a case log_fatal cannot be used, obviously. There are few alternatives:

Collect error messages in an array, then report all the errors with single log_fatal call:

    my @errors;
    ...
    push( @errors, ... );
    ...
    if ( @errors ) {
        $self->log_fatal( join( "\n", @errors ) );
    };

This works, but current implementation of log_fatal has a disadvantage: it prints the message twice, so output looks ugly. (See message handling in log_fatal is suboptimal.)

Another approach is reporting each error immediately with log, counting number of reported errors, and calling log_fatal once at the end:

    my $error_count = 0;
    ...
    $self->log( 'error' );
    ++ $error_count;
    ...
    if ( $error_count ) {
        $self->log_fatal( 'Aborting...' );
    };

This works, but incrementing the counter after each log call is boring and error-prone. Dist-Zilla-Role-ErrorLogger role automates it, making plugin code shorter and more readable:

    with 'Dist-Zilla-Role-ErrorLogger';
    ...
    $self->log_error( 'error' );
    ...
    $self->abort_if_errors();

NOTES

All the methods defined in the role log items through the log method. Dist::Zilla takes this method from Log::Dispatchouli, the latter uses String::Flogger to process the messages. It means you can use String::Flogger tricks, e. g.:

    $self->log_error( [ 'oops at %s line %d', $file, $line ] );
        #   [] are shorter than sprintf.

Also note how Log::Dispatchouli describes the log method:

    $logger->log( @messages );

and says:

    Each message is flogged individually, then joined with spaces.

So beware. A call

    $self->log_error( 'error 1', 'error 2' );

logs one message "error 1 error 2", not two messages "error 1" and "error 2", and bumps error_count by 1, not 2.

SEE ALSO

Dist::Zilla
Dist::Zilla::Role
Dist::Zilla::Plugin
Log::Dispatchouli
String::Flogger

AUTHOR

Van de Bugger <van.de.bugger@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2015 Van de Bugger

License GPLv3+: The GNU General Public License version 3 or later <http://www.gnu.org/licenses/gpl-3.0.txt>.

This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.