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