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