1 package Log::Contextual;
6 our $VERSION = '0.004202';
8 my @levels = qw(debug trace warn info error fatal);
10 use Exporter::Declare;
11 use Exporter::Declare::Export::Generator;
12 use Data::Dumper::Concise;
13 use Scalar::Util 'blessed';
16 require Log::Log4perl;
17 die if $Log::Log4perl::VERSION < 1.29;
18 Log::Log4perl->wrapper_register(__PACKAGE__)
21 # ____ is because tags must have at least one export and we don't want to
22 # export anything but the levels selected
25 exports(qw(____ set_logger with_logger ));
27 export_tag dlog => ('____');
28 export_tag log => ('____');
29 import_arguments qw(logger package_logger default_logger);
32 our $Router_Instance ||= do {
33 require Log::Contextual::Router;
34 Log::Contextual::Router->new
38 sub arg_logger { $_[1] }
39 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
40 sub arg_package_logger { $_[1] }
41 sub arg_default_logger { $_[1] }
44 my ($class, $importer, $spec) = @_;
45 my $router = $class->router;
46 my $exports = $spec->exports;
50 arguments => $spec->argument_info
53 die 'Log::Contextual does not have a default import list'
54 if $spec->config->{default};
56 $router->before_import(%router_args);
61 my $router = $class->router;
63 die ref($router) . " does not support set_logger()"
64 unless $router->does('Log::Contextual::Role::Router::SetLogger');
66 return $router->set_logger(@_);
67 }) if $exports->{'&set_logger'};
72 my $router = $class->router;
74 die ref($router) . " does not support with_logger()"
75 unless $router->does('Log::Contextual::Role::Router::WithLogger');
77 return $router->with_logger(@_);
78 }) if $exports->{'&with_logger'};
80 my @levels = @{$class->arg_levels($spec->config->{levels})};
81 for my $level (@levels) {
82 if ($spec->config->{log}) {
86 my ($code, @args) = @_;
87 $router->handle_log_request(
89 caller_package => scalar(caller),
91 message_level => $level,
93 message_args => \@args,
100 my ($code, @args) = @_;
101 $router->handle_log_request(
103 caller_package => scalar(caller),
105 message_level => $level,
106 message_sub => $code,
107 message_args => \@args,
112 if ($spec->config->{dlog}) {
116 my ($code, @args) = @_;
118 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
121 $router->handle_log_request(
123 caller_package => scalar(caller),
125 message_level => $level,
126 message_sub => $wrapped,
127 message_args => \@args,
134 my ($code, $ref) = @_;
136 local $_ = Data::Dumper::Concise::Dumper($_[0]);
139 $router->handle_log_request(
141 caller_package => scalar(caller),
143 message_level => $level,
144 message_sub => $wrapped,
145 message_args => [$ref],
154 my ($class, $importer, $spec) = @_;
158 arguments => $spec->argument_info
160 $class->router->after_import(%router_args);
169 Log::Contextual - Simple logging interface with a contextual log
173 use Log::Contextual qw( :log :dlog set_logger with_logger );
174 use Log::Contextual::SimpleLogger;
175 use Log::Log4perl ':easy';
176 Log::Log4perl->easy_init($DEBUG);
178 my $logger = Log::Log4perl->get_logger;
182 log_debug { 'program started' };
186 my $minilogger = Log::Contextual::SimpleLogger->new({
187 levels => [qw( trace debug )]
190 with_logger $minilogger => sub {
191 log_trace { 'foo entered' };
192 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
194 log_trace { 'foo left' };
200 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
201 with C<Log::Contextual>:
203 use Log::Contextual qw( :log :dlog set_logger );
204 use Log::Dispatchouli;
205 my $ld = Log::Dispatchouli->new({
206 ident => 'slrtbrfst',
213 log_debug { 'program started' };
223 The logging functions take blocks, so if a log level is disabled, the
226 # the following won't run if debug is off
227 log_debug { "the new count in the database is " . $rs->count };
229 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
234 The logging functions return their arguments, so you can stick them in
235 the middle of expressions:
237 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
241 C<Log::Contextual> is an interface for all major loggers. If you log through
242 C<Log::Contextual> you will be able to swap underlying loggers later.
246 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
247 Normally you don't need to know this, but you can take advantage of it when you
252 If you just want to add logging to your extremely basic application, start with
253 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
254 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
258 This module is a simple interface to extensible logging. It exists to
259 abstract your logging interface so that logging is as painless as possible,
260 while still allowing you to switch from one logger to another.
262 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
263 but in general you should use a real logger instead of that. For something
264 more serious but not overly complicated, try L<Log::Dispatchouli> (see
265 L</SYNOPSIS> for example.)
267 =head1 A WORK IN PROGRESS
269 This module is certainly not complete, but we will not break the interface
270 lightly, so I would say it's safe to use in production code. The main result
271 from that at this point is that doing:
275 will die as we do not yet know what the defaults should be. If it turns out
276 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
277 probably make C<:log> the default. But only time and usage will tell.
279 =head1 IMPORT OPTIONS
281 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
286 When you import this module you may use C<-logger> as a shortcut for
287 L<set_logger>, for example:
289 use Log::Contextual::SimpleLogger;
290 use Log::Contextual qw( :dlog ),
291 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
293 sometimes you might want to have the logger handy for other stuff, in which
294 case you might try something like the following:
297 BEGIN { $var_log = VarLogger->new }
298 use Log::Contextual qw( :dlog ), -logger => $var_log;
302 The C<-levels> import option allows you to define exactly which levels your
303 logger supports. So the default,
304 C<< [qw(debug trace warn info error fatal)] >>, works great for
305 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
306 supporting those levels is as easy as doing
309 -levels => [qw( debug info notice warning error critical alert emergency )];
311 =head2 -package_logger
313 The C<-package_logger> import option is similar to the C<-logger> import option
314 except C<-package_logger> sets the the logger for the current package.
316 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
320 use Log::Contextual::SimpleLogger;
321 use Log::Contextual qw( :log ),
322 -package_logger => Log::Contextual::WarnLogger->new({
323 env_prefix => 'MY_PACKAGE'
326 If you are interested in using this package for a module you are putting on
327 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
329 =head2 -default_logger
331 The C<-default_logger> import option is similar to the C<-logger> import option
332 except C<-default_logger> sets the the B<default> logger for the current package.
334 Basically it sets the logger to be used if C<set_logger> is never called; so
337 use Log::Contextual::SimpleLogger;
338 use Log::Contextual qw( :log ),
339 -default_logger => Log::Contextual::WarnLogger->new({
340 env_prefix => 'MY_PACKAGE'
343 =head1 SETTING DEFAULT IMPORT OPTIONS
345 Eventually you will get tired of writing the following in every single one of
349 use Log::Log4perl ':easy';
350 BEGIN { Log::Log4perl->easy_init($DEBUG) }
352 use Log::Contextual -logger => Log::Log4perl->get_logger;
354 You can set any of the import options for your whole project if you define your
355 own C<Log::Contextual> subclass as follows:
357 package MyApp::Log::Contextual;
359 use base 'Log::Contextual';
361 use Log::Log4perl ':easy';
362 Log::Log4perl->easy_init($DEBUG)
364 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
365 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
367 # or maybe instead of default_logger
368 sub arg_package_logger { $_[1] }
370 # and almost definitely not this, which is only here for completeness
371 sub arg_logger { $_[1] }
373 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
374 passed the values passed in from the arguments to the subclass, so you can
375 either throw them away, honor them, die on usage, or whatever. To be clear,
376 if you define your subclass, and someone uses it as follows:
378 use MyApp::Log::Contextual -default_logger => $foo,
379 -levels => [qw(bar baz biff)];
381 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
382 will get C<[qw(bar baz biff)]>;
388 my $logger = WarnLogger->new;
391 Arguments: L</LOGGER CODEREF>
393 C<set_logger> will just set the current logger to whatever you pass it. It
394 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
395 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
396 top-level script. To avoid foot-shooting the function will warn if you call it
401 my $logger = WarnLogger->new;
402 with_logger $logger => sub {
404 log_fatal { 'Non Logical Universe Detected' };
406 log_info { 'All is good' };
410 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
412 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
413 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
414 C<CodeRef> if needed.
420 Arguments: C<CodeRef $returning_message, @args>
422 C<log_$level> functions all work the same except that a different method
423 is called on the underlying C<$logger> object. The basic pattern is:
425 sub log_$level (&@) {
426 if ($logger->is_$level) {
427 $logger->$level(shift->(@_));
432 Note that the function returns it's arguments. This can be used in a number of
433 ways, but often it's convenient just for partial inspection of passthrough data
435 my @friends = log_trace {
436 'friends list being generated, data from first friend: ' .
437 Dumper($_[0]->TO_JSON)
438 } generate_friend_list();
440 If you want complete inspection of passthrough data, take a look at the
441 L</Dlog_$level> functions.
443 Which functions are exported depends on what was passed to L</-levels>. The
444 default (no C<-levels> option passed) would export:
466 Arguments: C<CodeRef $returning_message, Item $arg>
468 This is really just a special case of the L</log_$level> functions. It forces
469 scalar context when that is what you need. Other than that it works exactly
472 my $friend = logS_trace {
473 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
476 See also: L</DlogS_$level>.
482 Arguments: C<CodeRef $returning_message, @args>
484 All of the following six functions work the same as their L</log_$level>
485 brethren, except they return what is passed into them and put the stringified
486 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
487 you can do cool things like the following:
489 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
491 and the output might look something like:
499 Which functions are exported depends on what was passed to L</-levels>. The
500 default (no C<-levels> option passed) would export:
522 Arguments: C<CodeRef $returning_message, Item $arg>
524 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
525 They only take a single scalar after the C<$returning_message> instead of
526 slurping up (and also setting C<wantarray>) all the C<@args>
528 my $pals_rs = DlogS_debug { "pals resultset: $_" }
529 $schema->resultset('Pals')->search({ perlers => 1 });
531 =head1 LOGGER CODEREF
533 Anywhere a logger object can be passed, a coderef is accepted. This is so
534 that the user can use different logger objects based on runtime information.
535 The logger coderef is passed the package of the caller the caller level the
536 coderef needs to use if it wants more caller information. The latter is in
537 a hashref to allow for more options in the future.
539 Here is a basic example of a logger that exploits C<caller> to reproduce the
540 output of C<warn> with a logger:
543 my $var_log = Log::Contextual::SimpleLogger->new({
544 levels => [qw(trace debug info warn error fatal)],
545 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
547 my $warn_faker = sub {
548 my ($package, $args) = @_;
549 @caller_info = caller($args->{caller_level});
552 set_logger($warn_faker);
553 log_debug { 'test' };
555 The following is an example that uses the information passed to the logger
556 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
557 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
558 logger and lastly the logger for the C<A2> package to C<$l2>.
560 Note that it increases the caller level as it dispatches based on where
561 the caller of the log function, not the log function itself.
563 my $complex_dispatcher = do {
575 A2 => { -logger => $l2 },
579 my ( $package, $info ) = @_;
581 my $logger = $registry{'-logger'};
582 if (my $r = $registry{$package}) {
583 $logger = $r->{'-logger'} if $r->{'-logger'};
584 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
585 $sub =~ s/^\Q$package\E:://g;
586 $logger = $r->{$sub} if $r->{$sub};
592 set_logger $complex_dispatcher;
594 =head1 LOGGER INTERFACE
596 Because this module is ultimately pretty looking glue (glittery?) with the
597 awesome benefit of the Contextual part, users will often want to make their
598 favorite logger work with it. The following are the methods that should be
599 implemented in the logger:
614 The first six merely need to return true if that level is enabled. The latter
615 six take the results of whatever the user returned from their coderef and log
616 them. For a basic example see L<Log::Contextual::SimpleLogger>.
620 In between the loggers and the log functions is a log router that is responsible for
621 finding a logger to handle the log event and passing the log information to the
622 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
624 C<Log::Contextual> and packages that extend it will by default share a router singleton that
625 implements the with_logger() and set_logger() functions and also respects the -logger,
626 -package_logger, and -default_logger import options with their associated default value
627 functions. The router singleton is available as the return value of the router() function. Users
628 of Log::Contextual may overload router() to return instances of custom log routers that
629 could for example work with loggers that use a different interface.
633 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
637 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
641 mst - Matt S. Trout <mst@shadowcat.co.uk>
645 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
650 This library is free software and may be distributed under the same terms as