release 0.00202
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
CommitLineData
0daa11f3 1package Log::Contextual;
2
a2777569 3use strict;
4use warnings;
2033c911 5
733e43a7 6our $VERSION = '0.00202';
2033c911 7
8require Exporter;
f11f9542 9use Data::Dumper::Concise;
5b094c87 10use Scalar::Util 'blessed';
2033c911 11
a2777569 12BEGIN { our @ISA = qw(Exporter) }
2033c911 13
9b8e24d5 14my @dlog = (qw(
f11f9542 15 Dlog_debug DlogS_debug
16 Dlog_trace DlogS_trace
17 Dlog_warn DlogS_warn
18 Dlog_info DlogS_info
19 Dlog_error DlogS_error
20 Dlog_fatal DlogS_fatal
9b8e24d5 21 ));
f11f9542 22
9b8e24d5 23my @log = (qw(
9061df76 24 log_debug logS_debug
25 log_trace logS_trace
26 log_warn logS_warn
27 log_info logS_info
28 log_error logS_error
29 log_fatal logS_fatal
9b8e24d5 30 ));
f11f9542 31
a2777569 32our @EXPORT_OK = (
f11f9542 33 @dlog, @log,
9b8e24d5 34 qw( set_logger with_logger )
f11f9542 35);
36
a2777569 37our %EXPORT_TAGS = (
f11f9542 38 dlog => \@dlog,
39 log => \@log,
3dc9bd3c 40 all => [@dlog, @log],
f11f9542 41);
42
43sub import {
a2777569 44 my $package = shift;
f11f9542 45 die 'Log::Contextual does not have a default import list'
a2777569 46 unless @_;
47
48 for my $idx ( 0 .. $#_ ) {
3ccc9c47 49 my $val = $_[$idx];
50 if ( defined $val && $val eq '-logger' ) {
a2777569 51 set_logger($_[$idx + 1]);
52 splice @_, $idx, 2;
3ccc9c47 53 } elsif ( defined $val && $val eq '-default_logger' ) {
54 _set_default_logger_for(scalar caller, $_[$idx + 1]);
06e908c3 55 splice @_, $idx, 2;
a2777569 56 }
57 }
58 $package->export_to_level(1, $package, @_);
f11f9542 59}
2033c911 60
7cec609c 61our $Get_Logger;
5d8f2b84 62our %Default_Logger;
63
3ccc9c47 64sub _set_default_logger_for {
65 my $logger = $_[1];
66 if(ref $logger ne 'CODE') {
67 die 'logger was not a CodeRef or a logger object. Please try again.'
68 unless blessed($logger);
69 $logger = do { my $l = $logger; sub { $l } }
70 }
71 $Default_Logger{$_[0]} = $logger
72}
06e908c3 73
5d8f2b84 74sub _get_logger($) {
75 my $package = shift;
76 (
77 $Get_Logger ||
78 $Default_Logger{$package} ||
79 die q( no logger set! you can't try to log something without a logger! )
06e908c3 80 )->($package);
5d8f2b84 81}
7cec609c 82
8dc5a747 83sub set_logger {
84 my $logger = $_[0];
5b094c87 85 if(ref $logger ne 'CODE') {
86 die 'logger was not a CodeRef or a logger object. Please try again.'
87 unless blessed($logger);
88 $logger = do { my $l = $logger; sub { $l } }
89 }
5d8f2b84 90
91 warn 'set_logger (or -logger) called more than once! This is a bad idea!'
92 if $Get_Logger;
8dc5a747 93 $Get_Logger = $logger;
7cec609c 94}
95
98833ffb 96sub with_logger {
97 my $logger = $_[0];
5b094c87 98 if(ref $logger ne 'CODE') {
99 die 'logger was not a CodeRef or a logger object. Please try again.'
100 unless blessed($logger);
101 $logger = do { my $l = $logger; sub { $l } }
102 }
98833ffb 103 local $Get_Logger = $logger;
80c3e48b 104 $_[1]->();
2daff231 105}
106
d11de6ae 107sub _do_log {
108 my $level = shift;
109 my $logger = shift;
110 my $code = shift;
111 my @values = @_;
112
113 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 2;
114 $logger->$level($code->(@_))
115 if $logger->${\"is_$level"};
116 @values
117}
118
119sub _do_logS {
120 my $level = shift;
121 my $logger = shift;
122 my $code = shift;
123 my $value = shift;
124
125 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 2;
126 $logger->$level($code->($value))
127 if $logger->${\"is_$level"};
709d11fe 128 $value
129}
130
d11de6ae 131sub log_trace (&@) { _do_log( trace => _get_logger( caller ), shift @_, @_) }
132sub log_debug (&@) { _do_log( debug => _get_logger( caller ), shift @_, @_) }
133sub log_info (&@) { _do_log( info => _get_logger( caller ), shift @_, @_) }
134sub log_warn (&@) { _do_log( warn => _get_logger( caller ), shift @_, @_) }
135sub log_error (&@) { _do_log( error => _get_logger( caller ), shift @_, @_) }
136sub log_fatal (&@) { _do_log( fatal => _get_logger( caller ), shift @_, @_) }
709d11fe 137
d11de6ae 138sub logS_trace (&$) { _do_logS( trace => _get_logger( caller ), $_[0], $_[1]) }
139sub logS_debug (&$) { _do_logS( debug => _get_logger( caller ), $_[0], $_[1]) }
140sub logS_info (&$) { _do_logS( info => _get_logger( caller ), $_[0], $_[1]) }
141sub logS_warn (&$) { _do_logS( warn => _get_logger( caller ), $_[0], $_[1]) }
142sub logS_error (&$) { _do_logS( error => _get_logger( caller ), $_[0], $_[1]) }
143sub logS_fatal (&$) { _do_logS( fatal => _get_logger( caller ), $_[0], $_[1]) }
709d11fe 144
f11f9542 145
146sub Dlog_trace (&@) {
147 my $code = shift;
d11de6ae 148 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
149 return _do_log( trace => _get_logger( caller ), $code, @_ );
f11f9542 150}
151
a4273dbf 152sub Dlog_debug (&@) {
153 my $code = shift;
d11de6ae 154 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
155 return _do_log( debug => _get_logger( caller ), $code, @_ );
a4273dbf 156}
157
158sub Dlog_info (&@) {
159 my $code = shift;
d11de6ae 160 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
161 return _do_log( info => _get_logger( caller ), $code, @_ );
a4273dbf 162}
163
164sub Dlog_warn (&@) {
165 my $code = shift;
d11de6ae 166 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
167 return _do_log( warn => _get_logger( caller ), $code, @_ );
a4273dbf 168}
169
170sub Dlog_error (&@) {
171 my $code = shift;
d11de6ae 172 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
173 return _do_log( error => _get_logger( caller ), $code, @_ );
a4273dbf 174}
175
176sub Dlog_fatal (&@) {
177 my $code = shift;
d11de6ae 178 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
179 return _do_log( fatal => _get_logger( caller ), $code, @_ );
a4273dbf 180}
181
182
f11f9542 183sub DlogS_trace (&$) {
d11de6ae 184 local $_ = Data::Dumper::Concise::Dumper $_[1];
185 _do_logS( trace => _get_logger( caller ), $_[0], $_[1] )
f11f9542 186}
187
f11f9542 188sub DlogS_debug (&$) {
d11de6ae 189 local $_ = Data::Dumper::Concise::Dumper $_[1];
190 _do_logS( debug => _get_logger( caller ), $_[0], $_[1] )
f11f9542 191}
192
f11f9542 193sub DlogS_info (&$) {
d11de6ae 194 local $_ = Data::Dumper::Concise::Dumper $_[1];
195 _do_logS( info => _get_logger( caller ), $_[0], $_[1] )
f11f9542 196}
197
f11f9542 198sub DlogS_warn (&$) {
d11de6ae 199 local $_ = Data::Dumper::Concise::Dumper $_[1];
200 _do_logS( warn => _get_logger( caller ), $_[0], $_[1] )
f11f9542 201}
202
f11f9542 203sub DlogS_error (&$) {
d11de6ae 204 local $_ = Data::Dumper::Concise::Dumper $_[1];
205 _do_logS( error => _get_logger( caller ), $_[0], $_[1] )
f11f9542 206}
207
f11f9542 208sub DlogS_fatal (&$) {
d11de6ae 209 local $_ = Data::Dumper::Concise::Dumper $_[1];
210 _do_logS( fatal => _get_logger( caller ), $_[0], $_[1] )
f11f9542 211}
212
0daa11f3 2131;
0a3750e2 214
215__END__
216
2daff231 217=head1 NAME
218
8bc568d2 219Log::Contextual - Simple logging interface with a contextual log
2daff231 220
221=head1 SYNOPSIS
222
9b8e24d5 223 use Log::Contextual qw( :log :dlog set_logger with_logger );
5b094c87 224 use Log::Contextual::SimpleLogger;
225 use Log::Log4perl ':easy';
226 Log::Log4perl->easy_init($DEBUG);
2daff231 227
2daff231 228
5b094c87 229 my $logger = Log::Log4perl->get_logger;
230
231 set_logger $logger;
2daff231 232
9b8e24d5 233 log_debug { 'program started' };
2daff231 234
235 sub foo {
9b8e24d5 236 with_logger(Log::Contextual::SimpleLogger->new({
237 levels => [qw( trace debug )]
21431192 238 }) => sub {
239 log_trace { 'foo entered' };
9b8e24d5 240 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
2daff231 241 # ...
21431192 242 log_trace { 'foo left' };
9b8e24d5 243 });
2daff231 244 }
245
5b094c87 246 foo();
247
9fe4eeb3 248Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
249with C<Log::Contextual>:
250
251 use Log::Contextual qw( :log :dlog set_logger );
252 use Log::Dispatchouli;
253 my $ld = Log::Dispatchouli->new({
254 ident => 'slrtbrfst',
255 to_stderr => 1,
256 debug => 1,
257 });
258
259 set_logger $ld;
260
261 log_debug { 'program started' };
262
2daff231 263=head1 DESCRIPTION
264
3dc9bd3c 265This module is a simple interface to extensible logging. It is bundled with a
266really basic logger, L<Log::Contextual::SimpleLogger>, but in general you
267should use a real logger instead of that. For something more serious but not
9fe4eeb3 268overly complicated, try L<Log::Dispatchouli> (see L</SYNOPSIS> for example.)
3dc9bd3c 269
270=head1 OPTIONS
271
c154d18a 272=head2 -logger
273
3dc9bd3c 274When you import this module you may use C<-logger> as a shortcut for
275L<set_logger>, for example:
276
277 use Log::Contextual::SimpleLogger;
9b8e24d5 278 use Log::Contextual qw( :dlog ),
279 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
3dc9bd3c 280
281sometimes you might want to have the logger handy for other stuff, in which
282case you might try something like the following:
283
284 my $var_log;
285 BEGIN { $var_log = VarLogger->new }
9b8e24d5 286 use Log::Contextual qw( :dlog ), -logger => $var_log;
3dc9bd3c 287
c154d18a 288=head2 -default_logger
289
290The C<-default_logger> import option is similar to the C<-logger> import option
291except C<-default_logger> sets the the default logger for the current package.
292
293Basically it sets the logger to be used if C<set_logger> is never called; so
294
295 package My::Package;
296 use Log::Contextual::SimpleLogger;
297 use Log::Contextual qw( :log ),
298 -default_logger => Log::Contextual::WarnLogger->new({
ae59bbe3 299 env_prefix => 'MY_PACKAGE'
c154d18a 300 });
301
302If you are interested in using this package for a module you are putting on
303CPAN we recommend L<Log::Contextual::WarnLogger> for your default logger.
304
3dc9bd3c 305=head1 A WORK IN PROGRESS
306
307This module is certainly not complete, but we will not break the interface
308lightly, so I would say it's safe to use in production code. The main result
309from that at this point is that doing:
310
311 use Log::Contextual;
312
313will die as we do not yet know what the defaults should be. If it turns out
314that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
9b8e24d5 315probably make C<:log> the default. But only time and usage will tell.
2daff231 316
317=head1 FUNCTIONS
318
319=head2 set_logger
320
321 my $logger = WarnLogger->new;
21431192 322 set_logger $logger;
323
0e13e261 324Arguments: C<Ref|CodeRef $returning_logger>
2daff231 325
21431192 326C<set_logger> will just set the current logger to whatever you pass it. It
327expects a C<CodeRef>, but if you pass it something else it will wrap it in a
06e908c3 328C<CodeRef> for you. C<set_logger> is really meant only to be called from a
329top-level script. To avoid foot-shooting the function will warn if you call it
330more than once.
2daff231 331
332=head2 with_logger
333
334 my $logger = WarnLogger->new;
21431192 335 with_logger $logger => sub {
2daff231 336 if (1 == 0) {
337 log_fatal { 'Non Logical Universe Detected' };
338 } else {
339 log_info { 'All is good' };
340 }
80c3e48b 341 };
2daff231 342
0e13e261 343Arguments: C<Ref|CodeRef $returning_logger, CodeRef $to_execute>
2daff231 344
21431192 345C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
0e13e261 346As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
21431192 347C<CodeRef> if needed.
2daff231 348
21431192 349=head2 log_$level
2daff231 350
0e13e261 351Import Tag: C<:log>
3dc9bd3c 352
0e13e261 353Arguments: C<CodeRef $returning_message, @args>
2daff231 354
21431192 355All of the following six functions work the same except that a different method
356is called on the underlying C<$logger> object. The basic pattern is:
2daff231 357
0e13e261 358 sub log_$level (&@) {
21431192 359 if ($logger->is_$level) {
0e13e261 360 $logger->$level(shift->(@_));
21431192 361 }
0e13e261 362 @_
21431192 363 }
2daff231 364
0e13e261 365Note that the function returns it's arguments. This can be used in a number of
366ways, but often it's convenient just for partial inspection of passthrough data
367
368 my @friends = log_trace {
369 'friends list being generated, data from first friend: ' .
370 Dumper($_[0]->TO_JSON)
371 } generate_friend_list();
372
373If you want complete inspection of passthrough data, take a look at the
374L</Dlog_$level> functions.
375
21431192 376=head3 log_trace
2daff231 377
21431192 378 log_trace { 'entered method foo with args ' join q{,}, @args };
2daff231 379
21431192 380=head3 log_debug
2daff231 381
21431192 382 log_debug { 'entered method foo' };
2daff231 383
21431192 384=head3 log_info
2daff231 385
21431192 386 log_info { 'started process foo' };
2daff231 387
21431192 388=head3 log_warn
2daff231 389
21431192 390 log_warn { 'possible misconfiguration at line 10' };
2daff231 391
21431192 392=head3 log_error
2daff231 393
21431192 394 log_error { 'non-numeric user input!' };
2daff231 395
21431192 396=head3 log_fatal
2daff231 397
398 log_fatal { '1 is never equal to 0!' };
399
0e13e261 400=head2 logS_$level
401
402Import Tag: C<:log>
403
404Arguments: C<CodeRef $returning_message, Item $arg>
405
406This is really just a special case of the L</log_$level> functions. It forces
407scalar context when that is what you need. Other than that it works exactly
408same:
409
410 my $friend = logS_trace {
411 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
412 } friend();
413
414See also: L</DlogS_$level>.
415
21431192 416=head2 Dlog_$level
417
0e13e261 418Import Tag: C<:dlog>
3dc9bd3c 419
0e13e261 420Arguments: C<CodeRef $returning_message, @args>
2daff231 421
0e13e261 422All of the following six functions work the same as their L</log_$level>
9b8e24d5 423brethren, except they return what is passed into them and put the stringified
21431192 424(with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
425you can do cool things like the following:
426
427 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
428
429and the output might look something like:
430
431 names: "fREW"
432 "fRIOUX"
433 "fROOH"
434 "fRUE"
435 "fiSMBoC"
436
437=head3 Dlog_trace
438
9b8e24d5 439 my ($foo, $bar) = Dlog_trace { "entered method foo with args: $_" } @_;
21431192 440
441=head3 Dlog_debug
442
443 Dlog_debug { "random data structure: $_" } { foo => $bar };
444
445=head3 Dlog_info
446
447 return Dlog_info { "html from method returned: $_" } "<html>...</html>";
448
449=head3 Dlog_warn
450
451 Dlog_warn { "probably invalid value: $_" } $foo;
452
453=head3 Dlog_error
454
455 Dlog_error { "non-numeric user input! ($_)" } $port;
2daff231 456
21431192 457=head3 Dlog_fatal
2daff231 458
21431192 459 Dlog_fatal { '1 is never equal to 0!' } 'ZOMG ZOMG' if 1 == 0;
2daff231 460
83b33eb5 461=head2 DlogS_$level
462
0e13e261 463Import Tag: C<:dlog>
3dc9bd3c 464
0e13e261 465Arguments: C<CodeRef $returning_message, Item $arg>
83b33eb5 466
0e13e261 467Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
468They only take a single scalar after the C<$returning_message> instead of
469slurping up (and also setting C<wantarray>) all the C<@args>
83b33eb5 470
471 my $pals_rs = DlogS_debug { "pals resultset: $_" }
472 $schema->resultset('Pals')->search({ perlers => 1 });
473
3dc9bd3c 474=head1 LOGGER INTERFACE
475
476Because this module is ultimately pretty looking glue (glittery?) with the
477awesome benefit of the Contextual part, users will often want to make their
478favorite logger work with it. The following are the methods that should be
479implemented in the logger:
480
481 is_trace
482 is_debug
483 is_info
484 is_warn
485 is_error
486 is_fatal
487 trace
488 debug
489 info
490 warn
491 error
492 fatal
493
494The first six merely need to return true if that level is enabled. The latter
495six take the results of whatever the user returned from their coderef and log
496them. For a basic example see L<Log::Contextual::SimpleLogger>.
497
2daff231 498=head1 AUTHOR
499
500frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
501
502=head1 DESIGNER
503
504mst - Matt S. Trout <mst@shadowcat.co.uk>
505
506=head1 COPYRIGHT
507
508Copyright (c) 2010 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
509above.
510
511=head1 LICENSE
512
513This library is free software and may be distributed under the same terms as
514Perl 5 itself.
515
516=cut
517