1 package Log::Contextual;
3 # ABSTRACT: Simple logging interface with a contextual log
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';
15 use B qw(svref_2object);
19 ref $coderef or return;
20 my $cv = B::svref_2object($coderef);
21 $cv->isa('B::CV') or return;
22 # bail out if GV is undefined
23 $cv->GV->isa('B::SPECIAL') and return;
25 return $cv->GV->STASH->NAME;
28 my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
30 my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
33 my ($spec, $target, $name, $new_code) = @_;
35 if (my $code = $target->can($name)) {
38 $spec->add_export("&$name", $new_code)
39 unless (stash_name($code) eq __PACKAGE__);
41 $spec->add_export("&$name", $new_code)
46 require Log::Log4perl;
47 die if $Log::Log4perl::VERSION < 1.29;
48 Log::Log4perl->wrapper_register(__PACKAGE__)
51 # ____ is because tags must have at least one export and we don't want to
52 # export anything but the levels selected
55 exports('____', @dlog, @log, qw( set_logger with_logger ));
57 export_tag dlog => ('____');
58 export_tag log => ('____');
59 import_arguments qw(logger package_logger default_logger);
62 our $Router_Instance ||= do {
63 require Log::Contextual::Router;
64 Log::Contextual::Router->new
71 die 'Log::Contextual does not have a default import list';
76 sub arg_logger { $_[1] }
77 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
78 sub arg_package_logger { $_[1] }
79 sub arg_default_logger { $_[1] }
82 my ($class, $importer, $spec) = @_;
83 my $router = $class->router;
84 my $exports = $spec->exports;
88 arguments => $spec->argument_info
91 my @tags = $class->default_import($spec)
92 if $spec->config->{default};
95 die "only tags are supported for defaults at this time"
96 unless $_ =~ /^:(.*)$/;
98 $spec->config->{$1} = 1;
101 $router->before_import(%router_args);
103 if ($exports->{'&set_logger'}) {
104 die ref($router) . " does not support set_logger()"
105 unless $router->does('Log::Contextual::Role::Router::SetLogger');
107 _maybe_export($spec, $importer, 'set_logger',
108 sub { $router->set_logger(@_) },
112 if ($exports->{'&with_logger'}) {
113 die ref($router) . " does not support with_logger()"
114 unless $router->does('Log::Contextual::Role::Router::WithLogger');
116 _maybe_export($spec, $importer, 'with_logger',
117 sub { $router->with_logger(@_) },
121 my @levels = @{$class->arg_levels($spec->config->{levels})};
122 for my $level (@levels) {
123 if ($spec->config->{log} || $exports->{"&log_$level"}) {
129 my ($code, @args) = @_;
130 $router->handle_log_request(
132 caller_package => scalar(caller),
134 message_level => $level,
135 message_sub => $code,
136 message_args => \@args,
142 if ($spec->config->{log} || $exports->{"&logS_$level"}) {
148 my ($code, @args) = @_;
149 $router->handle_log_request(
151 caller_package => scalar(caller),
153 message_level => $level,
154 message_sub => $code,
155 message_args => \@args,
161 if ($spec->config->{dlog} || $exports->{"&Dlog_$level"}) {
167 my ($code, @args) = @_;
169 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
172 $router->handle_log_request(
174 caller_package => scalar(caller),
176 message_level => $level,
177 message_sub => $wrapped,
178 message_args => \@args,
184 if ($spec->config->{dlog} || $exports->{"&DlogS_$level"}) {
190 my ($code, $ref) = @_;
192 local $_ = Data::Dumper::Concise::Dumper($_[0]);
195 $router->handle_log_request(
197 caller_package => scalar(caller),
199 message_level => $level,
200 message_sub => $wrapped,
201 message_args => [$ref],
210 my ($class, $importer, $spec) = @_;
214 arguments => $spec->argument_info
216 $class->router->after_import(%router_args);
221 my $sub = "${_}_logger";
222 *{"Log::Contextual::$sub"} = sub {
223 die "$sub is no longer a direct sub in Log::Contextual. "
224 . 'Note that this feature was never tested nor documented. '
225 . "Please fix your code to import $sub instead of trying to use it directly"
235 use Log::Contextual qw( :log :dlog set_logger with_logger );
236 use Log::Contextual::SimpleLogger;
237 use Log::Log4perl ':easy';
238 Log::Log4perl->easy_init($DEBUG);
240 my $logger = Log::Log4perl->get_logger;
244 log_debug { 'program started' };
248 my $minilogger = Log::Contextual::SimpleLogger->new({
249 levels => [qw( trace debug )]
254 with_logger $minilogger => sub {
255 log_trace { 'foo entered' };
256 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
258 log_trace { 'foo left' };
264 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
265 with C<Log::Contextual>:
267 use Log::Contextual qw( :log :dlog set_logger );
268 use Log::Dispatchouli;
269 my $ld = Log::Dispatchouli->new({
270 ident => 'slrtbrfst',
277 log_debug { 'program started' };
287 The logging functions take blocks, so if a log level is disabled, the
290 # the following won't run if debug is off
291 log_debug { "the new count in the database is " . $rs->count };
293 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
298 The logging functions return their arguments, so you can stick them in
299 the middle of expressions:
301 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
305 C<Log::Contextual> is an interface for all major loggers. If you log through
306 C<Log::Contextual> you will be able to swap underlying loggers later.
310 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
311 Normally you don't need to know this, but you can take advantage of it when you
316 If you just want to add logging to your extremely basic application, start with
317 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
318 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
322 This module is a simple interface to extensible logging. It exists to
323 abstract your logging interface so that logging is as painless as possible,
324 while still allowing you to switch from one logger to another.
326 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
327 but in general you should use a real logger instead of that. For something
328 more serious but not overly complicated, try L<Log::Dispatchouli> (see
329 L</SYNOPSIS> for example.)
331 =head1 A WORK IN PROGRESS
333 This module is certainly not complete, but we will not break the interface
334 lightly, so I would say it's safe to use in production code. The main result
335 from that at this point is that doing:
339 will die as we do not yet know what the defaults should be. If it turns out
340 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
341 probably make C<:log> the default. But only time and usage will tell.
343 =head1 IMPORT OPTIONS
345 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
350 When you import this module you may use C<-logger> as a shortcut for
351 L</set_logger>, for example:
353 use Log::Contextual::SimpleLogger;
354 use Log::Contextual qw( :dlog ),
355 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
357 sometimes you might want to have the logger handy for other stuff, in which
358 case you might try something like the following:
361 BEGIN { $var_log = VarLogger->new }
362 use Log::Contextual qw( :dlog ), -logger => $var_log;
366 The C<-levels> import option allows you to define exactly which levels your
367 logger supports. So the default,
368 C<< [qw(debug trace warn info error fatal)] >>, works great for
369 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
370 supporting those levels is as easy as doing
373 -levels => [qw( debug info notice warning error critical alert emergency )];
375 =head2 -package_logger
377 The C<-package_logger> import option is similar to the C<-logger> import option
378 except C<-package_logger> sets the logger for the current package.
380 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
381 L</set_logger> or L</with_logger>.
384 use Log::Contextual::SimpleLogger;
385 use Log::Contextual qw( :log ),
386 -package_logger => Log::Contextual::WarnLogger->new({
387 env_prefix => 'MY_PACKAGE'
390 If you are interested in using this package for a module you are putting on
391 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
393 =head2 -default_logger
395 The C<-default_logger> import option is similar to the C<-logger> import option
396 except C<-default_logger> sets the B<default> logger for the current package.
398 Basically it sets the logger to be used if C<set_logger> is never called; so
401 use Log::Contextual::SimpleLogger;
402 use Log::Contextual qw( :log ),
403 -default_logger => Log::Contextual::WarnLogger->new({
404 env_prefix => 'MY_PACKAGE'
407 =head1 SETTING DEFAULT IMPORT OPTIONS
409 Eventually you will get tired of writing the following in every single one of
413 use Log::Log4perl ':easy';
414 BEGIN { Log::Log4perl->easy_init($DEBUG) }
416 use Log::Contextual -logger => Log::Log4perl->get_logger;
418 You can set any of the import options for your whole project if you define your
419 own C<Log::Contextual> subclass as follows:
421 package MyApp::Log::Contextual;
423 use base 'Log::Contextual';
425 use Log::Log4perl ':easy';
426 Log::Log4perl->easy_init($DEBUG)
428 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
429 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
430 sub default_import { ':log' }
432 # or maybe instead of default_logger
433 sub arg_package_logger { $_[1] }
435 # and almost definitely not this, which is only here for completeness
436 sub arg_logger { $_[1] }
438 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
439 passed the values passed in from the arguments to the subclass, so you can
440 either throw them away, honor them, die on usage, or whatever. To be clear,
441 if you define your subclass, and someone uses it as follows:
443 use MyApp::Log::Contextual -default_logger => $foo,
444 -levels => [qw(bar baz biff)];
446 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
447 will get C<[qw(bar baz biff)]>;
449 Additionally, the C<default_import> method is what happens if a user tries to
450 use your subclass with no arguments. The default just dies, but if you'd like
451 to change the default to import a tag merely return the tags you'd like to
452 import. So the following will all work:
454 sub default_import { ':log' }
456 sub default_import { ':dlog' }
458 sub default_import { qw(:dlog :log ) }
460 See L<Log::Contextual::Easy::Default> for an example of a subclass of
461 C<Log::Contextual> that makes use of default import options.
467 my $logger = WarnLogger->new;
470 Arguments: L</LOGGER CODEREF>
472 C<set_logger> will just set the current logger to whatever you pass it. It
473 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
474 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
475 top-level script. To avoid foot-shooting the function will warn if you call it
480 my $logger = WarnLogger->new;
481 with_logger $logger => sub {
483 log_fatal { 'Non Logical Universe Detected' };
485 log_info { 'All is good' };
489 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
491 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
492 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
493 C<CodeRef> if needed.
499 Arguments: C<CodeRef $returning_message, @args>
501 C<log_$level> functions all work the same except that a different method
502 is called on the underlying C<$logger> object. The basic pattern is:
504 sub log_$level (&@) {
505 if ($logger->is_$level) {
506 $logger->$level(shift->(@_));
511 Note that the function returns it's arguments. This can be used in a number of
512 ways, but often it's convenient just for partial inspection of passthrough data
514 my @friends = log_trace {
515 'friends list being generated, data from first friend: ' .
516 Dumper($_[0]->TO_JSON)
517 } generate_friend_list();
519 If you want complete inspection of passthrough data, take a look at the
520 L</Dlog_$level> functions.
522 Which functions are exported depends on what was passed to L</-levels>. The
523 default (no C<-levels> option passed) would export:
545 Arguments: C<CodeRef $returning_message, Item $arg>
547 This is really just a special case of the L</log_$level> functions. It forces
548 scalar context when that is what you need. Other than that it works exactly
551 my $friend = logS_trace {
552 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
555 See also: L</DlogS_$level>.
561 Arguments: C<CodeRef $returning_message, @args>
563 All of the following six functions work the same as their L</log_$level>
564 brethren, except they return what is passed into them and put the stringified
565 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
566 you can do cool things like the following:
568 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
570 and the output might look something like:
578 Which functions are exported depends on what was passed to L</-levels>. The
579 default (no C<-levels> option passed) would export:
601 Arguments: C<CodeRef $returning_message, Item $arg>
603 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
604 They only take a single scalar after the C<$returning_message> instead of
605 slurping up (and also setting C<wantarray>) all the C<@args>
607 my $pals_rs = DlogS_debug { "pals resultset: $_" }
608 $schema->resultset('Pals')->search({ perlers => 1 });
610 =head1 LOGGER CODEREF
612 Anywhere a logger object can be passed, a coderef is accepted. This is so
613 that the user can use different logger objects based on runtime information.
614 The logger coderef is passed the package of the caller the caller level the
615 coderef needs to use if it wants more caller information. The latter is in
616 a hashref to allow for more options in the future.
618 Here is a basic example of a logger that exploits C<caller> to reproduce the
619 output of C<warn> with a logger:
622 my $var_log = Log::Contextual::SimpleLogger->new({
623 levels => [qw(trace debug info warn error fatal)],
624 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
626 my $warn_faker = sub {
627 my ($package, $args) = @_;
628 @caller_info = caller($args->{caller_level});
631 set_logger($warn_faker);
632 log_debug { 'test' };
634 The following is an example that uses the information passed to the logger
635 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
636 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
637 logger and lastly the logger for the C<A2> package to C<$l2>.
639 Note that it increases the caller level as it dispatches based on where
640 the caller of the log function, not the log function itself.
642 my $complex_dispatcher = do {
654 A2 => { -logger => $l2 },
658 my ( $package, $info ) = @_;
660 my $logger = $registry{'-logger'};
661 if (my $r = $registry{$package}) {
662 $logger = $r->{'-logger'} if $r->{'-logger'};
663 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
664 $sub =~ s/^\Q$package\E:://g;
665 $logger = $r->{$sub} if $r->{$sub};
671 set_logger $complex_dispatcher;
673 =head1 LOGGER INTERFACE
675 Because this module is ultimately pretty looking glue (glittery?) with the
676 awesome benefit of the Contextual part, users will often want to make their
677 favorite logger work with it. The following are the methods that should be
678 implemented in the logger:
693 The first six merely need to return true if that level is enabled. The latter
694 six take the results of whatever the user returned from their coderef and log
695 them. For a basic example see L<Log::Contextual::SimpleLogger>.
699 In between the loggers and the log functions is a log router that is responsible for
700 finding a logger to handle the log event and passing the log information to the
701 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
703 C<Log::Contextual> and packages that extend it will by default share a router singleton that
704 implements the with_logger() and set_logger() functions and also respects the -logger,
705 -package_logger, and -default_logger import options with their associated default value
706 functions. The router singleton is available as the return value of the router() function. Users
707 of Log::Contextual may overload router() to return instances of custom log routers that
708 could for example work with loggers that use a different interface.
714 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
716 voj - Jakob Voß <voss@gbv.de>
720 mst - Matt S. Trout <mst@shadowcat.co.uk>