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