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