1 package Log::Contextual;
6 our $VERSION = '0.006000';
7 $VERSION = eval $VERSION
8 if $VERSION =~ /_/; # numify for warning-free dev releases
10 my @levels = qw(debug trace warn info error fatal);
12 use Exporter::Declare;
13 use Exporter::Declare::Export::Generator;
14 use Data::Dumper::Concise;
15 use Scalar::Util 'blessed';
17 my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
19 my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
22 require Log::Log4perl;
23 die if $Log::Log4perl::VERSION < 1.29;
24 Log::Log4perl->wrapper_register(__PACKAGE__)
27 # ____ is because tags must have at least one export and we don't want to
28 # export anything but the levels selected
31 exports('____', @dlog, @log, qw( set_logger with_logger ));
33 export_tag dlog => ('____');
34 export_tag log => ('____');
35 import_arguments qw(logger package_logger default_logger);
38 our $Router_Instance ||= do {
39 require Log::Contextual::Router;
40 Log::Contextual::Router->new
47 die 'Log::Contextual does not have a default import list';
52 sub arg_logger { $_[1] }
53 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
54 sub arg_package_logger { $_[1] }
55 sub arg_default_logger { $_[1] }
58 my ($class, $importer, $spec) = @_;
59 my $router = $class->router;
60 my $exports = $spec->exports;
64 arguments => $spec->argument_info
67 my @tags = $class->default_import($spec)
68 if $spec->config->{default};
71 die "only tags are supported for defaults at this time"
72 unless $_ =~ /^:(.*)$/;
74 $spec->config->{$1} = 1;
77 $router->before_import(%router_args);
79 if ($exports->{'&set_logger'}) {
80 die ref($router) . " does not support set_logger()"
81 unless $router->does('Log::Contextual::Role::Router::SetLogger');
83 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
86 if ($exports->{'&with_logger'}) {
87 die ref($router) . " does not support with_logger()"
88 unless $router->does('Log::Contextual::Role::Router::WithLogger');
90 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
93 my @levels = @{$class->arg_levels($spec->config->{levels})};
94 for my $level (@levels) {
95 if ($spec->config->{log} || $exports->{"&log_$level"}) {
99 my ($code, @args) = @_;
100 $router->handle_log_request(
102 caller_package => scalar(caller),
104 message_level => $level,
105 message_sub => $code,
106 message_args => \@args,
111 if ($spec->config->{log} || $exports->{"&logS_$level"}) {
115 my ($code, @args) = @_;
116 $router->handle_log_request(
118 caller_package => scalar(caller),
120 message_level => $level,
121 message_sub => $code,
122 message_args => \@args,
127 if ($spec->config->{dlog} || $exports->{"&Dlog_$level"}) {
131 my ($code, @args) = @_;
133 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
136 $router->handle_log_request(
138 caller_package => scalar(caller),
140 message_level => $level,
141 message_sub => $wrapped,
142 message_args => \@args,
147 if ($spec->config->{dlog} || $exports->{"&DlogS_$level"}) {
151 my ($code, $ref) = @_;
153 local $_ = Data::Dumper::Concise::Dumper($_[0]);
156 $router->handle_log_request(
158 caller_package => scalar(caller),
160 message_level => $level,
161 message_sub => $wrapped,
162 message_args => [$ref],
171 my ($class, $importer, $spec) = @_;
175 arguments => $spec->argument_info
177 $class->router->after_import(%router_args);
182 my $sub = "${_}_logger";
183 *{"Log::Contextual::$sub"} = sub {
184 die "$sub is no longer a direct sub in Log::Contextual. "
185 . 'Note that this feature was never tested nor documented. '
186 . "Please fix your code to import $sub instead of trying to use it directly"
196 Log::Contextual - Simple logging interface with a contextual log
200 use Log::Contextual qw( :log :dlog set_logger with_logger );
201 use Log::Contextual::SimpleLogger;
202 use Log::Log4perl ':easy';
203 Log::Log4perl->easy_init($DEBUG);
205 my $logger = Log::Log4perl->get_logger;
209 log_debug { 'program started' };
213 my $minilogger = Log::Contextual::SimpleLogger->new({
214 levels => [qw( trace debug )]
219 with_logger $minilogger => sub {
220 log_trace { 'foo entered' };
221 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
223 log_trace { 'foo left' };
229 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
230 with C<Log::Contextual>:
232 use Log::Contextual qw( :log :dlog set_logger );
233 use Log::Dispatchouli;
234 my $ld = Log::Dispatchouli->new({
235 ident => 'slrtbrfst',
242 log_debug { 'program started' };
252 The logging functions take blocks, so if a log level is disabled, the
255 # the following won't run if debug is off
256 log_debug { "the new count in the database is " . $rs->count };
258 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
263 The logging functions return their arguments, so you can stick them in
264 the middle of expressions:
266 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
270 C<Log::Contextual> is an interface for all major loggers. If you log through
271 C<Log::Contextual> you will be able to swap underlying loggers later.
275 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
276 Normally you don't need to know this, but you can take advantage of it when you
281 If you just want to add logging to your extremely basic application, start with
282 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
283 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
287 This module is a simple interface to extensible logging. It exists to
288 abstract your logging interface so that logging is as painless as possible,
289 while still allowing you to switch from one logger to another.
291 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
292 but in general you should use a real logger instead of that. For something
293 more serious but not overly complicated, try L<Log::Dispatchouli> (see
294 L</SYNOPSIS> for example.)
296 =head1 A WORK IN PROGRESS
298 This module is certainly not complete, but we will not break the interface
299 lightly, so I would say it's safe to use in production code. The main result
300 from that at this point is that doing:
304 will die as we do not yet know what the defaults should be. If it turns out
305 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
306 probably make C<:log> the default. But only time and usage will tell.
308 =head1 IMPORT OPTIONS
310 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
315 When you import this module you may use C<-logger> as a shortcut for
316 L</set_logger>, for example:
318 use Log::Contextual::SimpleLogger;
319 use Log::Contextual qw( :dlog ),
320 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
322 sometimes you might want to have the logger handy for other stuff, in which
323 case you might try something like the following:
326 BEGIN { $var_log = VarLogger->new }
327 use Log::Contextual qw( :dlog ), -logger => $var_log;
331 The C<-levels> import option allows you to define exactly which levels your
332 logger supports. So the default,
333 C<< [qw(debug trace warn info error fatal)] >>, works great for
334 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
335 supporting those levels is as easy as doing
338 -levels => [qw( debug info notice warning error critical alert emergency )];
340 =head2 -package_logger
342 The C<-package_logger> import option is similar to the C<-logger> import option
343 except C<-package_logger> sets the logger for the current package.
345 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
349 use Log::Contextual::SimpleLogger;
350 use Log::Contextual qw( :log ),
351 -package_logger => Log::Contextual::WarnLogger->new({
352 env_prefix => 'MY_PACKAGE'
355 If you are interested in using this package for a module you are putting on
356 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
358 =head2 -default_logger
360 The C<-default_logger> import option is similar to the C<-logger> import option
361 except C<-default_logger> sets the B<default> logger for the current package.
363 Basically it sets the logger to be used if C<set_logger> is never called; so
366 use Log::Contextual::SimpleLogger;
367 use Log::Contextual qw( :log ),
368 -default_logger => Log::Contextual::WarnLogger->new({
369 env_prefix => 'MY_PACKAGE'
372 =head1 SETTING DEFAULT IMPORT OPTIONS
374 Eventually you will get tired of writing the following in every single one of
378 use Log::Log4perl ':easy';
379 BEGIN { Log::Log4perl->easy_init($DEBUG) }
381 use Log::Contextual -logger => Log::Log4perl->get_logger;
383 You can set any of the import options for your whole project if you define your
384 own C<Log::Contextual> subclass as follows:
386 package MyApp::Log::Contextual;
388 use base 'Log::Contextual';
390 use Log::Log4perl ':easy';
391 Log::Log4perl->easy_init($DEBUG)
393 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
394 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
395 sub default_import { ':log' }
397 # or maybe instead of default_logger
398 sub arg_package_logger { $_[1] }
400 # and almost definitely not this, which is only here for completeness
401 sub arg_logger { $_[1] }
403 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
404 passed the values passed in from the arguments to the subclass, so you can
405 either throw them away, honor them, die on usage, or whatever. To be clear,
406 if you define your subclass, and someone uses it as follows:
408 use MyApp::Log::Contextual -default_logger => $foo,
409 -levels => [qw(bar baz biff)];
411 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
412 will get C<[qw(bar baz biff)]>;
414 Additionally, the C<default_import> method is what happens if a user tries to
415 use your subclass with no arguments. The default just dies, but if you'd like
416 to change the default to import a tag merely return the tags you'd like to
417 import. So the following will all work:
419 sub default_import { ':log' }
421 sub default_import { ':dlog' }
423 sub default_import { qw(:dlog :log ) }
425 See L<Log::Contextual::Easy::Default> for an example of a subclass of
426 C<Log::Contextual> that makes use of default import options.
432 my $logger = WarnLogger->new;
435 Arguments: L</LOGGER CODEREF>
437 C<set_logger> will just set the current logger to whatever you pass it. It
438 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
439 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
440 top-level script. To avoid foot-shooting the function will warn if you call it
445 my $logger = WarnLogger->new;
446 with_logger $logger => sub {
448 log_fatal { 'Non Logical Universe Detected' };
450 log_info { 'All is good' };
454 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
456 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
457 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
458 C<CodeRef> if needed.
464 Arguments: C<CodeRef $returning_message, @args>
466 C<log_$level> functions all work the same except that a different method
467 is called on the underlying C<$logger> object. The basic pattern is:
469 sub log_$level (&@) {
470 if ($logger->is_$level) {
471 $logger->$level(shift->(@_));
476 Note that the function returns it's arguments. This can be used in a number of
477 ways, but often it's convenient just for partial inspection of passthrough data
479 my @friends = log_trace {
480 'friends list being generated, data from first friend: ' .
481 Dumper($_[0]->TO_JSON)
482 } generate_friend_list();
484 If you want complete inspection of passthrough data, take a look at the
485 L</Dlog_$level> functions.
487 Which functions are exported depends on what was passed to L</-levels>. The
488 default (no C<-levels> option passed) would export:
510 Arguments: C<CodeRef $returning_message, Item $arg>
512 This is really just a special case of the L</log_$level> functions. It forces
513 scalar context when that is what you need. Other than that it works exactly
516 my $friend = logS_trace {
517 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
520 See also: L</DlogS_$level>.
526 Arguments: C<CodeRef $returning_message, @args>
528 All of the following six functions work the same as their L</log_$level>
529 brethren, except they return what is passed into them and put the stringified
530 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
531 you can do cool things like the following:
533 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
535 and the output might look something like:
543 Which functions are exported depends on what was passed to L</-levels>. The
544 default (no C<-levels> option passed) would export:
566 Arguments: C<CodeRef $returning_message, Item $arg>
568 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
569 They only take a single scalar after the C<$returning_message> instead of
570 slurping up (and also setting C<wantarray>) all the C<@args>
572 my $pals_rs = DlogS_debug { "pals resultset: $_" }
573 $schema->resultset('Pals')->search({ perlers => 1 });
575 =head1 LOGGER CODEREF
577 Anywhere a logger object can be passed, a coderef is accepted. This is so
578 that the user can use different logger objects based on runtime information.
579 The logger coderef is passed the package of the caller the caller level the
580 coderef needs to use if it wants more caller information. The latter is in
581 a hashref to allow for more options in the future.
583 Here is a basic example of a logger that exploits C<caller> to reproduce the
584 output of C<warn> with a logger:
587 my $var_log = Log::Contextual::SimpleLogger->new({
588 levels => [qw(trace debug info warn error fatal)],
589 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
591 my $warn_faker = sub {
592 my ($package, $args) = @_;
593 @caller_info = caller($args->{caller_level});
596 set_logger($warn_faker);
597 log_debug { 'test' };
599 The following is an example that uses the information passed to the logger
600 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
601 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
602 logger and lastly the logger for the C<A2> package to C<$l2>.
604 Note that it increases the caller level as it dispatches based on where
605 the caller of the log function, not the log function itself.
607 my $complex_dispatcher = do {
619 A2 => { -logger => $l2 },
623 my ( $package, $info ) = @_;
625 my $logger = $registry{'-logger'};
626 if (my $r = $registry{$package}) {
627 $logger = $r->{'-logger'} if $r->{'-logger'};
628 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
629 $sub =~ s/^\Q$package\E:://g;
630 $logger = $r->{$sub} if $r->{$sub};
636 set_logger $complex_dispatcher;
638 =head1 LOGGER INTERFACE
640 Because this module is ultimately pretty looking glue (glittery?) with the
641 awesome benefit of the Contextual part, users will often want to make their
642 favorite logger work with it. The following are the methods that should be
643 implemented in the logger:
658 The first six merely need to return true if that level is enabled. The latter
659 six take the results of whatever the user returned from their coderef and log
660 them. For a basic example see L<Log::Contextual::SimpleLogger>.
664 In between the loggers and the log functions is a log router that is responsible for
665 finding a logger to handle the log event and passing the log information to the
666 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
668 C<Log::Contextual> and packages that extend it will by default share a router singleton that
669 implements the with_logger() and set_logger() functions and also respects the -logger,
670 -package_logger, and -default_logger import options with their associated default value
671 functions. The router singleton is available as the return value of the router() function. Users
672 of Log::Contextual may overload router() to return instances of custom log routers that
673 could for example work with loggers that use a different interface.
677 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
683 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
685 voj - Jakob Voß <voss@gbv.de>
689 mst - Matt S. Trout <mst@shadowcat.co.uk>
693 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
698 This library is free software and may be distributed under the same terms as