—package
Catalyst::Log;
use
Moose;
use
Data::Dump;
use
Class::MOP ();
our
%LEVELS
= ();
# Levels stored as bit field, ergo debug = 1, warn = 2 etc
our
%LEVEL_MATCH
= ();
# Stored as additive, thus debug = 31, warn = 30 etc
has
level
=> (
is
=>
'rw'
);
has
_body
=> (
is
=>
'rw'
);
has
abort
=> (
is
=>
'rw'
);
{
my
@levels
=
qw[ debug info warn error fatal ]
;
my
$meta
= Class::MOP::get_metaclass_by_name(__PACKAGE__);
my
$summed_level
= 0;
for
(
my
$i
=
$#levels
;
$i
>= 0 ;
$i
-- ) {
my
$name
=
$levels
[
$i
];
my
$level
= 1 <<
$i
;
$summed_level
|=
$level
;
$LEVELS
{
$name
} =
$level
;
$LEVEL_MATCH
{
$name
} =
$summed_level
;
$meta
->add_method(
$name
,
sub
{
my
$self
=
shift
;
if
(
$self
->level &
$level
) {
$self
->_log(
$name
,
@_
);
}
});
$meta
->add_method(
"is_$name"
,
sub
{
my
$self
=
shift
;
return
$self
->level &
$level
;
});;
}
}
around
new
=>
sub
{
my
$orig
=
shift
;
my
$class
=
shift
;
my
$self
=
$class
->
$orig
;
$self
->levels(
scalar
(
@_
) ?
@_
:
keys
%LEVELS
);
return
$self
;
};
sub
levels {
my
(
$self
,
@levels
) =
@_
;
$self
->level(0);
$self
->enable(
@levels
);
}
sub
enable {
my
(
$self
,
@levels
) =
@_
;
my
$level
=
$self
->level;
for
(
map
{
$LEVEL_MATCH
{
$_
} }
@levels
){
$level
|=
$_
;
}
$self
->level(
$level
);
}
sub
disable {
my
(
$self
,
@levels
) =
@_
;
my
$level
=
$self
->level;
for
(
map
{
$LEVELS
{
$_
} }
@levels
){
$level
&= ~
$_
;
}
$self
->level(
$level
);
}
our
$HAS_DUMPED
;
sub
_dump {
my
$self
=
shift
;
unless
(
$HAS_DUMPED
++) {
cluck(
"Catalyst::Log::_dump is deprecated and will be removed. Please change to using your own Dumper.\n"
);
}
$self
->info( Data::Dump::
dump
(
@_
) );
}
sub
_log {
my
$self
=
shift
;
my
$level
=
shift
;
my
$message
=
join
(
"\n"
,
@_
);
$message
.=
"\n"
unless
$message
=~ /\n$/;
my
$body
=
$self
->_body;
$body
.=
sprintf
(
"[%s] %s"
,
$level
,
$message
);
$self
->_body(
$body
);
}
sub
_flush {
my
$self
=
shift
;
if
(
$self
->abort || !
$self
->_body ) {
$self
->abort(
undef
);
}
else
{
$self
->_send_to_log(
$self
->_body );
}
$self
->_body(
undef
);
}
sub
_send_to_log {
my
$self
=
shift
;
STDERR
@_
;
}
# 5.7 compat code.
# Alias _body to body, add a before modifier to warn..
my
$meta
= __PACKAGE__->meta;
# Calling meta method here fine as we happen at compile time.
$meta
->add_method(
'body'
,
$meta
->get_method(
'_body'
));
my
%package_hash
;
# Only warn once per method, per package.
# I haven't provided a way to disable them, patches welcome.
$meta
->add_before_method_modifier(
'body'
,
sub
{
my
$class
= blessed(
shift
);
$package_hash
{
$class
}++ ||
do
{
warn
(
"Class $class is calling the deprecated method Catalyst::Log->body method,\n"
.
"this will be removed in Catalyst 5.81"
);
};
});
# End 5.70 backwards compatibility hacks.
no
Moose;
__PACKAGE__->meta->make_immutable(
inline_constructor
=> 0);
1;
__END__
=head1 NAME
Catalyst::Log - Catalyst Log Class
=head1 SYNOPSIS
$log = $c->log;
$log->debug($message);
$log->info($message);
$log->warn($message);
$log->error($message);
$log->fatal($message);
if ( $log->is_debug ) {
# expensive debugging
}
See L<Catalyst>.
=head1 DESCRIPTION
This module provides the default, simple logging functionality for Catalyst.
If you want something different set C<< $c->log >> in your application module,
e.g.:
$c->log( MyLogger->new );
Your logging object is expected to provide the interface described here.
Good alternatives to consider are Log::Log4Perl and Log::Dispatch.
If you want to be able to log arbitrary warnings, you can do something along
the lines of
$SIG{__WARN__} = sub { MyApp->log->warn(@_); };
however this is (a) global, (b) hairy and (c) may have unexpected side effects.
Don't say we didn't warn you.
=head1 LOG LEVELS
=head2 debug
$log->is_debug;
$log->debug($message);
=head2 info
$log->is_info;
$log->info($message);
=head2 warn
$log->is_warn;
$log->warn($message);
=head2 error
$log->is_error;
$log->error($message);
=head2 fatal
$log->is_fatal;
$log->fatal($message);
=head1 METHODS
=head2 new
Constructor. Defaults to enable all levels unless levels are provided in
arguments.
$log = Catalyst::Log->new;
$log = Catalyst::Log->new( 'warn', 'error' );
=head2 level
Contains a bitmask of the currently set log levels.
=head2 levels
Set log levels
$log->levels( 'warn', 'error', 'fatal' );
=head2 enable
Enable log levels
$log->enable( 'warn', 'error' );
=head2 disable
Disable log levels
$log->disable( 'warn', 'error' );
=head2 is_debug
=head2 is_error
=head2 is_fatal
=head2 is_info
=head2 is_warn
Is the log level active?
=head2 abort
Should Catalyst emit logs for this request? Will be reset at the end of
each request.
*NOTE* This method is not compatible with other log apis, so if you plan
to use Log4Perl or another logger, you should call it like this:
$c->log->abort(1) if $c->log->can('abort');
=head2 _send_to_log
$log->_send_to_log( @messages );
This protected method is what actually sends the log information to STDERR.
You may subclass this module and override this method to get finer control
over the log output.
=head2 meta
=head1 SEE ALSO
L<Catalyst>.
=head1 AUTHORS
Catalyst Contributors, see Catalyst.pm
=head1 COPYRIGHT
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
__PACKAGE__->meta->make_immutable;
1;