avoid playing with meta in Catalyst::Log
[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;
0816209f 7use Carp qw/ cluck /;
9b2bc37b 8
c72d2e24 9our %LEVELS = (); # Levels stored as bit field, ergo debug = 1, warn = 2 etc
10our %LEVEL_MATCH = (); # Stored as additive, thus debug = 31, warn = 30 etc
a6433a05 11
3cdcf968 12has level => (is => 'rw');
5fb12dbb 13has _body => (is => 'rw');
3cdcf968 14has abort => (is => 'rw');
1b526dcc 15has autoflush => (is => 'rw', default => sub {1});
21da7377 16has _psgi_logger => (is => 'rw', predicate => '_has_psgi_logger', clearer => '_clear_psgi_logger');
17has _psgi_errors => (is => 'rw', predicate => '_has_psgi_errors', clearer => '_clear_psgi_errors');
50f53fd7 18
19sub clear_psgi {
20 my $self = shift;
21 $self->_clear_psgi_logger;
22 $self->_clear_psgi_errors;
23}
24
25sub psgienv {
26 my ($self, $env) = @_;
27
21da7377 28 $self->_psgi_logger($env->{'psgix.logger'}) if $env->{'psgix.logger'};
29 $self->_psgi_errors($env->{'psgi.errors'}) if $env->{'psgi.errors'};
50f53fd7 30}
31
3cdcf968 32
2f9e6321 33{
a6433a05 34 my @levels = qw[ debug info warn error fatal ];
846772b7 35
c72d2e24 36 my $summed_level = 0;
63475445 37 for my $i ( reverse 0 .. $#levels ) {
846772b7 38
39 my $name = $levels[$i];
eaae9a92 40
846772b7 41 my $level = 1 << $i;
c72d2e24 42 $summed_level |= $level;
eaae9a92 43
a6433a05 44 $LEVELS{$name} = $level;
c72d2e24 45 $LEVEL_MATCH{$name} = $summed_level;
a6433a05 46
63475445 47 no strict 'refs';
48
49 *$name = sub {
846772b7 50 my $self = shift;
51
3cdcf968 52 if ( $self->level & $level ) {
846772b7 53 $self->_log( $name, @_ );
54 }
63475445 55 };
846772b7 56
63475445 57 *{"is_$name"} = sub {
846772b7 58 my $self = shift;
3cdcf968 59 return $self->level & $level;
63475445 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..
63475445 163*body = \&_body;
eaae9a92 164my %package_hash; # Only warn once per method, per package.
71415389 165 # I haven't provided a way to disable them, patches welcome.
63475445 166before body => sub {
71415389 167 my $class = blessed(shift);
168 $package_hash{$class}++ || do {
169 warn("Class $class is calling the deprecated method Catalyst::Log->body method,\n"
170 . "this will be removed in Catalyst 5.81");
171 };
63475445 172};
71415389 173# End 5.70 backwards compatibility hacks.
174
6680c772 175no Moose;
bb7d3f91 176__PACKAGE__->meta->make_immutable;
6680c772 177
846772b7 1781;
179
180__END__
fc7ec1d9 181
a273dd58 182=for stopwords psgienv
183
fc7ec1d9 184=head1 NAME
185
186Catalyst::Log - Catalyst Log Class
187
188=head1 SYNOPSIS
189
82d2fcbe 190 $log = $c->log;
846772b7 191 $log->debug($message);
192 $log->info($message);
193 $log->warn($message);
194 $log->error($message);
195 $log->fatal($message);
846772b7 196
f4dbb0d9 197 if ( $log->is_debug ) {
846772b7 198 # expensive debugging
199 }
82d2fcbe 200
a6433a05 201
fc7ec1d9 202See L<Catalyst>.
203
204=head1 DESCRIPTION
205
adee716c 206This module provides the default, simple logging functionality for Catalyst.
207If you want something different set C<< $c->log >> in your application module,
208e.g.:
82d2fcbe 209
210 $c->log( MyLogger->new );
211
212Your logging object is expected to provide the interface described here.
397be447 213Good alternatives to consider are Log::Log4Perl and Log::Dispatch.
214
215If you want to be able to log arbitrary warnings, you can do something along
216the lines of
217
218 $SIG{__WARN__} = sub { MyApp->log->warn(@_); };
219
220however this is (a) global, (b) hairy and (c) may have unexpected side effects.
221Don't say we didn't warn you.
82d2fcbe 222
a6433a05 223=head1 LOG LEVELS
224
b5ecfcf0 225=head2 debug
a6433a05 226
227 $log->is_debug;
228 $log->debug($message);
229
b5ecfcf0 230=head2 info
a6433a05 231
232 $log->is_info;
233 $log->info($message);
234
b5ecfcf0 235=head2 warn
a6433a05 236
237 $log->is_warn;
238 $log->warn($message);
239
b5ecfcf0 240=head2 error
a6433a05 241
242 $log->is_error;
243 $log->error($message);
244
b5ecfcf0 245=head2 fatal
a6433a05 246
247 $log->is_fatal;
248 $log->fatal($message);
249
b22c6668 250=head1 METHODS
fc7ec1d9 251
b5ecfcf0 252=head2 new
a6433a05 253
26e73131 254Constructor. Defaults to enable all levels unless levels are provided in
a6433a05 255arguments.
256
257 $log = Catalyst::Log->new;
26e73131 258 $log = Catalyst::Log->new( 'warn', 'error' );
a6433a05 259
3cdcf968 260=head2 level
261
262Contains a bitmask of the currently set log levels.
263
b5ecfcf0 264=head2 levels
a6433a05 265
266Set log levels
b22c6668 267
a6433a05 268 $log->levels( 'warn', 'error', 'fatal' );
fc7ec1d9 269
b5ecfcf0 270=head2 enable
fc7ec1d9 271
a6433a05 272Enable log levels
fc7ec1d9 273
a6433a05 274 $log->enable( 'warn', 'error' );
fc7ec1d9 275
b5ecfcf0 276=head2 disable
fc7ec1d9 277
a6433a05 278Disable log levels
fc7ec1d9 279
a6433a05 280 $log->disable( 'warn', 'error' );
fc7ec1d9 281
b5ecfcf0 282=head2 is_debug
a2f2cde9 283
b5ecfcf0 284=head2 is_error
a2f2cde9 285
b5ecfcf0 286=head2 is_fatal
a2f2cde9 287
b5ecfcf0 288=head2 is_info
a2f2cde9 289
b5ecfcf0 290=head2 is_warn
49ba64d7 291
292Is the log level active?
293
b5ecfcf0 294=head2 abort
4be535b1 295
eaae9a92 296Should Catalyst emit logs for this request? Will be reset at the end of
297each request.
4be535b1 298
299*NOTE* This method is not compatible with other log apis, so if you plan
300to use Log4Perl or another logger, you should call it like this:
301
302 $c->log->abort(1) if $c->log->can('abort');
303
1b526dcc 304=head2 autoflush
305
88e5a8b0 306When enabled (default), messages are written to the log immediately instead
307of queued until the end of the request.
1b526dcc 308
88e5a8b0 309This option, as well as C<abort>, is provided for modules such as
310L<Catalyst::Plugin::Static::Simple> to be able to programmatically
1b526dcc 311suppress the output of log messages. By turning off C<autoflush> (application-wide
88e5a8b0 312setting) and then setting the C<abort> flag within a given request, all log
1b526dcc 313messages for the given request will be suppressed. C<abort> can still be set
88e5a8b0 314independently of turning off C<autoflush>, however. It just means any messages
315sent to the log up until that point in the request will obviously still be emitted,
1b526dcc 316since C<autoflush> means they are written in real-time.
317
88e5a8b0 318If you need to turn off autoflush you should do it like this (in your main app
1b526dcc 319class):
320
321 after setup_finalize => sub {
322 my $c = shift;
323 $c->log->autoflush(0) if $c->log->can('autoflush');
324 };
325
adee716c 326=head2 _send_to_log
327
328 $log->_send_to_log( @messages );
329
330This protected method is what actually sends the log information to STDERR.
331You may subclass this module and override this method to get finer control
332over the log output.
333
d298046a 334=head2 psgienv $env
335
336 $log->psgienv($env);
337
338NOTE: This is not meant for public consumption.
339
340Set the PSGI environment for this request. This ensures logs will be sent to
341the right place. If the environment has a C<psgix.logger>, it will be used. If
342not, we will send logs to C<psgi.errors> if that exists. As a last fallback, we
343will send to STDERR as before.
344
a273dd58 345=head2 clear_psgi
346
347Clears the PSGI environment attributes set by L</psgienv>.
348
fc7ec1d9 349=head1 SEE ALSO
350
351L<Catalyst>.
352
2f381252 353=head1 AUTHORS
fc7ec1d9 354
2f381252 355Catalyst Contributors, see Catalyst.pm
fc7ec1d9 356
357=head1 COPYRIGHT
358
536bee89 359This library is free software. You can redistribute it and/or modify
61b1e958 360it under the same terms as Perl itself.
fc7ec1d9 361
362=cut