1 package Log::Contextual;
6 our $VERSION = '0.004202';
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';
16 require Log::Log4perl;
17 die if $Log::Log4perl::VERSION < 1.29;
18 Log::Log4perl->wrapper_register(__PACKAGE__)
21 # ____ is because tags must have at least one export and we don't want to
22 # export anything but the levels selected
25 exports(qw(____ set_logger with_logger ));
27 export_tag dlog => ('____');
28 export_tag log => ('____');
29 import_arguments qw(logger package_logger default_logger);
32 our $Router_Instance ||= do {
33 require Log::Contextual::Router;
34 Log::Contextual::Router->new
38 sub arg_logger { $_[1] }
39 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
40 sub arg_package_logger { $_[1] }
41 sub arg_default_logger { $_[1] }
44 my ($class, $importer, $spec) = @_;
45 my $router = $class->router;
46 my $exports = $spec->exports;
50 arguments => $spec->argument_info
53 die 'Log::Contextual does not have a default import list'
54 if $spec->config->{default};
56 $router->before_import(%router_args);
58 if ($exports->{'&set_logger'}) {
59 die ref($router) . " does not support set_logger()"
60 unless $router->does('Log::Contextual::Role::Router::SetLogger');
62 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
65 if ($exports->{'&with_logger'}) {
66 die ref($router) . " does not support with_logger()"
67 unless $router->does('Log::Contextual::Role::Router::WithLogger');
69 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
72 my @levels = @{$class->arg_levels($spec->config->{levels})};
73 for my $level (@levels) {
74 if ($spec->config->{log}) {
78 my ($code, @args) = @_;
79 $router->handle_log_request(
81 caller_package => scalar(caller),
83 message_level => $level,
85 message_args => \@args,
92 my ($code, @args) = @_;
93 $router->handle_log_request(
95 caller_package => scalar(caller),
97 message_level => $level,
99 message_args => \@args,
104 if ($spec->config->{dlog}) {
108 my ($code, @args) = @_;
110 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
113 $router->handle_log_request(
115 caller_package => scalar(caller),
117 message_level => $level,
118 message_sub => $wrapped,
119 message_args => \@args,
126 my ($code, $ref) = @_;
128 local $_ = Data::Dumper::Concise::Dumper($_[0]);
131 $router->handle_log_request(
133 caller_package => scalar(caller),
135 message_level => $level,
136 message_sub => $wrapped,
137 message_args => [$ref],
146 my ($class, $importer, $spec) = @_;
150 arguments => $spec->argument_info
152 $class->router->after_import(%router_args);
161 Log::Contextual - Simple logging interface with a contextual log
165 use Log::Contextual qw( :log :dlog set_logger with_logger );
166 use Log::Contextual::SimpleLogger;
167 use Log::Log4perl ':easy';
168 Log::Log4perl->easy_init($DEBUG);
170 my $logger = Log::Log4perl->get_logger;
174 log_debug { 'program started' };
178 my $minilogger = Log::Contextual::SimpleLogger->new({
179 levels => [qw( trace debug )]
184 with_logger $minilogger => sub {
185 log_trace { 'foo entered' };
186 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
188 log_trace { 'foo left' };
194 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
195 with C<Log::Contextual>:
197 use Log::Contextual qw( :log :dlog set_logger );
198 use Log::Dispatchouli;
199 my $ld = Log::Dispatchouli->new({
200 ident => 'slrtbrfst',
207 log_debug { 'program started' };
217 The logging functions take blocks, so if a log level is disabled, the
220 # the following won't run if debug is off
221 log_debug { "the new count in the database is " . $rs->count };
223 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
228 The logging functions return their arguments, so you can stick them in
229 the middle of expressions:
231 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
235 C<Log::Contextual> is an interface for all major loggers. If you log through
236 C<Log::Contextual> you will be able to swap underlying loggers later.
240 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
241 Normally you don't need to know this, but you can take advantage of it when you
246 If you just want to add logging to your extremely basic application, start with
247 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
248 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
252 This module is a simple interface to extensible logging. It exists to
253 abstract your logging interface so that logging is as painless as possible,
254 while still allowing you to switch from one logger to another.
256 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
257 but in general you should use a real logger instead of that. For something
258 more serious but not overly complicated, try L<Log::Dispatchouli> (see
259 L</SYNOPSIS> for example.)
261 =head1 A WORK IN PROGRESS
263 This module is certainly not complete, but we will not break the interface
264 lightly, so I would say it's safe to use in production code. The main result
265 from that at this point is that doing:
269 will die as we do not yet know what the defaults should be. If it turns out
270 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
271 probably make C<:log> the default. But only time and usage will tell.
273 =head1 IMPORT OPTIONS
275 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
280 When you import this module you may use C<-logger> as a shortcut for
281 L<set_logger>, for example:
283 use Log::Contextual::SimpleLogger;
284 use Log::Contextual qw( :dlog ),
285 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
287 sometimes you might want to have the logger handy for other stuff, in which
288 case you might try something like the following:
291 BEGIN { $var_log = VarLogger->new }
292 use Log::Contextual qw( :dlog ), -logger => $var_log;
296 The C<-levels> import option allows you to define exactly which levels your
297 logger supports. So the default,
298 C<< [qw(debug trace warn info error fatal)] >>, works great for
299 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
300 supporting those levels is as easy as doing
303 -levels => [qw( debug info notice warning error critical alert emergency )];
305 =head2 -package_logger
307 The C<-package_logger> import option is similar to the C<-logger> import option
308 except C<-package_logger> sets the the logger for the current package.
310 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
314 use Log::Contextual::SimpleLogger;
315 use Log::Contextual qw( :log ),
316 -package_logger => Log::Contextual::WarnLogger->new({
317 env_prefix => 'MY_PACKAGE'
320 If you are interested in using this package for a module you are putting on
321 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
323 =head2 -default_logger
325 The C<-default_logger> import option is similar to the C<-logger> import option
326 except C<-default_logger> sets the the B<default> logger for the current package.
328 Basically it sets the logger to be used if C<set_logger> is never called; so
331 use Log::Contextual::SimpleLogger;
332 use Log::Contextual qw( :log ),
333 -default_logger => Log::Contextual::WarnLogger->new({
334 env_prefix => 'MY_PACKAGE'
337 =head1 SETTING DEFAULT IMPORT OPTIONS
339 Eventually you will get tired of writing the following in every single one of
343 use Log::Log4perl ':easy';
344 BEGIN { Log::Log4perl->easy_init($DEBUG) }
346 use Log::Contextual -logger => Log::Log4perl->get_logger;
348 You can set any of the import options for your whole project if you define your
349 own C<Log::Contextual> subclass as follows:
351 package MyApp::Log::Contextual;
353 use base 'Log::Contextual';
355 use Log::Log4perl ':easy';
356 Log::Log4perl->easy_init($DEBUG)
358 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
359 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
361 # or maybe instead of default_logger
362 sub arg_package_logger { $_[1] }
364 # and almost definitely not this, which is only here for completeness
365 sub arg_logger { $_[1] }
367 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
368 passed the values passed in from the arguments to the subclass, so you can
369 either throw them away, honor them, die on usage, or whatever. To be clear,
370 if you define your subclass, and someone uses it as follows:
372 use MyApp::Log::Contextual -default_logger => $foo,
373 -levels => [qw(bar baz biff)];
375 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
376 will get C<[qw(bar baz biff)]>;
382 my $logger = WarnLogger->new;
385 Arguments: L</LOGGER CODEREF>
387 C<set_logger> will just set the current logger to whatever you pass it. It
388 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
389 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
390 top-level script. To avoid foot-shooting the function will warn if you call it
395 my $logger = WarnLogger->new;
396 with_logger $logger => sub {
398 log_fatal { 'Non Logical Universe Detected' };
400 log_info { 'All is good' };
404 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
406 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
407 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
408 C<CodeRef> if needed.
414 Arguments: C<CodeRef $returning_message, @args>
416 C<log_$level> functions all work the same except that a different method
417 is called on the underlying C<$logger> object. The basic pattern is:
419 sub log_$level (&@) {
420 if ($logger->is_$level) {
421 $logger->$level(shift->(@_));
426 Note that the function returns it's arguments. This can be used in a number of
427 ways, but often it's convenient just for partial inspection of passthrough data
429 my @friends = log_trace {
430 'friends list being generated, data from first friend: ' .
431 Dumper($_[0]->TO_JSON)
432 } generate_friend_list();
434 If you want complete inspection of passthrough data, take a look at the
435 L</Dlog_$level> functions.
437 Which functions are exported depends on what was passed to L</-levels>. The
438 default (no C<-levels> option passed) would export:
460 Arguments: C<CodeRef $returning_message, Item $arg>
462 This is really just a special case of the L</log_$level> functions. It forces
463 scalar context when that is what you need. Other than that it works exactly
466 my $friend = logS_trace {
467 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
470 See also: L</DlogS_$level>.
476 Arguments: C<CodeRef $returning_message, @args>
478 All of the following six functions work the same as their L</log_$level>
479 brethren, except they return what is passed into them and put the stringified
480 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
481 you can do cool things like the following:
483 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
485 and the output might look something like:
493 Which functions are exported depends on what was passed to L</-levels>. The
494 default (no C<-levels> option passed) would export:
516 Arguments: C<CodeRef $returning_message, Item $arg>
518 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
519 They only take a single scalar after the C<$returning_message> instead of
520 slurping up (and also setting C<wantarray>) all the C<@args>
522 my $pals_rs = DlogS_debug { "pals resultset: $_" }
523 $schema->resultset('Pals')->search({ perlers => 1 });
525 =head1 LOGGER CODEREF
527 Anywhere a logger object can be passed, a coderef is accepted. This is so
528 that the user can use different logger objects based on runtime information.
529 The logger coderef is passed the package of the caller the caller level the
530 coderef needs to use if it wants more caller information. The latter is in
531 a hashref to allow for more options in the future.
533 Here is a basic example of a logger that exploits C<caller> to reproduce the
534 output of C<warn> with a logger:
537 my $var_log = Log::Contextual::SimpleLogger->new({
538 levels => [qw(trace debug info warn error fatal)],
539 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
541 my $warn_faker = sub {
542 my ($package, $args) = @_;
543 @caller_info = caller($args->{caller_level});
546 set_logger($warn_faker);
547 log_debug { 'test' };
549 The following is an example that uses the information passed to the logger
550 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
551 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
552 logger and lastly the logger for the C<A2> package to C<$l2>.
554 Note that it increases the caller level as it dispatches based on where
555 the caller of the log function, not the log function itself.
557 my $complex_dispatcher = do {
569 A2 => { -logger => $l2 },
573 my ( $package, $info ) = @_;
575 my $logger = $registry{'-logger'};
576 if (my $r = $registry{$package}) {
577 $logger = $r->{'-logger'} if $r->{'-logger'};
578 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
579 $sub =~ s/^\Q$package\E:://g;
580 $logger = $r->{$sub} if $r->{$sub};
586 set_logger $complex_dispatcher;
588 =head1 LOGGER INTERFACE
590 Because this module is ultimately pretty looking glue (glittery?) with the
591 awesome benefit of the Contextual part, users will often want to make their
592 favorite logger work with it. The following are the methods that should be
593 implemented in the logger:
608 The first six merely need to return true if that level is enabled. The latter
609 six take the results of whatever the user returned from their coderef and log
610 them. For a basic example see L<Log::Contextual::SimpleLogger>.
614 In between the loggers and the log functions is a log router that is responsible for
615 finding a logger to handle the log event and passing the log information to the
616 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
618 C<Log::Contextual> and packages that extend it will by default share a router singleton that
619 implements the with_logger() and set_logger() functions and also respects the -logger,
620 -package_logger, and -default_logger import options with their associated default value
621 functions. The router singleton is available as the return value of the router() function. Users
622 of Log::Contextual may overload router() to return instances of custom log routers that
623 could for example work with loggers that use a different interface.
627 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
631 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
635 mst - Matt S. Trout <mst@shadowcat.co.uk>
639 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
644 This library is free software and may be distributed under the same terms as