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