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