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