1 package Log::Contextual;
6 our $VERSION = '0.005000_01';
7 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
9 my @levels = qw(debug trace warn info error fatal);
11 use Exporter::Declare;
12 use Exporter::Declare::Export::Generator;
13 use Data::Dumper::Concise;
14 use Scalar::Util 'blessed';
17 require Log::Log4perl;
18 die if $Log::Log4perl::VERSION < 1.29;
19 Log::Log4perl->wrapper_register(__PACKAGE__)
22 # ____ is because tags must have at least one export and we don't want to
23 # export anything but the levels selected
26 exports(qw(____ set_logger with_logger ));
28 export_tag dlog => ('____');
29 export_tag log => ('____');
30 import_arguments qw(logger package_logger default_logger);
33 our $Router_Instance ||= do {
34 require Log::Contextual::Router;
35 Log::Contextual::Router->new
39 sub arg_logger { $_[1] }
40 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
41 sub arg_package_logger { $_[1] }
42 sub arg_default_logger { $_[1] }
45 my ($class, $importer, $spec) = @_;
46 my $router = $class->router;
47 my $exports = $spec->exports;
51 arguments => $spec->argument_info
54 die 'Log::Contextual does not have a default import list'
55 if $spec->config->{default};
57 $router->before_import(%router_args);
59 if ($exports->{'&set_logger'}) {
60 die ref($router) . " does not support set_logger()"
61 unless $router->does('Log::Contextual::Role::Router::SetLogger');
63 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
66 if ($exports->{'&with_logger'}) {
67 die ref($router) . " does not support with_logger()"
68 unless $router->does('Log::Contextual::Role::Router::WithLogger');
70 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
73 my @levels = @{$class->arg_levels($spec->config->{levels})};
74 for my $level (@levels) {
75 if ($spec->config->{log}) {
79 my ($code, @args) = @_;
80 $router->handle_log_request(
82 caller_package => scalar(caller),
84 message_level => $level,
86 message_args => \@args,
93 my ($code, @args) = @_;
94 $router->handle_log_request(
96 caller_package => scalar(caller),
98 message_level => $level,
100 message_args => \@args,
105 if ($spec->config->{dlog}) {
109 my ($code, @args) = @_;
111 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
114 $router->handle_log_request(
116 caller_package => scalar(caller),
118 message_level => $level,
119 message_sub => $wrapped,
120 message_args => \@args,
127 my ($code, $ref) = @_;
129 local $_ = Data::Dumper::Concise::Dumper($_[0]);
132 $router->handle_log_request(
134 caller_package => scalar(caller),
136 message_level => $level,
137 message_sub => $wrapped,
138 message_args => [$ref],
147 my ($class, $importer, $spec) = @_;
151 arguments => $spec->argument_info
153 $class->router->after_import(%router_args);
162 Log::Contextual - Simple logging interface with a contextual log
166 use Log::Contextual qw( :log :dlog set_logger with_logger );
167 use Log::Contextual::SimpleLogger;
168 use Log::Log4perl ':easy';
169 Log::Log4perl->easy_init($DEBUG);
171 my $logger = Log::Log4perl->get_logger;
175 log_debug { 'program started' };
179 my $minilogger = Log::Contextual::SimpleLogger->new({
180 levels => [qw( trace debug )]
185 with_logger $minilogger => sub {
186 log_trace { 'foo entered' };
187 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
189 log_trace { 'foo left' };
195 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
196 with C<Log::Contextual>:
198 use Log::Contextual qw( :log :dlog set_logger );
199 use Log::Dispatchouli;
200 my $ld = Log::Dispatchouli->new({
201 ident => 'slrtbrfst',
208 log_debug { 'program started' };
218 The logging functions take blocks, so if a log level is disabled, the
221 # the following won't run if debug is off
222 log_debug { "the new count in the database is " . $rs->count };
224 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
229 The logging functions return their arguments, so you can stick them in
230 the middle of expressions:
232 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
236 C<Log::Contextual> is an interface for all major loggers. If you log through
237 C<Log::Contextual> you will be able to swap underlying loggers later.
241 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
242 Normally you don't need to know this, but you can take advantage of it when you
247 If you just want to add logging to your extremely basic application, start with
248 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
249 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
253 This module is a simple interface to extensible logging. It exists to
254 abstract your logging interface so that logging is as painless as possible,
255 while still allowing you to switch from one logger to another.
257 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
258 but in general you should use a real logger instead of that. For something
259 more serious but not overly complicated, try L<Log::Dispatchouli> (see
260 L</SYNOPSIS> for example.)
262 =head1 A WORK IN PROGRESS
264 This module is certainly not complete, but we will not break the interface
265 lightly, so I would say it's safe to use in production code. The main result
266 from that at this point is that doing:
270 will die as we do not yet know what the defaults should be. If it turns out
271 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
272 probably make C<:log> the default. But only time and usage will tell.
274 =head1 IMPORT OPTIONS
276 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
281 When you import this module you may use C<-logger> as a shortcut for
282 L<set_logger>, for example:
284 use Log::Contextual::SimpleLogger;
285 use Log::Contextual qw( :dlog ),
286 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
288 sometimes you might want to have the logger handy for other stuff, in which
289 case you might try something like the following:
292 BEGIN { $var_log = VarLogger->new }
293 use Log::Contextual qw( :dlog ), -logger => $var_log;
297 The C<-levels> import option allows you to define exactly which levels your
298 logger supports. So the default,
299 C<< [qw(debug trace warn info error fatal)] >>, works great for
300 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
301 supporting those levels is as easy as doing
304 -levels => [qw( debug info notice warning error critical alert emergency )];
306 =head2 -package_logger
308 The C<-package_logger> import option is similar to the C<-logger> import option
309 except C<-package_logger> sets the the logger for the current package.
311 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
315 use Log::Contextual::SimpleLogger;
316 use Log::Contextual qw( :log ),
317 -package_logger => Log::Contextual::WarnLogger->new({
318 env_prefix => 'MY_PACKAGE'
321 If you are interested in using this package for a module you are putting on
322 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
324 =head2 -default_logger
326 The C<-default_logger> import option is similar to the C<-logger> import option
327 except C<-default_logger> sets the the B<default> logger for the current package.
329 Basically it sets the logger to be used if C<set_logger> is never called; so
332 use Log::Contextual::SimpleLogger;
333 use Log::Contextual qw( :log ),
334 -default_logger => Log::Contextual::WarnLogger->new({
335 env_prefix => 'MY_PACKAGE'
338 =head1 SETTING DEFAULT IMPORT OPTIONS
340 Eventually you will get tired of writing the following in every single one of
344 use Log::Log4perl ':easy';
345 BEGIN { Log::Log4perl->easy_init($DEBUG) }
347 use Log::Contextual -logger => Log::Log4perl->get_logger;
349 You can set any of the import options for your whole project if you define your
350 own C<Log::Contextual> subclass as follows:
352 package MyApp::Log::Contextual;
354 use base 'Log::Contextual';
356 use Log::Log4perl ':easy';
357 Log::Log4perl->easy_init($DEBUG)
359 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
360 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
362 # or maybe instead of default_logger
363 sub arg_package_logger { $_[1] }
365 # and almost definitely not this, which is only here for completeness
366 sub arg_logger { $_[1] }
368 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
369 passed the values passed in from the arguments to the subclass, so you can
370 either throw them away, honor them, die on usage, or whatever. To be clear,
371 if you define your subclass, and someone uses it as follows:
373 use MyApp::Log::Contextual -default_logger => $foo,
374 -levels => [qw(bar baz biff)];
376 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
377 will get C<[qw(bar baz biff)]>;
383 my $logger = WarnLogger->new;
386 Arguments: L</LOGGER CODEREF>
388 C<set_logger> will just set the current logger to whatever you pass it. It
389 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
390 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
391 top-level script. To avoid foot-shooting the function will warn if you call it
396 my $logger = WarnLogger->new;
397 with_logger $logger => sub {
399 log_fatal { 'Non Logical Universe Detected' };
401 log_info { 'All is good' };
405 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
407 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
408 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
409 C<CodeRef> if needed.
415 Arguments: C<CodeRef $returning_message, @args>
417 C<log_$level> functions all work the same except that a different method
418 is called on the underlying C<$logger> object. The basic pattern is:
420 sub log_$level (&@) {
421 if ($logger->is_$level) {
422 $logger->$level(shift->(@_));
427 Note that the function returns it's arguments. This can be used in a number of
428 ways, but often it's convenient just for partial inspection of passthrough data
430 my @friends = log_trace {
431 'friends list being generated, data from first friend: ' .
432 Dumper($_[0]->TO_JSON)
433 } generate_friend_list();
435 If you want complete inspection of passthrough data, take a look at the
436 L</Dlog_$level> functions.
438 Which functions are exported depends on what was passed to L</-levels>. The
439 default (no C<-levels> option passed) would export:
461 Arguments: C<CodeRef $returning_message, Item $arg>
463 This is really just a special case of the L</log_$level> functions. It forces
464 scalar context when that is what you need. Other than that it works exactly
467 my $friend = logS_trace {
468 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
471 See also: L</DlogS_$level>.
477 Arguments: C<CodeRef $returning_message, @args>
479 All of the following six functions work the same as their L</log_$level>
480 brethren, except they return what is passed into them and put the stringified
481 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
482 you can do cool things like the following:
484 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
486 and the output might look something like:
494 Which functions are exported depends on what was passed to L</-levels>. The
495 default (no C<-levels> option passed) would export:
517 Arguments: C<CodeRef $returning_message, Item $arg>
519 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
520 They only take a single scalar after the C<$returning_message> instead of
521 slurping up (and also setting C<wantarray>) all the C<@args>
523 my $pals_rs = DlogS_debug { "pals resultset: $_" }
524 $schema->resultset('Pals')->search({ perlers => 1 });
526 =head1 LOGGER CODEREF
528 Anywhere a logger object can be passed, a coderef is accepted. This is so
529 that the user can use different logger objects based on runtime information.
530 The logger coderef is passed the package of the caller the caller level the
531 coderef needs to use if it wants more caller information. The latter is in
532 a hashref to allow for more options in the future.
534 Here is a basic example of a logger that exploits C<caller> to reproduce the
535 output of C<warn> with a logger:
538 my $var_log = Log::Contextual::SimpleLogger->new({
539 levels => [qw(trace debug info warn error fatal)],
540 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
542 my $warn_faker = sub {
543 my ($package, $args) = @_;
544 @caller_info = caller($args->{caller_level});
547 set_logger($warn_faker);
548 log_debug { 'test' };
550 The following is an example that uses the information passed to the logger
551 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
552 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
553 logger and lastly the logger for the C<A2> package to C<$l2>.
555 Note that it increases the caller level as it dispatches based on where
556 the caller of the log function, not the log function itself.
558 my $complex_dispatcher = do {
570 A2 => { -logger => $l2 },
574 my ( $package, $info ) = @_;
576 my $logger = $registry{'-logger'};
577 if (my $r = $registry{$package}) {
578 $logger = $r->{'-logger'} if $r->{'-logger'};
579 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
580 $sub =~ s/^\Q$package\E:://g;
581 $logger = $r->{$sub} if $r->{$sub};
587 set_logger $complex_dispatcher;
589 =head1 LOGGER INTERFACE
591 Because this module is ultimately pretty looking glue (glittery?) with the
592 awesome benefit of the Contextual part, users will often want to make their
593 favorite logger work with it. The following are the methods that should be
594 implemented in the logger:
609 The first six merely need to return true if that level is enabled. The latter
610 six take the results of whatever the user returned from their coderef and log
611 them. For a basic example see L<Log::Contextual::SimpleLogger>.
615 In between the loggers and the log functions is a log router that is responsible for
616 finding a logger to handle the log event and passing the log information to the
617 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
619 C<Log::Contextual> and packages that extend it will by default share a router singleton that
620 implements the with_logger() and set_logger() functions and also respects the -logger,
621 -package_logger, and -default_logger import options with their associated default value
622 functions. The router singleton is available as the return value of the router() function. Users
623 of Log::Contextual may overload router() to return instances of custom log routers that
624 could for example work with loggers that use a different interface.
628 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
632 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
636 mst - Matt S. Trout <mst@shadowcat.co.uk>
640 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
645 This library is free software and may be distributed under the same terms as