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