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
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.