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