Fix RT#83267
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
CommitLineData
0daa11f3 1package Log::Contextual;
2
a2777569 3use strict;
4use warnings;
2033c911 5
8ccaf9fb 6our $VERSION = '0.005001';
b42fe5d2 7$VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
2033c911 8
ae9785e2 9my @levels = qw(debug trace warn info error fatal);
10
675503c7 11use Exporter::Declare;
12use Exporter::Declare::Export::Generator;
f11f9542 13use Data::Dumper::Concise;
5b094c87 14use Scalar::Util 'blessed';
2033c911 15
e0e3c3d0 16my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
17
18my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
19
b144ba01 20eval {
21 require Log::Log4perl;
22 die if $Log::Log4perl::VERSION < 1.29;
23 Log::Log4perl->wrapper_register(__PACKAGE__)
24};
25
5fd26f45 26# ____ is because tags must have at least one export and we don't want to
27# export anything but the levels selected
6ae293d7 28sub ____ { }
5fd26f45 29
e0e3c3d0 30exports ('____',
31 @dlog, @log,
32 qw( set_logger with_logger )
33);
f11f9542 34
5fd26f45 35export_tag dlog => ('____');
36export_tag log => ('____');
675503c7 37import_arguments qw(logger package_logger default_logger);
38
139ded54 39sub router {
0092c26a 40 our $Router_Instance ||= do {
41 require Log::Contextual::Router;
42 Log::Contextual::Router->new
6ae293d7 43 }
0092c26a 44}
45
e06303cd 46sub default_import {
47 my ($class) = shift;
48
49 die 'Log::Contextual does not have a default import list';
50
51 ()
52}
53
6ae293d7 54sub arg_logger { $_[1] }
55sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
8112b699 56sub arg_package_logger { $_[1] }
57sub arg_default_logger { $_[1] }
58
675503c7 59sub before_import {
60 my ($class, $importer, $spec) = @_;
6ae293d7 61 my $router = $class->router;
62 my $exports = $spec->exports;
63 my %router_args = (
64 exporter => $class,
65 target => $importer,
66 arguments => $spec->argument_info
67 );
f11f9542 68
e06303cd 69 my @tags = $class->default_import($spec)
6ae293d7 70 if $spec->config->{default};
675503c7 71
e06303cd 72 for (@tags) {
73 die "only tags are supported for defaults at this time"
74 unless $_ =~ /^:(.*)$/;
75
76 $spec->config->{$1} = 1;
77 }
78
a5454e75 79 $router->before_import(%router_args);
8112b699 80
84d7d9ee 81 if ($exports->{'&set_logger'}) {
82 die ref($router) . " does not support set_logger()"
83 unless $router->does('Log::Contextual::Role::Router::SetLogger');
4d605164 84
84d7d9ee 85 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
86 }
4d605164 87
84d7d9ee 88 if ($exports->{'&with_logger'}) {
89 die ref($router) . " does not support with_logger()"
90 unless $router->does('Log::Contextual::Role::Router::WithLogger');
4d605164 91
84d7d9ee 92 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
93 }
4d605164 94
5fd26f45 95 my @levels = @{$class->arg_levels($spec->config->{levels})};
675503c7 96 for my $level (@levels) {
97 if ($spec->config->{log}) {
6ae293d7 98 $spec->add_export(
99 "&log_$level",
100 sub (&@) {
101 my ($code, @args) = @_;
102 $router->handle_log_request(
103 exporter => $class,
104 caller_package => scalar(caller),
105 caller_level => 1,
106 message_level => $level,
107 message_sub => $code,
108 message_args => \@args,
109 );
110 return @args;
111 });
112 $spec->add_export(
113 "&logS_$level",
114 sub (&@) {
115 my ($code, @args) = @_;
116 $router->handle_log_request(
117 exporter => $class,
118 caller_package => scalar(caller),
119 caller_level => 1,
120 message_level => $level,
121 message_sub => $code,
122 message_args => \@args,
123 );
124 return $args[0];
125 });
675503c7 126 }
127 if ($spec->config->{dlog}) {
6ae293d7 128 $spec->add_export(
129 "&Dlog_$level",
130 sub (&@) {
131 my ($code, @args) = @_;
132 my $wrapped = sub {
133 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
134 &$code;
135 };
136 $router->handle_log_request(
137 exporter => $class,
138 caller_package => scalar(caller),
139 caller_level => 1,
140 message_level => $level,
141 message_sub => $wrapped,
142 message_args => \@args,
143 );
144 return @args;
145 });
146 $spec->add_export(
147 "&DlogS_$level",
148 sub (&$) {
149 my ($code, $ref) = @_;
150 my $wrapped = sub {
151 local $_ = Data::Dumper::Concise::Dumper($_[0]);
152 &$code;
153 };
154 $router->handle_log_request(
155 exporter => $class,
156 caller_package => scalar(caller),
157 caller_level => 1,
158 message_level => $level,
159 message_sub => $wrapped,
160 message_args => [$ref],
161 );
162 return $ref;
163 });
a2777569 164 }
165 }
675503c7 166}
167
a5454e75 168sub after_import {
169 my ($class, $importer, $spec) = @_;
6ae293d7 170 my %router_args = (
171 exporter => $class,
172 target => $importer,
173 arguments => $spec->argument_info
174 );
a5454e75 175 $class->router->after_import(%router_args);
176}
709d11fe 177
0daa11f3 1781;
0a3750e2 179
180__END__
181
2daff231 182=head1 NAME
183
8bc568d2 184Log::Contextual - Simple logging interface with a contextual log
2daff231 185
186=head1 SYNOPSIS
187
9b8e24d5 188 use Log::Contextual qw( :log :dlog set_logger with_logger );
5b094c87 189 use Log::Contextual::SimpleLogger;
190 use Log::Log4perl ':easy';
191 Log::Log4perl->easy_init($DEBUG);
2daff231 192
5b094c87 193 my $logger = Log::Log4perl->get_logger;
194
195 set_logger $logger;
2daff231 196
9b8e24d5 197 log_debug { 'program started' };
2daff231 198
199 sub foo {
f9bf084b 200
201 my $minilogger = Log::Contextual::SimpleLogger->new({
202 levels => [qw( trace debug )]
203 });
204
2ae9c121 205 my @args = @_;
206
f9bf084b 207 with_logger $minilogger => sub {
21431192 208 log_trace { 'foo entered' };
2ae9c121 209 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
2daff231 210 # ...
21431192 211 log_trace { 'foo left' };
f9bf084b 212 };
2daff231 213 }
214
5b094c87 215 foo();
216
9fe4eeb3 217Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
218with C<Log::Contextual>:
219
220 use Log::Contextual qw( :log :dlog set_logger );
221 use Log::Dispatchouli;
222 my $ld = Log::Dispatchouli->new({
223 ident => 'slrtbrfst',
224 to_stderr => 1,
225 debug => 1,
226 });
227
228 set_logger $ld;
229
230 log_debug { 'program started' };
231
2daff231 232=head1 DESCRIPTION
233
30d7027a 234Major benefits:
235
236=over 2
237
238=item * Efficient
239
240The logging functions take blocks, so if a log level is disabled, the
241block will not run:
242
243 # the following won't run if debug is off
244 log_debug { "the new count in the database is " . $rs->count };
245
246Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
247enabled.
248
249=item * Handy
250
251The logging functions return their arguments, so you can stick them in
252the middle of expressions:
253
254 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
255
256=item * Generic
257
258C<Log::Contextual> is an interface for all major loggers. If you log through
259C<Log::Contextual> you will be able to swap underlying loggers later.
260
261=item * Powerful
262
39cd2f65 263C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
30d7027a 264Normally you don't need to know this, but you can take advantage of it when you
265need to later
266
267=item * Scalable
268
269If you just want to add logging to your extremely basic application, start with
270L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
271L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
272
273=back
274
275This module is a simple interface to extensible logging. It exists to
276abstract your logging interface so that logging is as painless as possible,
277while still allowing you to switch from one logger to another.
3dc9bd3c 278
30d7027a 279It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
280but in general you should use a real logger instead of that. For something
281more serious but not overly complicated, try L<Log::Dispatchouli> (see
282L</SYNOPSIS> for example.)
a2af6976 283
e36f2183 284=head1 A WORK IN PROGRESS
285
286This module is certainly not complete, but we will not break the interface
287lightly, so I would say it's safe to use in production code. The main result
288from that at this point is that doing:
289
290 use Log::Contextual;
291
292will die as we do not yet know what the defaults should be. If it turns out
293that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
294probably make C<:log> the default. But only time and usage will tell.
295
296=head1 IMPORT OPTIONS
297
298See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
299wide.
3dc9bd3c 300
c154d18a 301=head2 -logger
302
3dc9bd3c 303When you import this module you may use C<-logger> as a shortcut for
304L<set_logger>, for example:
305
306 use Log::Contextual::SimpleLogger;
9b8e24d5 307 use Log::Contextual qw( :dlog ),
308 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
3dc9bd3c 309
310sometimes you might want to have the logger handy for other stuff, in which
311case you might try something like the following:
312
313 my $var_log;
314 BEGIN { $var_log = VarLogger->new }
9b8e24d5 315 use Log::Contextual qw( :dlog ), -logger => $var_log;
3dc9bd3c 316
5fd26f45 317=head2 -levels
318
319The C<-levels> import option allows you to define exactly which levels your
320logger supports. So the default,
321C<< [qw(debug trace warn info error fatal)] >>, works great for
322L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
323supporting those levels is as easy as doing
324
325 use Log::Contextual
326 -levels => [qw( debug info notice warning error critical alert emergency )];
327
e2b4b29c 328=head2 -package_logger
329
330The C<-package_logger> import option is similar to the C<-logger> import option
331except C<-package_logger> sets the the logger for the current package.
332
333Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
334L</set_logger>.
335
336 package My::Package;
337 use Log::Contextual::SimpleLogger;
338 use Log::Contextual qw( :log ),
339 -package_logger => Log::Contextual::WarnLogger->new({
340 env_prefix => 'MY_PACKAGE'
341 });
342
343If you are interested in using this package for a module you are putting on
344CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
345
c154d18a 346=head2 -default_logger
347
348The C<-default_logger> import option is similar to the C<-logger> import option
e2b4b29c 349except C<-default_logger> sets the the B<default> logger for the current package.
c154d18a 350
351Basically it sets the logger to be used if C<set_logger> is never called; so
352
353 package My::Package;
354 use Log::Contextual::SimpleLogger;
355 use Log::Contextual qw( :log ),
356 -default_logger => Log::Contextual::WarnLogger->new({
ae59bbe3 357 env_prefix => 'MY_PACKAGE'
c154d18a 358 });
359
e36f2183 360=head1 SETTING DEFAULT IMPORT OPTIONS
3dc9bd3c 361
e36f2183 362Eventually you will get tired of writing the following in every single one of
363your packages:
3dc9bd3c 364
e36f2183 365 use Log::Log4perl;
366 use Log::Log4perl ':easy';
367 BEGIN { Log::Log4perl->easy_init($DEBUG) }
3dc9bd3c 368
e36f2183 369 use Log::Contextual -logger => Log::Log4perl->get_logger;
370
371You can set any of the import options for your whole project if you define your
372own C<Log::Contextual> subclass as follows:
373
374 package MyApp::Log::Contextual;
375
376 use base 'Log::Contextual';
377
378 use Log::Log4perl ':easy';
379 Log::Log4perl->easy_init($DEBUG)
380
2b40dee5 381 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
e36f2183 382 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
e06303cd 383 sub default_import { ':log' }
e36f2183 384
2b40dee5 385 # or maybe instead of default_logger
e36f2183 386 sub arg_package_logger { $_[1] }
e36f2183 387
2b40dee5 388 # and almost definitely not this, which is only here for completeness
389 sub arg_logger { $_[1] }
e36f2183 390
2b40dee5 391Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
392passed the values passed in from the arguments to the subclass, so you can
393either throw them away, honor them, die on usage, or whatever. To be clear,
394if you define your subclass, and someone uses it as follows:
e36f2183 395
2b40dee5 396 use MyApp::Log::Contextual -default_logger => $foo,
397 -levels => [qw(bar baz biff)];
398
399Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
e36f2183 400will get C<[qw(bar baz biff)]>;
2daff231 401
e06303cd 402Additionally, the C<default_import> method is what happens if a user tries to
403use your subclass with no arguments. The default just dies, but if you'd like
404to change the default to import a tag merely return the tags you'd like to
405import. So the following will all work:
406
407 sub default_import { ':log' }
408
409 sub default_import { ':dlog' }
410
411 sub default_import { qw(:dlog :log ) }
412
2daff231 413=head1 FUNCTIONS
414
415=head2 set_logger
416
417 my $logger = WarnLogger->new;
21431192 418 set_logger $logger;
419
27141a7a 420Arguments: L</LOGGER CODEREF>
2daff231 421
21431192 422C<set_logger> will just set the current logger to whatever you pass it. It
423expects a C<CodeRef>, but if you pass it something else it will wrap it in a
06e908c3 424C<CodeRef> for you. C<set_logger> is really meant only to be called from a
425top-level script. To avoid foot-shooting the function will warn if you call it
426more than once.
2daff231 427
428=head2 with_logger
429
430 my $logger = WarnLogger->new;
21431192 431 with_logger $logger => sub {
2daff231 432 if (1 == 0) {
433 log_fatal { 'Non Logical Universe Detected' };
434 } else {
435 log_info { 'All is good' };
436 }
80c3e48b 437 };
2daff231 438
27141a7a 439Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
2daff231 440
21431192 441C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
0e13e261 442As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
21431192 443C<CodeRef> if needed.
2daff231 444
21431192 445=head2 log_$level
2daff231 446
0e13e261 447Import Tag: C<:log>
3dc9bd3c 448
0e13e261 449Arguments: C<CodeRef $returning_message, @args>
2daff231 450
a4d67519 451C<log_$level> functions all work the same except that a different method
21431192 452is called on the underlying C<$logger> object. The basic pattern is:
2daff231 453
0e13e261 454 sub log_$level (&@) {
21431192 455 if ($logger->is_$level) {
0e13e261 456 $logger->$level(shift->(@_));
21431192 457 }
0e13e261 458 @_
21431192 459 }
2daff231 460
0e13e261 461Note that the function returns it's arguments. This can be used in a number of
462ways, but often it's convenient just for partial inspection of passthrough data
463
464 my @friends = log_trace {
465 'friends list being generated, data from first friend: ' .
466 Dumper($_[0]->TO_JSON)
467 } generate_friend_list();
468
469If you want complete inspection of passthrough data, take a look at the
470L</Dlog_$level> functions.
471
a4d67519 472Which functions are exported depends on what was passed to L</-levels>. The
473default (no C<-levels> option passed) would export:
2daff231 474
a4d67519 475=over 2
2daff231 476
a4d67519 477=item log_trace
2daff231 478
a4d67519 479=item log_debug
2daff231 480
a4d67519 481=item log_info
2daff231 482
a4d67519 483=item log_warn
2daff231 484
a4d67519 485=item log_error
2daff231 486
a4d67519 487=item log_fatal
2daff231 488
a4d67519 489=back
2daff231 490
0e13e261 491=head2 logS_$level
492
493Import Tag: C<:log>
494
495Arguments: C<CodeRef $returning_message, Item $arg>
496
497This is really just a special case of the L</log_$level> functions. It forces
498scalar context when that is what you need. Other than that it works exactly
499same:
500
501 my $friend = logS_trace {
502 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
503 } friend();
504
505See also: L</DlogS_$level>.
506
21431192 507=head2 Dlog_$level
508
0e13e261 509Import Tag: C<:dlog>
3dc9bd3c 510
0e13e261 511Arguments: C<CodeRef $returning_message, @args>
2daff231 512
0e13e261 513All of the following six functions work the same as their L</log_$level>
9b8e24d5 514brethren, except they return what is passed into them and put the stringified
21431192 515(with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
516you can do cool things like the following:
517
518 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
519
520and the output might look something like:
521
522 names: "fREW"
523 "fRIOUX"
524 "fROOH"
525 "fRUE"
526 "fiSMBoC"
527
a4d67519 528Which functions are exported depends on what was passed to L</-levels>. The
529default (no C<-levels> option passed) would export:
21431192 530
a4d67519 531=over 2
21431192 532
a4d67519 533=item Dlog_trace
21431192 534
a4d67519 535=item Dlog_debug
21431192 536
a4d67519 537=item Dlog_info
21431192 538
a4d67519 539=item Dlog_warn
21431192 540
a4d67519 541=item Dlog_error
2daff231 542
a4d67519 543=item Dlog_fatal
2daff231 544
a4d67519 545=back
2daff231 546
83b33eb5 547=head2 DlogS_$level
548
0e13e261 549Import Tag: C<:dlog>
3dc9bd3c 550
0e13e261 551Arguments: C<CodeRef $returning_message, Item $arg>
83b33eb5 552
0e13e261 553Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
554They only take a single scalar after the C<$returning_message> instead of
555slurping up (and also setting C<wantarray>) all the C<@args>
83b33eb5 556
557 my $pals_rs = DlogS_debug { "pals resultset: $_" }
558 $schema->resultset('Pals')->search({ perlers => 1 });
559
27141a7a 560=head1 LOGGER CODEREF
561
562Anywhere a logger object can be passed, a coderef is accepted. This is so
563that the user can use different logger objects based on runtime information.
564The logger coderef is passed the package of the caller the caller level the
565coderef needs to use if it wants more caller information. The latter is in
566a hashref to allow for more options in the future.
567
37a8266a 568Here is a basic example of a logger that exploits C<caller> to reproduce the
569output of C<warn> with a logger:
570
571 my @caller_info;
572 my $var_log = Log::Contextual::SimpleLogger->new({
573 levels => [qw(trace debug info warn error fatal)],
574 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
575 });
576 my $warn_faker = sub {
577 my ($package, $args) = @_;
578 @caller_info = caller($args->{caller_level});
579 $var_log
580 };
581 set_logger($warn_faker);
582 log_debug { 'test' };
583
27141a7a 584The following is an example that uses the information passed to the logger
585coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
586package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
587logger and lastly the logger for the C<A2> package to C<$l2>.
588
37a8266a 589Note that it increases the caller level as it dispatches based on where
590the caller of the log function, not the log function itself.
591
27141a7a 592 my $complex_dispatcher = do {
593
594 my $l1 = ...;
595 my $l2 = ...;
596 my $l3 = ...;
597
598 my %registry = (
599 -logger => $l3,
600 A1 => {
601 -logger => $l1,
602 lol => $l2,
603 },
604 A2 => { -logger => $l2 },
605 );
606
607 sub {
608 my ( $package, $info ) = @_;
609
610 my $logger = $registry{'-logger'};
611 if (my $r = $registry{$package}) {
612 $logger = $r->{'-logger'} if $r->{'-logger'};
37a8266a 613 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
27141a7a 614 $sub =~ s/^\Q$package\E:://g;
615 $logger = $r->{$sub} if $r->{$sub};
616 }
617 return $logger;
618 }
619 };
620
621 set_logger $complex_dispatcher;
622
3dc9bd3c 623=head1 LOGGER INTERFACE
624
625Because this module is ultimately pretty looking glue (glittery?) with the
626awesome benefit of the Contextual part, users will often want to make their
627favorite logger work with it. The following are the methods that should be
628implemented in the logger:
629
630 is_trace
631 is_debug
632 is_info
633 is_warn
634 is_error
635 is_fatal
636 trace
637 debug
638 info
639 warn
640 error
641 fatal
642
643The first six merely need to return true if that level is enabled. The latter
644six take the results of whatever the user returned from their coderef and log
645them. For a basic example see L<Log::Contextual::SimpleLogger>.
646
eab2ca3c 647=head1 LOG ROUTING
648
a5454e75 649In between the loggers and the log functions is a log router that is responsible for
eab2ca3c 650finding a logger to handle the log event and passing the log information to the
a5454e75 651logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
eab2ca3c 652
a5454e75 653C<Log::Contextual> and packages that extend it will by default share a router singleton that
654implements the with_logger() and set_logger() functions and also respects the -logger,
655-package_logger, and -default_logger import options with their associated default value
656functions. The router singleton is available as the return value of the router() function. Users
657of Log::Contextual may overload router() to return instances of custom log routers that
658could for example work with loggers that use a different interface.
eab2ca3c 659
a5454e75 660=head1 AUTHOR
2daff231 661
662frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
663
a5454e75 664=head1 CONTRIBUTORS
665
eab2ca3c 666triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
667
2daff231 668=head1 DESIGNER
669
670mst - Matt S. Trout <mst@shadowcat.co.uk>
671
672=head1 COPYRIGHT
673
a6e29e27 674Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
2daff231 675above.
676
677=head1 LICENSE
678
679This library is free software and may be distributed under the same terms as
680Perl 5 itself.
681
682=cut
683