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