1 package Log::Contextual;
6 our $VERSION = '0.005001';
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}) {
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,
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}) {
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,
149 my ($code, $ref) = @_;
151 local $_ = Data::Dumper::Concise::Dumper($_[0]);
154 $router->handle_log_request(
156 caller_package => scalar(caller),
158 message_level => $level,
159 message_sub => $wrapped,
160 message_args => [$ref],
169 my ($class, $importer, $spec) = @_;
173 arguments => $spec->argument_info
175 $class->router->after_import(%router_args);
184 Log::Contextual - Simple logging interface with a contextual log
188 use Log::Contextual qw( :log :dlog set_logger with_logger );
189 use Log::Contextual::SimpleLogger;
190 use Log::Log4perl ':easy';
191 Log::Log4perl->easy_init($DEBUG);
193 my $logger = Log::Log4perl->get_logger;
197 log_debug { 'program started' };
201 my $minilogger = Log::Contextual::SimpleLogger->new({
202 levels => [qw( trace debug )]
207 with_logger $minilogger => sub {
208 log_trace { 'foo entered' };
209 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
211 log_trace { 'foo left' };
217 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
218 with C<Log::Contextual>:
220 use Log::Contextual qw( :log :dlog set_logger );
221 use Log::Dispatchouli;
222 my $ld = Log::Dispatchouli->new({
223 ident => 'slrtbrfst',
230 log_debug { 'program started' };
240 The logging functions take blocks, so if a log level is disabled, the
243 # the following won't run if debug is off
244 log_debug { "the new count in the database is " . $rs->count };
246 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
251 The logging functions return their arguments, so you can stick them in
252 the middle of expressions:
254 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
258 C<Log::Contextual> is an interface for all major loggers. If you log through
259 C<Log::Contextual> you will be able to swap underlying loggers later.
263 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
264 Normally you don't need to know this, but you can take advantage of it when you
269 If you just want to add logging to your extremely basic application, start with
270 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
271 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
275 This module is a simple interface to extensible logging. It exists to
276 abstract your logging interface so that logging is as painless as possible,
277 while still allowing you to switch from one logger to another.
279 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
280 but in general you should use a real logger instead of that. For something
281 more serious but not overly complicated, try L<Log::Dispatchouli> (see
282 L</SYNOPSIS> for example.)
284 =head1 A WORK IN PROGRESS
286 This module is certainly not complete, but we will not break the interface
287 lightly, so I would say it's safe to use in production code. The main result
288 from that at this point is that doing:
292 will die as we do not yet know what the defaults should be. If it turns out
293 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
294 probably make C<:log> the default. But only time and usage will tell.
296 =head1 IMPORT OPTIONS
298 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
303 When you import this module you may use C<-logger> as a shortcut for
304 L<set_logger>, for example:
306 use Log::Contextual::SimpleLogger;
307 use Log::Contextual qw( :dlog ),
308 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
310 sometimes you might want to have the logger handy for other stuff, in which
311 case you might try something like the following:
314 BEGIN { $var_log = VarLogger->new }
315 use Log::Contextual qw( :dlog ), -logger => $var_log;
319 The C<-levels> import option allows you to define exactly which levels your
320 logger supports. So the default,
321 C<< [qw(debug trace warn info error fatal)] >>, works great for
322 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
323 supporting those levels is as easy as doing
326 -levels => [qw( debug info notice warning error critical alert emergency )];
328 =head2 -package_logger
330 The C<-package_logger> import option is similar to the C<-logger> import option
331 except C<-package_logger> sets the the logger for the current package.
333 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
337 use Log::Contextual::SimpleLogger;
338 use Log::Contextual qw( :log ),
339 -package_logger => Log::Contextual::WarnLogger->new({
340 env_prefix => 'MY_PACKAGE'
343 If you are interested in using this package for a module you are putting on
344 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
346 =head2 -default_logger
348 The C<-default_logger> import option is similar to the C<-logger> import option
349 except C<-default_logger> sets the the B<default> logger for the current package.
351 Basically it sets the logger to be used if C<set_logger> is never called; so
354 use Log::Contextual::SimpleLogger;
355 use Log::Contextual qw( :log ),
356 -default_logger => Log::Contextual::WarnLogger->new({
357 env_prefix => 'MY_PACKAGE'
360 =head1 SETTING DEFAULT IMPORT OPTIONS
362 Eventually you will get tired of writing the following in every single one of
366 use Log::Log4perl ':easy';
367 BEGIN { Log::Log4perl->easy_init($DEBUG) }
369 use Log::Contextual -logger => Log::Log4perl->get_logger;
371 You can set any of the import options for your whole project if you define your
372 own C<Log::Contextual> subclass as follows:
374 package MyApp::Log::Contextual;
376 use base 'Log::Contextual';
378 use Log::Log4perl ':easy';
379 Log::Log4perl->easy_init($DEBUG)
381 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
382 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
383 sub default_import { ':log' }
385 # or maybe instead of default_logger
386 sub arg_package_logger { $_[1] }
388 # and almost definitely not this, which is only here for completeness
389 sub arg_logger { $_[1] }
391 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
392 passed the values passed in from the arguments to the subclass, so you can
393 either throw them away, honor them, die on usage, or whatever. To be clear,
394 if you define your subclass, and someone uses it as follows:
396 use MyApp::Log::Contextual -default_logger => $foo,
397 -levels => [qw(bar baz biff)];
399 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
400 will get C<[qw(bar baz biff)]>;
402 Additionally, the C<default_import> method is what happens if a user tries to
403 use your subclass with no arguments. The default just dies, but if you'd like
404 to change the default to import a tag merely return the tags you'd like to
405 import. So the following will all work:
407 sub default_import { ':log' }
409 sub default_import { ':dlog' }
411 sub default_import { qw(:dlog :log ) }
417 my $logger = WarnLogger->new;
420 Arguments: L</LOGGER CODEREF>
422 C<set_logger> will just set the current logger to whatever you pass it. It
423 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
424 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
425 top-level script. To avoid foot-shooting the function will warn if you call it
430 my $logger = WarnLogger->new;
431 with_logger $logger => sub {
433 log_fatal { 'Non Logical Universe Detected' };
435 log_info { 'All is good' };
439 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
441 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
442 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
443 C<CodeRef> if needed.
449 Arguments: C<CodeRef $returning_message, @args>
451 C<log_$level> functions all work the same except that a different method
452 is called on the underlying C<$logger> object. The basic pattern is:
454 sub log_$level (&@) {
455 if ($logger->is_$level) {
456 $logger->$level(shift->(@_));
461 Note that the function returns it's arguments. This can be used in a number of
462 ways, but often it's convenient just for partial inspection of passthrough data
464 my @friends = log_trace {
465 'friends list being generated, data from first friend: ' .
466 Dumper($_[0]->TO_JSON)
467 } generate_friend_list();
469 If you want complete inspection of passthrough data, take a look at the
470 L</Dlog_$level> functions.
472 Which functions are exported depends on what was passed to L</-levels>. The
473 default (no C<-levels> option passed) would export:
495 Arguments: C<CodeRef $returning_message, Item $arg>
497 This is really just a special case of the L</log_$level> functions. It forces
498 scalar context when that is what you need. Other than that it works exactly
501 my $friend = logS_trace {
502 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
505 See also: L</DlogS_$level>.
511 Arguments: C<CodeRef $returning_message, @args>
513 All of the following six functions work the same as their L</log_$level>
514 brethren, except they return what is passed into them and put the stringified
515 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
516 you can do cool things like the following:
518 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
520 and the output might look something like:
528 Which functions are exported depends on what was passed to L</-levels>. The
529 default (no C<-levels> option passed) would export:
551 Arguments: C<CodeRef $returning_message, Item $arg>
553 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
554 They only take a single scalar after the C<$returning_message> instead of
555 slurping up (and also setting C<wantarray>) all the C<@args>
557 my $pals_rs = DlogS_debug { "pals resultset: $_" }
558 $schema->resultset('Pals')->search({ perlers => 1 });
560 =head1 LOGGER CODEREF
562 Anywhere a logger object can be passed, a coderef is accepted. This is so
563 that the user can use different logger objects based on runtime information.
564 The logger coderef is passed the package of the caller the caller level the
565 coderef needs to use if it wants more caller information. The latter is in
566 a hashref to allow for more options in the future.
568 Here is a basic example of a logger that exploits C<caller> to reproduce the
569 output of C<warn> with a logger:
572 my $var_log = Log::Contextual::SimpleLogger->new({
573 levels => [qw(trace debug info warn error fatal)],
574 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
576 my $warn_faker = sub {
577 my ($package, $args) = @_;
578 @caller_info = caller($args->{caller_level});
581 set_logger($warn_faker);
582 log_debug { 'test' };
584 The following is an example that uses the information passed to the logger
585 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
586 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
587 logger and lastly the logger for the C<A2> package to C<$l2>.
589 Note that it increases the caller level as it dispatches based on where
590 the caller of the log function, not the log function itself.
592 my $complex_dispatcher = do {
604 A2 => { -logger => $l2 },
608 my ( $package, $info ) = @_;
610 my $logger = $registry{'-logger'};
611 if (my $r = $registry{$package}) {
612 $logger = $r->{'-logger'} if $r->{'-logger'};
613 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
614 $sub =~ s/^\Q$package\E:://g;
615 $logger = $r->{$sub} if $r->{$sub};
621 set_logger $complex_dispatcher;
623 =head1 LOGGER INTERFACE
625 Because this module is ultimately pretty looking glue (glittery?) with the
626 awesome benefit of the Contextual part, users will often want to make their
627 favorite logger work with it. The following are the methods that should be
628 implemented in the logger:
643 The first six merely need to return true if that level is enabled. The latter
644 six take the results of whatever the user returned from their coderef and log
645 them. For a basic example see L<Log::Contextual::SimpleLogger>.
649 In between the loggers and the log functions is a log router that is responsible for
650 finding a logger to handle the log event and passing the log information to the
651 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
653 C<Log::Contextual> and packages that extend it will by default share a router singleton that
654 implements the with_logger() and set_logger() functions and also respects the -logger,
655 -package_logger, and -default_logger import options with their associated default value
656 functions. The router singleton is available as the return value of the router() function. Users
657 of Log::Contextual may overload router() to return instances of custom log routers that
658 could for example work with loggers that use a different interface.
662 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
666 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
670 mst - Matt S. Trout <mst@shadowcat.co.uk>
674 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
679 This library is free software and may be distributed under the same terms as