1 package Log::Contextual;
6 our $VERSION = '0.006000';
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';
16 my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
18 my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
21 require Log::Log4perl;
22 die if $Log::Log4perl::VERSION < 1.29;
23 Log::Log4perl->wrapper_register(__PACKAGE__)
26 # ____ is because tags must have at least one export and we don't want to
27 # export anything but the levels selected
32 qw( set_logger with_logger )
35 export_tag dlog => ('____');
36 export_tag log => ('____');
37 import_arguments qw(logger package_logger default_logger);
40 our $Router_Instance ||= do {
41 require Log::Contextual::Router;
42 Log::Contextual::Router->new
49 die 'Log::Contextual does not have a default import list';
54 sub arg_logger { $_[1] }
55 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
56 sub arg_package_logger { $_[1] }
57 sub arg_default_logger { $_[1] }
60 my ($class, $importer, $spec) = @_;
61 my $router = $class->router;
62 my $exports = $spec->exports;
66 arguments => $spec->argument_info
69 my @tags = $class->default_import($spec)
70 if $spec->config->{default};
73 die "only tags are supported for defaults at this time"
74 unless $_ =~ /^:(.*)$/;
76 $spec->config->{$1} = 1;
79 $router->before_import(%router_args);
81 if ($exports->{'&set_logger'}) {
82 die ref($router) . " does not support set_logger()"
83 unless $router->does('Log::Contextual::Role::Router::SetLogger');
85 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
88 if ($exports->{'&with_logger'}) {
89 die ref($router) . " does not support with_logger()"
90 unless $router->does('Log::Contextual::Role::Router::WithLogger');
92 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
95 my @levels = @{$class->arg_levels($spec->config->{levels})};
96 for my $level (@levels) {
97 if ($spec->config->{log} || $exports->{"&log_$level"}) {
101 my ($code, @args) = @_;
102 $router->handle_log_request(
104 caller_package => scalar(caller),
106 message_level => $level,
107 message_sub => $code,
108 message_args => \@args,
113 if ($spec->config->{log} || $exports->{"&logS_$level"}) {
117 my ($code, @args) = @_;
118 $router->handle_log_request(
120 caller_package => scalar(caller),
122 message_level => $level,
123 message_sub => $code,
124 message_args => \@args,
129 if ($spec->config->{dlog} || $exports->{"&Dlog_$level"}) {
133 my ($code, @args) = @_;
135 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
138 $router->handle_log_request(
140 caller_package => scalar(caller),
142 message_level => $level,
143 message_sub => $wrapped,
144 message_args => \@args,
149 if ($spec->config->{dlog} || $exports->{"&DlogS_$level"}) {
153 my ($code, $ref) = @_;
155 local $_ = Data::Dumper::Concise::Dumper($_[0]);
158 $router->handle_log_request(
160 caller_package => scalar(caller),
162 message_level => $level,
163 message_sub => $wrapped,
164 message_args => [$ref],
173 my ($class, $importer, $spec) = @_;
177 arguments => $spec->argument_info
179 $class->router->after_import(%router_args);
184 my $sub = "${_}_logger";
185 *{"Log::Contextual::$sub"} = sub {
186 die "$sub is no longer a direct sub in Log::Contextual. " .
187 'Note that this feature was never tested nor documented. ' .
188 "Please fix your code to import $sub instead of trying to use it directly"
198 Log::Contextual - Simple logging interface with a contextual log
202 use Log::Contextual qw( :log :dlog set_logger with_logger );
203 use Log::Contextual::SimpleLogger;
204 use Log::Log4perl ':easy';
205 Log::Log4perl->easy_init($DEBUG);
207 my $logger = Log::Log4perl->get_logger;
211 log_debug { 'program started' };
215 my $minilogger = Log::Contextual::SimpleLogger->new({
216 levels => [qw( trace debug )]
221 with_logger $minilogger => sub {
222 log_trace { 'foo entered' };
223 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
225 log_trace { 'foo left' };
231 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
232 with C<Log::Contextual>:
234 use Log::Contextual qw( :log :dlog set_logger );
235 use Log::Dispatchouli;
236 my $ld = Log::Dispatchouli->new({
237 ident => 'slrtbrfst',
244 log_debug { 'program started' };
254 The logging functions take blocks, so if a log level is disabled, the
257 # the following won't run if debug is off
258 log_debug { "the new count in the database is " . $rs->count };
260 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
265 The logging functions return their arguments, so you can stick them in
266 the middle of expressions:
268 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
272 C<Log::Contextual> is an interface for all major loggers. If you log through
273 C<Log::Contextual> you will be able to swap underlying loggers later.
277 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
278 Normally you don't need to know this, but you can take advantage of it when you
283 If you just want to add logging to your extremely basic application, start with
284 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
285 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
289 This module is a simple interface to extensible logging. It exists to
290 abstract your logging interface so that logging is as painless as possible,
291 while still allowing you to switch from one logger to another.
293 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
294 but in general you should use a real logger instead of that. For something
295 more serious but not overly complicated, try L<Log::Dispatchouli> (see
296 L</SYNOPSIS> for example.)
298 =head1 A WORK IN PROGRESS
300 This module is certainly not complete, but we will not break the interface
301 lightly, so I would say it's safe to use in production code. The main result
302 from that at this point is that doing:
306 will die as we do not yet know what the defaults should be. If it turns out
307 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
308 probably make C<:log> the default. But only time and usage will tell.
310 =head1 IMPORT OPTIONS
312 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
317 When you import this module you may use C<-logger> as a shortcut for
318 L</set_logger>, for example:
320 use Log::Contextual::SimpleLogger;
321 use Log::Contextual qw( :dlog ),
322 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
324 sometimes you might want to have the logger handy for other stuff, in which
325 case you might try something like the following:
328 BEGIN { $var_log = VarLogger->new }
329 use Log::Contextual qw( :dlog ), -logger => $var_log;
333 The C<-levels> import option allows you to define exactly which levels your
334 logger supports. So the default,
335 C<< [qw(debug trace warn info error fatal)] >>, works great for
336 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
337 supporting those levels is as easy as doing
340 -levels => [qw( debug info notice warning error critical alert emergency )];
342 =head2 -package_logger
344 The C<-package_logger> import option is similar to the C<-logger> import option
345 except C<-package_logger> sets the logger for the current package.
347 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
351 use Log::Contextual::SimpleLogger;
352 use Log::Contextual qw( :log ),
353 -package_logger => Log::Contextual::WarnLogger->new({
354 env_prefix => 'MY_PACKAGE'
357 If you are interested in using this package for a module you are putting on
358 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
360 =head2 -default_logger
362 The C<-default_logger> import option is similar to the C<-logger> import option
363 except C<-default_logger> sets the B<default> logger for the current package.
365 Basically it sets the logger to be used if C<set_logger> is never called; so
368 use Log::Contextual::SimpleLogger;
369 use Log::Contextual qw( :log ),
370 -default_logger => Log::Contextual::WarnLogger->new({
371 env_prefix => 'MY_PACKAGE'
374 =head1 SETTING DEFAULT IMPORT OPTIONS
376 Eventually you will get tired of writing the following in every single one of
380 use Log::Log4perl ':easy';
381 BEGIN { Log::Log4perl->easy_init($DEBUG) }
383 use Log::Contextual -logger => Log::Log4perl->get_logger;
385 You can set any of the import options for your whole project if you define your
386 own C<Log::Contextual> subclass as follows:
388 package MyApp::Log::Contextual;
390 use base 'Log::Contextual';
392 use Log::Log4perl ':easy';
393 Log::Log4perl->easy_init($DEBUG)
395 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
396 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
397 sub default_import { ':log' }
399 # or maybe instead of default_logger
400 sub arg_package_logger { $_[1] }
402 # and almost definitely not this, which is only here for completeness
403 sub arg_logger { $_[1] }
405 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
406 passed the values passed in from the arguments to the subclass, so you can
407 either throw them away, honor them, die on usage, or whatever. To be clear,
408 if you define your subclass, and someone uses it as follows:
410 use MyApp::Log::Contextual -default_logger => $foo,
411 -levels => [qw(bar baz biff)];
413 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
414 will get C<[qw(bar baz biff)]>;
416 Additionally, the C<default_import> method is what happens if a user tries to
417 use your subclass with no arguments. The default just dies, but if you'd like
418 to change the default to import a tag merely return the tags you'd like to
419 import. So the following will all work:
421 sub default_import { ':log' }
423 sub default_import { ':dlog' }
425 sub default_import { qw(:dlog :log ) }
427 See L<Log::Contextual::Easy::Default> for an example of a subclass of
428 C<Log::Contextual> that makes use of default import options.
434 my $logger = WarnLogger->new;
437 Arguments: L</LOGGER CODEREF>
439 C<set_logger> will just set the current logger to whatever you pass it. It
440 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
441 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
442 top-level script. To avoid foot-shooting the function will warn if you call it
447 my $logger = WarnLogger->new;
448 with_logger $logger => sub {
450 log_fatal { 'Non Logical Universe Detected' };
452 log_info { 'All is good' };
456 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
458 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
459 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
460 C<CodeRef> if needed.
466 Arguments: C<CodeRef $returning_message, @args>
468 C<log_$level> functions all work the same except that a different method
469 is called on the underlying C<$logger> object. The basic pattern is:
471 sub log_$level (&@) {
472 if ($logger->is_$level) {
473 $logger->$level(shift->(@_));
478 Note that the function returns it's arguments. This can be used in a number of
479 ways, but often it's convenient just for partial inspection of passthrough data
481 my @friends = log_trace {
482 'friends list being generated, data from first friend: ' .
483 Dumper($_[0]->TO_JSON)
484 } generate_friend_list();
486 If you want complete inspection of passthrough data, take a look at the
487 L</Dlog_$level> functions.
489 Which functions are exported depends on what was passed to L</-levels>. The
490 default (no C<-levels> option passed) would export:
512 Arguments: C<CodeRef $returning_message, Item $arg>
514 This is really just a special case of the L</log_$level> functions. It forces
515 scalar context when that is what you need. Other than that it works exactly
518 my $friend = logS_trace {
519 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
522 See also: L</DlogS_$level>.
528 Arguments: C<CodeRef $returning_message, @args>
530 All of the following six functions work the same as their L</log_$level>
531 brethren, except they return what is passed into them and put the stringified
532 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
533 you can do cool things like the following:
535 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
537 and the output might look something like:
545 Which functions are exported depends on what was passed to L</-levels>. The
546 default (no C<-levels> option passed) would export:
568 Arguments: C<CodeRef $returning_message, Item $arg>
570 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
571 They only take a single scalar after the C<$returning_message> instead of
572 slurping up (and also setting C<wantarray>) all the C<@args>
574 my $pals_rs = DlogS_debug { "pals resultset: $_" }
575 $schema->resultset('Pals')->search({ perlers => 1 });
577 =head1 LOGGER CODEREF
579 Anywhere a logger object can be passed, a coderef is accepted. This is so
580 that the user can use different logger objects based on runtime information.
581 The logger coderef is passed the package of the caller the caller level the
582 coderef needs to use if it wants more caller information. The latter is in
583 a hashref to allow for more options in the future.
585 Here is a basic example of a logger that exploits C<caller> to reproduce the
586 output of C<warn> with a logger:
589 my $var_log = Log::Contextual::SimpleLogger->new({
590 levels => [qw(trace debug info warn error fatal)],
591 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
593 my $warn_faker = sub {
594 my ($package, $args) = @_;
595 @caller_info = caller($args->{caller_level});
598 set_logger($warn_faker);
599 log_debug { 'test' };
601 The following is an example that uses the information passed to the logger
602 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
603 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
604 logger and lastly the logger for the C<A2> package to C<$l2>.
606 Note that it increases the caller level as it dispatches based on where
607 the caller of the log function, not the log function itself.
609 my $complex_dispatcher = do {
621 A2 => { -logger => $l2 },
625 my ( $package, $info ) = @_;
627 my $logger = $registry{'-logger'};
628 if (my $r = $registry{$package}) {
629 $logger = $r->{'-logger'} if $r->{'-logger'};
630 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
631 $sub =~ s/^\Q$package\E:://g;
632 $logger = $r->{$sub} if $r->{$sub};
638 set_logger $complex_dispatcher;
640 =head1 LOGGER INTERFACE
642 Because this module is ultimately pretty looking glue (glittery?) with the
643 awesome benefit of the Contextual part, users will often want to make their
644 favorite logger work with it. The following are the methods that should be
645 implemented in the logger:
660 The first six merely need to return true if that level is enabled. The latter
661 six take the results of whatever the user returned from their coderef and log
662 them. For a basic example see L<Log::Contextual::SimpleLogger>.
666 In between the loggers and the log functions is a log router that is responsible for
667 finding a logger to handle the log event and passing the log information to the
668 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
670 C<Log::Contextual> and packages that extend it will by default share a router singleton that
671 implements the with_logger() and set_logger() functions and also respects the -logger,
672 -package_logger, and -default_logger import options with their associated default value
673 functions. The router singleton is available as the return value of the router() function. Users
674 of Log::Contextual may overload router() to return instances of custom log routers that
675 could for example work with loggers that use a different interface.
679 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
685 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
687 voj - Jakob Voß <voss@gbv.de>
691 mst - Matt S. Trout <mst@shadowcat.co.uk>
695 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
700 This library is free software and may be distributed under the same terms as