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