version 5.90065
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Log.pm
CommitLineData
fc7ec1d9 1package Catalyst::Log;
2
e5ecd5bc 3use Moose;
531f1ab6 4with 'MooseX::Emulate::Class::Accessor::Fast';
5
f63c03e4 6use Data::Dump;
dd5b1dc4 7use Moose::Util 'find_meta';
0816209f 8use Carp qw/ cluck /;
9b2bc37b 9
c72d2e24 10our %LEVELS = (); # Levels stored as bit field, ergo debug = 1, warn = 2 etc
11our %LEVEL_MATCH = (); # Stored as additive, thus debug = 31, warn = 30 etc
a6433a05 12
3cdcf968 13has level => (is => 'rw');
5fb12dbb 14has _body => (is => 'rw');
3cdcf968 15has abort => (is => 'rw');
66ef1679 16has autoflush => (is => 'rw', default => sub {1});
21da7377 17has _psgi_logger => (is => 'rw', predicate => '_has_psgi_logger', clearer => '_clear_psgi_logger');
18has _psgi_errors => (is => 'rw', predicate => '_has_psgi_errors', clearer => '_clear_psgi_errors');
50f53fd7 19
20sub clear_psgi {
21 my $self = shift;
22 $self->_clear_psgi_logger;
23 $self->_clear_psgi_errors;
24}
25
26sub psgienv {
27 my ($self, $env) = @_;
28
21da7377 29 $self->_psgi_logger($env->{'psgix.logger'}) if $env->{'psgix.logger'};
30 $self->_psgi_errors($env->{'psgi.errors'}) if $env->{'psgi.errors'};
50f53fd7 31}
32
3cdcf968 33
2f9e6321 34{
a6433a05 35 my @levels = qw[ debug info warn error fatal ];
846772b7 36
dd5b1dc4 37 my $meta = find_meta(__PACKAGE__);
c72d2e24 38 my $summed_level = 0;
39 for ( my $i = $#levels ; $i >= 0 ; $i-- ) {
846772b7 40
41 my $name = $levels[$i];
eaae9a92 42
846772b7 43 my $level = 1 << $i;
c72d2e24 44 $summed_level |= $level;
eaae9a92 45
a6433a05 46 $LEVELS{$name} = $level;
c72d2e24 47 $LEVEL_MATCH{$name} = $summed_level;
a6433a05 48
4090e3bb 49 $meta->add_method($name, sub {
846772b7 50 my $self = shift;
51
3cdcf968 52 if ( $self->level & $level ) {
846772b7 53 $self->_log( $name, @_ );
54 }
4090e3bb 55 });
846772b7 56
4090e3bb 57 $meta->add_method("is_$name", sub {
846772b7 58 my $self = shift;
3cdcf968 59 return $self->level & $level;
4090e3bb 60 });;
846772b7 61 }
a6433a05 62}
63
4090e3bb 64around new => sub {
65 my $orig = shift;
a6433a05 66 my $class = shift;
4090e3bb 67 my $self = $class->$orig;
e2422920 68
c72d2e24 69 $self->levels( scalar(@_) ? @_ : keys %LEVELS );
e2422920 70
a6433a05 71 return $self;
4090e3bb 72};
a6433a05 73
74sub levels {
75 my ( $self, @levels ) = @_;
76 $self->level(0);
77 $self->enable(@levels);
78}
79
80sub enable {
81 my ( $self, @levels ) = @_;
3cdcf968 82 my $level = $self->level;
c72d2e24 83 for(map { $LEVEL_MATCH{$_} } @levels){
3cdcf968 84 $level |= $_;
85 }
86 $self->level($level);
a6433a05 87}
846772b7 88
a6433a05 89sub disable {
90 my ( $self, @levels ) = @_;
3cdcf968 91 my $level = $self->level;
92 for(map { $LEVELS{$_} } @levels){
93 $level &= ~$_;
94 }
95 $self->level($level);
846772b7 96}
97
0816209f 98our $HAS_DUMPED;
a6433a05 99sub _dump {
846772b7 100 my $self = shift;
0816209f 101 unless ($HAS_DUMPED++) {
102 cluck("Catalyst::Log::_dump is deprecated and will be removed. Please change to using your own Dumper.\n");
103 }
f63c03e4 104 $self->info( Data::Dump::dump(@_) );
846772b7 105}
106
107sub _log {
108 my $self = shift;
109 my $level = shift;
846772b7 110 my $message = join( "\n", @_ );
21da7377 111 if ($self->can('_has_psgi_logger') and $self->_has_psgi_logger) {
cbffbe25 112 $self->_psgi_logger->({
0eb98ebd 113 level => $level,
114 message => $message,
115 });
116 } else {
208732e6 117 $message .= "\n" unless $message =~ /\n$/;
0eb98ebd 118 my $body = $self->_body;
119 $body .= sprintf( "[%s] %s", $level, $message );
cbffbe25 120 $self->_body($body);
0eb98ebd 121 }
cae5df2c 122 if( $self->autoflush && !$self->abort ) {
123 $self->_flush;
124 }
cbffbe25 125 return 1;
4be535b1 126}
127
128sub _flush {
b5ecfcf0 129 my $self = shift;
3cdcf968 130 if ( $self->abort || !$self->_body ) {
b5ecfcf0 131 $self->abort(undef);
132 }
133 else {
3cdcf968 134 $self->_send_to_log( $self->_body );
4be535b1 135 }
3cdcf968 136 $self->_body(undef);
846772b7 137}
138
adee716c 139sub _send_to_log {
140 my $self = shift;
21da7377 141 if ($self->can('_has_psgi_errors') and $self->_has_psgi_errors) {
142 $self->_psgi_errors->print(@_);
0eb98ebd 143 } else {
144 print STDERR @_;
145 }
adee716c 146}
147
71415389 148# 5.7 compat code.
149# Alias _body to body, add a before modifier to warn..
150my $meta = __PACKAGE__->meta; # Calling meta method here fine as we happen at compile time.
151$meta->add_method('body', $meta->get_method('_body'));
eaae9a92 152my %package_hash; # Only warn once per method, per package.
71415389 153 # I haven't provided a way to disable them, patches welcome.
154$meta->add_before_method_modifier('body', sub {
155 my $class = blessed(shift);
156 $package_hash{$class}++ || do {
157 warn("Class $class is calling the deprecated method Catalyst::Log->body method,\n"
158 . "this will be removed in Catalyst 5.81");
159 };
160});
161# End 5.70 backwards compatibility hacks.
162
6680c772 163no Moose;
d14f9123 164__PACKAGE__->meta->make_immutable(inline_constructor => 0);
6680c772 165
846772b7 1661;
167
168__END__
fc7ec1d9 169
a273dd58 170=for stopwords psgienv
171
fc7ec1d9 172=head1 NAME
173
174Catalyst::Log - Catalyst Log Class
175
176=head1 SYNOPSIS
177
82d2fcbe 178 $log = $c->log;
846772b7 179 $log->debug($message);
180 $log->info($message);
181 $log->warn($message);
182 $log->error($message);
183 $log->fatal($message);
846772b7 184
f4dbb0d9 185 if ( $log->is_debug ) {
846772b7 186 # expensive debugging
187 }
82d2fcbe 188
a6433a05 189
fc7ec1d9 190See L<Catalyst>.
191
192=head1 DESCRIPTION
193
adee716c 194This module provides the default, simple logging functionality for Catalyst.
195If you want something different set C<< $c->log >> in your application module,
196e.g.:
82d2fcbe 197
198 $c->log( MyLogger->new );
199
200Your logging object is expected to provide the interface described here.
397be447 201Good alternatives to consider are Log::Log4Perl and Log::Dispatch.
202
203If you want to be able to log arbitrary warnings, you can do something along
204the lines of
205
206 $SIG{__WARN__} = sub { MyApp->log->warn(@_); };
207
208however this is (a) global, (b) hairy and (c) may have unexpected side effects.
209Don't say we didn't warn you.
82d2fcbe 210
a6433a05 211=head1 LOG LEVELS
212
b5ecfcf0 213=head2 debug
a6433a05 214
215 $log->is_debug;
216 $log->debug($message);
217
b5ecfcf0 218=head2 info
a6433a05 219
220 $log->is_info;
221 $log->info($message);
222
b5ecfcf0 223=head2 warn
a6433a05 224
225 $log->is_warn;
226 $log->warn($message);
227
b5ecfcf0 228=head2 error
a6433a05 229
230 $log->is_error;
231 $log->error($message);
232
b5ecfcf0 233=head2 fatal
a6433a05 234
235 $log->is_fatal;
236 $log->fatal($message);
237
b22c6668 238=head1 METHODS
fc7ec1d9 239
b5ecfcf0 240=head2 new
a6433a05 241
26e73131 242Constructor. Defaults to enable all levels unless levels are provided in
a6433a05 243arguments.
244
245 $log = Catalyst::Log->new;
26e73131 246 $log = Catalyst::Log->new( 'warn', 'error' );
a6433a05 247
3cdcf968 248=head2 level
249
250Contains a bitmask of the currently set log levels.
251
b5ecfcf0 252=head2 levels
a6433a05 253
254Set log levels
b22c6668 255
a6433a05 256 $log->levels( 'warn', 'error', 'fatal' );
fc7ec1d9 257
b5ecfcf0 258=head2 enable
fc7ec1d9 259
a6433a05 260Enable log levels
fc7ec1d9 261
a6433a05 262 $log->enable( 'warn', 'error' );
fc7ec1d9 263
b5ecfcf0 264=head2 disable
fc7ec1d9 265
a6433a05 266Disable log levels
fc7ec1d9 267
a6433a05 268 $log->disable( 'warn', 'error' );
fc7ec1d9 269
b5ecfcf0 270=head2 is_debug
a2f2cde9 271
b5ecfcf0 272=head2 is_error
a2f2cde9 273
b5ecfcf0 274=head2 is_fatal
a2f2cde9 275
b5ecfcf0 276=head2 is_info
a2f2cde9 277
b5ecfcf0 278=head2 is_warn
49ba64d7 279
280Is the log level active?
281
b5ecfcf0 282=head2 abort
4be535b1 283
eaae9a92 284Should Catalyst emit logs for this request? Will be reset at the end of
285each request.
4be535b1 286
287*NOTE* This method is not compatible with other log apis, so if you plan
288to use Log4Perl or another logger, you should call it like this:
289
290 $c->log->abort(1) if $c->log->can('abort');
291
cae5df2c 292=head2 autoflush
293
66ef1679 294When enabled (default), messages are written to the log immediately instead
295of queued until the end of the request.
296
297This option, as well as C<abort>, is provided for modules such as
298L<Catalyst::Plugin::Static::Simple> to be able to programmatically
299suppress the output of log messages. By turning off C<autoflush> (application-wide
300setting) and then setting the C<abort> flag within a given request, all log
301messages for the given request will be suppressed. C<abort> can still be set
302independently of turning off C<autoflush>, however. It just means any messages
303sent to the log up until that point in the request will obviously still be emitted,
304since C<autoflush> means they are written in real-time.
305
306If you need to turn off autoflush you should do it like this (in your main app
307class):
308
309 after setup_finalize => sub {
310 my $c = shift;
311 $c->log->autoflush(0) if $c->log->can('autoflush');
312 };
cae5df2c 313
adee716c 314=head2 _send_to_log
315
316 $log->_send_to_log( @messages );
317
318This protected method is what actually sends the log information to STDERR.
319You may subclass this module and override this method to get finer control
320over the log output.
321
d298046a 322=head2 psgienv $env
323
324 $log->psgienv($env);
325
326NOTE: This is not meant for public consumption.
327
328Set the PSGI environment for this request. This ensures logs will be sent to
329the right place. If the environment has a C<psgix.logger>, it will be used. If
330not, we will send logs to C<psgi.errors> if that exists. As a last fallback, we
331will send to STDERR as before.
332
a273dd58 333=head2 clear_psgi
334
335Clears the PSGI environment attributes set by L</psgienv>.
336
3cdcf968 337=head2 meta
338
fc7ec1d9 339=head1 SEE ALSO
340
341L<Catalyst>.
342
2f381252 343=head1 AUTHORS
fc7ec1d9 344
2f381252 345Catalyst Contributors, see Catalyst.pm
fc7ec1d9 346
347=head1 COPYRIGHT
348
536bee89 349This library is free software. You can redistribute it and/or modify
61b1e958 350it under the same terms as Perl itself.
fc7ec1d9 351
352=cut
353
e5ecd5bc 354__PACKAGE__->meta->make_immutable;
355
fc7ec1d9 3561;