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