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