super late commit of release 0.00201
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
CommitLineData
0daa11f3 1package Log::Contextual;
2
a2777569 3use strict;
4use warnings;
2033c911 5
eab992c0 6our $VERSION = '0.00201';
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
a4273dbf 107
108
4d8ea78d 109sub log_trace (&@) {
5d8f2b84 110 my $log = _get_logger( caller );
4d8ea78d 111 my $code = shift;
70a05830 112 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 113 $log->trace($code->(@_))
6dc6632a 114 if $log->is_trace;
4d8ea78d 115 @_
6dc6632a 116}
117
4d8ea78d 118sub log_debug (&@) {
5d8f2b84 119 my $log = _get_logger( caller );
4d8ea78d 120 my $code = shift;
70a05830 121 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 122 $log->debug($code->(@_))
7cec609c 123 if $log->is_debug;
4d8ea78d 124 @_
7cec609c 125}
126
4d8ea78d 127sub log_info (&@) {
5d8f2b84 128 my $log = _get_logger( caller );
4d8ea78d 129 my $code = shift;
70a05830 130 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 131 $log->info($code->(@_))
6dc6632a 132 if $log->is_info;
4d8ea78d 133 @_
6dc6632a 134}
135
4d8ea78d 136sub log_warn (&@) {
5d8f2b84 137 my $log = _get_logger( caller );
4d8ea78d 138 my $code = shift;
70a05830 139 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 140 $log->warn($code->(@_))
6dc6632a 141 if $log->is_warn;
4d8ea78d 142 @_
6dc6632a 143}
144
4d8ea78d 145sub log_error (&@) {
5d8f2b84 146 my $log = _get_logger( caller );
4d8ea78d 147 my $code = shift;
70a05830 148 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 149 $log->error($code->(@_))
6dc6632a 150 if $log->is_error;
4d8ea78d 151 @_
6dc6632a 152}
153
4d8ea78d 154sub log_fatal (&@) {
5d8f2b84 155 my $log = _get_logger( caller );
4d8ea78d 156 my $code = shift;
70a05830 157 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
4d8ea78d 158 $log->fatal($code->(@_))
6dc6632a 159 if $log->is_fatal;
4d8ea78d 160 @_
6dc6632a 161}
162
f11f9542 163
709d11fe 164sub logS_trace (&$) {
5d8f2b84 165 my $log = _get_logger( caller );
709d11fe 166 my $code = shift;
167 my $value = shift;
70a05830 168 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 169 $log->trace($code->($value))
170 if $log->is_trace;
171 $value
172}
173
174sub logS_debug (&$) {
5d8f2b84 175 my $log = _get_logger( caller );
709d11fe 176 my $code = shift;
177 my $value = shift;
70a05830 178 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 179 $log->debug($code->($value))
180 if $log->is_debug;
181 $value
182}
183
184sub logS_info (&$) {
5d8f2b84 185 my $log = _get_logger( caller );
709d11fe 186 my $code = shift;
187 my $value = shift;
70a05830 188 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 189 $log->info($code->($value))
190 if $log->is_info;
191 $value
192}
193
194sub logS_warn (&$) {
5d8f2b84 195 my $log = _get_logger( caller );
709d11fe 196 my $code = shift;
197 my $value = shift;
70a05830 198 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 199 $log->warn($code->($value))
200 if $log->is_warn;
201 $value
202}
203
204sub logS_error (&$) {
5d8f2b84 205 my $log = _get_logger( caller );
709d11fe 206 my $code = shift;
207 my $value = shift;
70a05830 208 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 209 $log->error($code->($value))
210 if $log->is_error;
211 $value
212}
213
214sub logS_fatal (&$) {
5d8f2b84 215 my $log = _get_logger( caller );
709d11fe 216 my $code = shift;
217 my $value = shift;
70a05830 218 local $Log::Log4perl::caller_depth = ($Log::Log4perl::caller_depth || 0 ) + 1;
709d11fe 219 $log->fatal($code->($value))
220 if $log->is_fatal;
221 $value
222}
223
224
f11f9542 225
226sub Dlog_trace (&@) {
227 my $code = shift;
228 my @values = @_;
5a1c7d54 229 return log_trace {
db70b0a5 230 if (@values) {
231 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
232 } else {
233 do { local $_ = '()'; $code->() };
234 }
5a1c7d54 235 } @values
f11f9542 236}
237
a4273dbf 238sub Dlog_debug (&@) {
239 my $code = shift;
240 my @values = @_;
241 log_debug {
db70b0a5 242 if (@values) {
243 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
244 } else {
245 do { local $_ = '()'; $code->() };
246 }
a4273dbf 247 } @values
248}
249
250sub Dlog_info (&@) {
251 my $code = shift;
252 my @values = @_;
253 log_info {
db70b0a5 254 if (@values) {
255 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
256 } else {
257 do { local $_ = '()'; $code->() };
258 }
a4273dbf 259 } @values
260}
261
262sub Dlog_warn (&@) {
263 my $code = shift;
264 my @values = @_;
265 log_warn {
db70b0a5 266 if (@values) {
267 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
268 } else {
269 do { local $_ = '()'; $code->() };
270 }
a4273dbf 271 } @values
272}
273
274sub Dlog_error (&@) {
275 my $code = shift;
276 my @values = @_;
277 log_error {
db70b0a5 278 if (@values) {
279 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
280 } else {
281 do { local $_ = '()'; $code->() };
282 }
a4273dbf 283 } @values
284}
285
286sub Dlog_fatal (&@) {
287 my $code = shift;
288 my @values = @_;
289 log_fatal {
db70b0a5 290 if (@values) {
291 do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
292 } else {
293 do { local $_ = '()'; $code->() };
294 }
a4273dbf 295 } @values
296}
297
298
299
f11f9542 300sub DlogS_trace (&$) {
301 my $code = $_[0];
302 my $value = $_[1];
709d11fe 303 logS_trace {
f11f9542 304 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 305 } $value
f11f9542 306}
307
f11f9542 308sub DlogS_debug (&$) {
309 my $code = $_[0];
310 my $value = $_[1];
709d11fe 311 logS_debug {
f11f9542 312 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 313 } $value
f11f9542 314}
315
f11f9542 316sub DlogS_info (&$) {
317 my $code = $_[0];
318 my $value = $_[1];
709d11fe 319 logS_info {
f11f9542 320 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 321 } $value
f11f9542 322}
323
f11f9542 324sub DlogS_warn (&$) {
325 my $code = $_[0];
326 my $value = $_[1];
709d11fe 327 logS_warn {
f11f9542 328 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 329 } $value
f11f9542 330}
331
f11f9542 332sub DlogS_error (&$) {
333 my $code = $_[0];
334 my $value = $_[1];
709d11fe 335 logS_error {
f11f9542 336 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 337 } $value
f11f9542 338}
339
f11f9542 340sub DlogS_fatal (&$) {
341 my $code = $_[0];
342 my $value = $_[1];
709d11fe 343 logS_fatal {
f11f9542 344 do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
709d11fe 345 } $value
f11f9542 346}
347
0daa11f3 3481;
0a3750e2 349
350__END__
351
2daff231 352=head1 NAME
353
8bc568d2 354Log::Contextual - Simple logging interface with a contextual log
2daff231 355
356=head1 SYNOPSIS
357
9b8e24d5 358 use Log::Contextual qw( :log :dlog set_logger with_logger );
5b094c87 359 use Log::Contextual::SimpleLogger;
360 use Log::Log4perl ':easy';
361 Log::Log4perl->easy_init($DEBUG);
2daff231 362
2daff231 363
5b094c87 364 my $logger = Log::Log4perl->get_logger;
365
366 set_logger $logger;
2daff231 367
9b8e24d5 368 log_debug { 'program started' };
2daff231 369
370 sub foo {
9b8e24d5 371 with_logger(Log::Contextual::SimpleLogger->new({
372 levels => [qw( trace debug )]
21431192 373 }) => sub {
374 log_trace { 'foo entered' };
9b8e24d5 375 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
2daff231 376 # ...
21431192 377 log_trace { 'foo left' };
9b8e24d5 378 });
2daff231 379 }
380
5b094c87 381 foo();
382
9fe4eeb3 383Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
384with C<Log::Contextual>:
385
386 use Log::Contextual qw( :log :dlog set_logger );
387 use Log::Dispatchouli;
388 my $ld = Log::Dispatchouli->new({
389 ident => 'slrtbrfst',
390 to_stderr => 1,
391 debug => 1,
392 });
393
394 set_logger $ld;
395
396 log_debug { 'program started' };
397
2daff231 398=head1 DESCRIPTION
399
3dc9bd3c 400This module is a simple interface to extensible logging. It is bundled with a
401really basic logger, L<Log::Contextual::SimpleLogger>, but in general you
402should use a real logger instead of that. For something more serious but not
9fe4eeb3 403overly complicated, try L<Log::Dispatchouli> (see L</SYNOPSIS> for example.)
3dc9bd3c 404
405=head1 OPTIONS
406
c154d18a 407=head2 -logger
408
3dc9bd3c 409When you import this module you may use C<-logger> as a shortcut for
410L<set_logger>, for example:
411
412 use Log::Contextual::SimpleLogger;
9b8e24d5 413 use Log::Contextual qw( :dlog ),
414 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
3dc9bd3c 415
416sometimes you might want to have the logger handy for other stuff, in which
417case you might try something like the following:
418
419 my $var_log;
420 BEGIN { $var_log = VarLogger->new }
9b8e24d5 421 use Log::Contextual qw( :dlog ), -logger => $var_log;
3dc9bd3c 422
c154d18a 423=head2 -default_logger
424
425The C<-default_logger> import option is similar to the C<-logger> import option
426except C<-default_logger> sets the the default logger for the current package.
427
428Basically it sets the logger to be used if C<set_logger> is never called; so
429
430 package My::Package;
431 use Log::Contextual::SimpleLogger;
432 use Log::Contextual qw( :log ),
433 -default_logger => Log::Contextual::WarnLogger->new({
ae59bbe3 434 env_prefix => 'MY_PACKAGE'
c154d18a 435 });
436
437If you are interested in using this package for a module you are putting on
438CPAN we recommend L<Log::Contextual::WarnLogger> for your default logger.
439
3dc9bd3c 440=head1 A WORK IN PROGRESS
441
442This module is certainly not complete, but we will not break the interface
443lightly, so I would say it's safe to use in production code. The main result
444from that at this point is that doing:
445
446 use Log::Contextual;
447
448will die as we do not yet know what the defaults should be. If it turns out
449that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
9b8e24d5 450probably make C<:log> the default. But only time and usage will tell.
2daff231 451
452=head1 FUNCTIONS
453
454=head2 set_logger
455
456 my $logger = WarnLogger->new;
21431192 457 set_logger $logger;
458
0e13e261 459Arguments: C<Ref|CodeRef $returning_logger>
2daff231 460
21431192 461C<set_logger> will just set the current logger to whatever you pass it. It
462expects a C<CodeRef>, but if you pass it something else it will wrap it in a
06e908c3 463C<CodeRef> for you. C<set_logger> is really meant only to be called from a
464top-level script. To avoid foot-shooting the function will warn if you call it
465more than once.
2daff231 466
467=head2 with_logger
468
469 my $logger = WarnLogger->new;
21431192 470 with_logger $logger => sub {
2daff231 471 if (1 == 0) {
472 log_fatal { 'Non Logical Universe Detected' };
473 } else {
474 log_info { 'All is good' };
475 }
80c3e48b 476 };
2daff231 477
0e13e261 478Arguments: C<Ref|CodeRef $returning_logger, CodeRef $to_execute>
2daff231 479
21431192 480C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
0e13e261 481As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
21431192 482C<CodeRef> if needed.
2daff231 483
21431192 484=head2 log_$level
2daff231 485
0e13e261 486Import Tag: C<:log>
3dc9bd3c 487
0e13e261 488Arguments: C<CodeRef $returning_message, @args>
2daff231 489
21431192 490All of the following six functions work the same except that a different method
491is called on the underlying C<$logger> object. The basic pattern is:
2daff231 492
0e13e261 493 sub log_$level (&@) {
21431192 494 if ($logger->is_$level) {
0e13e261 495 $logger->$level(shift->(@_));
21431192 496 }
0e13e261 497 @_
21431192 498 }
2daff231 499
0e13e261 500Note that the function returns it's arguments. This can be used in a number of
501ways, but often it's convenient just for partial inspection of passthrough data
502
503 my @friends = log_trace {
504 'friends list being generated, data from first friend: ' .
505 Dumper($_[0]->TO_JSON)
506 } generate_friend_list();
507
508If you want complete inspection of passthrough data, take a look at the
509L</Dlog_$level> functions.
510
21431192 511=head3 log_trace
2daff231 512
21431192 513 log_trace { 'entered method foo with args ' join q{,}, @args };
2daff231 514
21431192 515=head3 log_debug
2daff231 516
21431192 517 log_debug { 'entered method foo' };
2daff231 518
21431192 519=head3 log_info
2daff231 520
21431192 521 log_info { 'started process foo' };
2daff231 522
21431192 523=head3 log_warn
2daff231 524
21431192 525 log_warn { 'possible misconfiguration at line 10' };
2daff231 526
21431192 527=head3 log_error
2daff231 528
21431192 529 log_error { 'non-numeric user input!' };
2daff231 530
21431192 531=head3 log_fatal
2daff231 532
533 log_fatal { '1 is never equal to 0!' };
534
0e13e261 535=head2 logS_$level
536
537Import Tag: C<:log>
538
539Arguments: C<CodeRef $returning_message, Item $arg>
540
541This is really just a special case of the L</log_$level> functions. It forces
542scalar context when that is what you need. Other than that it works exactly
543same:
544
545 my $friend = logS_trace {
546 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
547 } friend();
548
549See also: L</DlogS_$level>.
550
21431192 551=head2 Dlog_$level
552
0e13e261 553Import Tag: C<:dlog>
3dc9bd3c 554
0e13e261 555Arguments: C<CodeRef $returning_message, @args>
2daff231 556
0e13e261 557All of the following six functions work the same as their L</log_$level>
9b8e24d5 558brethren, except they return what is passed into them and put the stringified
21431192 559(with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
560you can do cool things like the following:
561
562 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
563
564and the output might look something like:
565
566 names: "fREW"
567 "fRIOUX"
568 "fROOH"
569 "fRUE"
570 "fiSMBoC"
571
572=head3 Dlog_trace
573
9b8e24d5 574 my ($foo, $bar) = Dlog_trace { "entered method foo with args: $_" } @_;
21431192 575
576=head3 Dlog_debug
577
578 Dlog_debug { "random data structure: $_" } { foo => $bar };
579
580=head3 Dlog_info
581
582 return Dlog_info { "html from method returned: $_" } "<html>...</html>";
583
584=head3 Dlog_warn
585
586 Dlog_warn { "probably invalid value: $_" } $foo;
587
588=head3 Dlog_error
589
590 Dlog_error { "non-numeric user input! ($_)" } $port;
2daff231 591
21431192 592=head3 Dlog_fatal
2daff231 593
21431192 594 Dlog_fatal { '1 is never equal to 0!' } 'ZOMG ZOMG' if 1 == 0;
2daff231 595
83b33eb5 596=head2 DlogS_$level
597
0e13e261 598Import Tag: C<:dlog>
3dc9bd3c 599
0e13e261 600Arguments: C<CodeRef $returning_message, Item $arg>
83b33eb5 601
0e13e261 602Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
603They only take a single scalar after the C<$returning_message> instead of
604slurping up (and also setting C<wantarray>) all the C<@args>
83b33eb5 605
606 my $pals_rs = DlogS_debug { "pals resultset: $_" }
607 $schema->resultset('Pals')->search({ perlers => 1 });
608
3dc9bd3c 609=head1 LOGGER INTERFACE
610
611Because this module is ultimately pretty looking glue (glittery?) with the
612awesome benefit of the Contextual part, users will often want to make their
613favorite logger work with it. The following are the methods that should be
614implemented in the logger:
615
616 is_trace
617 is_debug
618 is_info
619 is_warn
620 is_error
621 is_fatal
622 trace
623 debug
624 info
625 warn
626 error
627 fatal
628
629The first six merely need to return true if that level is enabled. The latter
630six take the results of whatever the user returned from their coderef and log
631them. For a basic example see L<Log::Contextual::SimpleLogger>.
632
2daff231 633=head1 AUTHOR
634
635frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
636
637=head1 DESIGNER
638
639mst - Matt S. Trout <mst@shadowcat.co.uk>
640
641=head1 COPYRIGHT
642
643Copyright (c) 2010 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
644above.
645
646=head1 LICENSE
647
648This library is free software and may be distributed under the same terms as
649Perl 5 itself.
650
651=cut
652