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';
15 my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
17 my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
20 require Log::Log4perl;
21 die if $Log::Log4perl::VERSION < 1.29;
22 Log::Log4perl->wrapper_register(__PACKAGE__)
25 # ____ is because tags must have at least one export and we don't want to
26 # export anything but the levels selected
31 qw( set_logger with_logger )
34 export_tag dlog => ('____');
35 export_tag log => ('____');
36 import_arguments qw(logger package_logger default_logger);
39 our $Router_Instance ||= do {
40 require Log::Contextual::Router;
41 Log::Contextual::Router->new
45 sub arg_logger { $_[1] }
46 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
47 sub arg_package_logger { $_[1] }
48 sub arg_default_logger { $_[1] }
51 my ($class, $importer, $spec) = @_;
52 my $router = $class->router;
53 my $exports = $spec->exports;
54 my %router_args = (exporter => $class, target => $importer, arguments => $spec->argument_info);
56 die 'Log::Contextual does not have a default import list'
57 if $spec->config->{default};
59 $router->before_import(%router_args);
61 $spec->add_export('&set_logger', sub {
62 my $router = $class->router;
64 die ref($router) . " does not support set_logger()"
65 unless $router->does('Log::Contextual::Role::Router::SetLogger');
67 return $router->set_logger(@_);
68 }) if $exports->{'&set_logger'};
70 $spec->add_export('&with_logger', sub {
71 my $router = $class->router;
73 die ref($router) . " does not support with_logger()"
74 unless $router->does('Log::Contextual::Role::Router::WithLogger');
76 return $router->with_logger(@_);
77 }) if $exports->{'&with_logger'};
79 my @levels = @{$class->arg_levels($spec->config->{levels})};
80 for my $level (@levels) {
81 if ($spec->config->{log}) {
82 $spec->add_export("&log_$level", sub (&@) {
83 my ($code, @args) = @_;
84 $router->handle_log_request(
85 exporter => $class, caller_package => scalar(caller), caller_level => 1,
86 message_level => $level, message_sub => $code, message_args => \@args,
90 $spec->add_export("&logS_$level", sub (&@) {
91 my ($code, @args) = @_;
92 $router->handle_log_request(
93 exporter => $class, caller_package => scalar(caller), caller_level => 1,
94 message_level => $level, message_sub => $code, message_args => \@args,
99 if ($spec->config->{dlog}) {
100 $spec->add_export("&Dlog_$level", sub (&@) {
101 my ($code, @args) = @_;
103 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
106 $router->handle_log_request(
107 exporter => $class, caller_package => scalar(caller), caller_level => 1,
108 message_level => $level, message_sub => $wrapped, message_args => \@args,
112 $spec->add_export("&DlogS_$level", sub (&$) {
113 my ($code, $ref) = @_;
115 local $_ = Data::Dumper::Concise::Dumper($_[0]);
118 $router->handle_log_request(
119 exporter => $class, caller_package => scalar(caller), caller_level => 1,
120 message_level => $level, message_sub => $wrapped, message_args => [ $ref ],
129 my ($class, $importer, $spec) = @_;
130 my %router_args = (exporter => $class, target => $importer, arguments => $spec->argument_info);
131 $class->router->after_import(%router_args);
140 Log::Contextual - Simple logging interface with a contextual log
144 use Log::Contextual qw( :log :dlog set_logger with_logger );
145 use Log::Contextual::SimpleLogger;
146 use Log::Log4perl ':easy';
147 Log::Log4perl->easy_init($DEBUG);
149 my $logger = Log::Log4perl->get_logger;
153 log_debug { 'program started' };
157 my $minilogger = Log::Contextual::SimpleLogger->new({
158 levels => [qw( trace debug )]
161 with_logger $minilogger => sub {
162 log_trace { 'foo entered' };
163 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
165 log_trace { 'foo left' };
171 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
172 with C<Log::Contextual>:
174 use Log::Contextual qw( :log :dlog set_logger );
175 use Log::Dispatchouli;
176 my $ld = Log::Dispatchouli->new({
177 ident => 'slrtbrfst',
184 log_debug { 'program started' };
194 The logging functions take blocks, so if a log level is disabled, the
197 # the following won't run if debug is off
198 log_debug { "the new count in the database is " . $rs->count };
200 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
205 The logging functions return their arguments, so you can stick them in
206 the middle of expressions:
208 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
212 C<Log::Contextual> is an interface for all major loggers. If you log through
213 C<Log::Contextual> you will be able to swap underlying loggers later.
217 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
218 Normally you don't need to know this, but you can take advantage of it when you
223 If you just want to add logging to your extremely basic application, start with
224 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
225 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
229 This module is a simple interface to extensible logging. It exists to
230 abstract your logging interface so that logging is as painless as possible,
231 while still allowing you to switch from one logger to another.
233 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
234 but in general you should use a real logger instead of that. For something
235 more serious but not overly complicated, try L<Log::Dispatchouli> (see
236 L</SYNOPSIS> for example.)
238 =head1 A WORK IN PROGRESS
240 This module is certainly not complete, but we will not break the interface
241 lightly, so I would say it's safe to use in production code. The main result
242 from that at this point is that doing:
246 will die as we do not yet know what the defaults should be. If it turns out
247 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
248 probably make C<:log> the default. But only time and usage will tell.
250 =head1 IMPORT OPTIONS
252 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
257 When you import this module you may use C<-logger> as a shortcut for
258 L<set_logger>, for example:
260 use Log::Contextual::SimpleLogger;
261 use Log::Contextual qw( :dlog ),
262 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
264 sometimes you might want to have the logger handy for other stuff, in which
265 case you might try something like the following:
268 BEGIN { $var_log = VarLogger->new }
269 use Log::Contextual qw( :dlog ), -logger => $var_log;
273 The C<-levels> import option allows you to define exactly which levels your
274 logger supports. So the default,
275 C<< [qw(debug trace warn info error fatal)] >>, works great for
276 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
277 supporting those levels is as easy as doing
280 -levels => [qw( debug info notice warning error critical alert emergency )];
282 =head2 -package_logger
284 The C<-package_logger> import option is similar to the C<-logger> import option
285 except C<-package_logger> sets the the logger for the current package.
287 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
291 use Log::Contextual::SimpleLogger;
292 use Log::Contextual qw( :log ),
293 -package_logger => Log::Contextual::WarnLogger->new({
294 env_prefix => 'MY_PACKAGE'
297 If you are interested in using this package for a module you are putting on
298 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
300 =head2 -default_logger
302 The C<-default_logger> import option is similar to the C<-logger> import option
303 except C<-default_logger> sets the the B<default> logger for the current package.
305 Basically it sets the logger to be used if C<set_logger> is never called; so
308 use Log::Contextual::SimpleLogger;
309 use Log::Contextual qw( :log ),
310 -default_logger => Log::Contextual::WarnLogger->new({
311 env_prefix => 'MY_PACKAGE'
314 =head1 SETTING DEFAULT IMPORT OPTIONS
316 Eventually you will get tired of writing the following in every single one of
320 use Log::Log4perl ':easy';
321 BEGIN { Log::Log4perl->easy_init($DEBUG) }
323 use Log::Contextual -logger => Log::Log4perl->get_logger;
325 You can set any of the import options for your whole project if you define your
326 own C<Log::Contextual> subclass as follows:
328 package MyApp::Log::Contextual;
330 use base 'Log::Contextual';
332 use Log::Log4perl ':easy';
333 Log::Log4perl->easy_init($DEBUG)
335 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
336 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
338 # or maybe instead of default_logger
339 sub arg_package_logger { $_[1] }
341 # and almost definitely not this, which is only here for completeness
342 sub arg_logger { $_[1] }
344 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
345 passed the values passed in from the arguments to the subclass, so you can
346 either throw them away, honor them, die on usage, or whatever. To be clear,
347 if you define your subclass, and someone uses it as follows:
349 use MyApp::Log::Contextual -default_logger => $foo,
350 -levels => [qw(bar baz biff)];
352 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
353 will get C<[qw(bar baz biff)]>;
359 my $logger = WarnLogger->new;
362 Arguments: L</LOGGER CODEREF>
364 C<set_logger> will just set the current logger to whatever you pass it. It
365 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
366 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
367 top-level script. To avoid foot-shooting the function will warn if you call it
372 my $logger = WarnLogger->new;
373 with_logger $logger => sub {
375 log_fatal { 'Non Logical Universe Detected' };
377 log_info { 'All is good' };
381 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
383 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
384 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
385 C<CodeRef> if needed.
391 Arguments: C<CodeRef $returning_message, @args>
393 C<log_$level> functions all work the same except that a different method
394 is called on the underlying C<$logger> object. The basic pattern is:
396 sub log_$level (&@) {
397 if ($logger->is_$level) {
398 $logger->$level(shift->(@_));
403 Note that the function returns it's arguments. This can be used in a number of
404 ways, but often it's convenient just for partial inspection of passthrough data
406 my @friends = log_trace {
407 'friends list being generated, data from first friend: ' .
408 Dumper($_[0]->TO_JSON)
409 } generate_friend_list();
411 If you want complete inspection of passthrough data, take a look at the
412 L</Dlog_$level> functions.
414 Which functions are exported depends on what was passed to L</-levels>. The
415 default (no C<-levels> option passed) would export:
437 Arguments: C<CodeRef $returning_message, Item $arg>
439 This is really just a special case of the L</log_$level> functions. It forces
440 scalar context when that is what you need. Other than that it works exactly
443 my $friend = logS_trace {
444 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
447 See also: L</DlogS_$level>.
453 Arguments: C<CodeRef $returning_message, @args>
455 All of the following six functions work the same as their L</log_$level>
456 brethren, except they return what is passed into them and put the stringified
457 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
458 you can do cool things like the following:
460 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
462 and the output might look something like:
470 Which functions are exported depends on what was passed to L</-levels>. The
471 default (no C<-levels> option passed) would export:
493 Arguments: C<CodeRef $returning_message, Item $arg>
495 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
496 They only take a single scalar after the C<$returning_message> instead of
497 slurping up (and also setting C<wantarray>) all the C<@args>
499 my $pals_rs = DlogS_debug { "pals resultset: $_" }
500 $schema->resultset('Pals')->search({ perlers => 1 });
502 =head1 LOGGER CODEREF
504 Anywhere a logger object can be passed, a coderef is accepted. This is so
505 that the user can use different logger objects based on runtime information.
506 The logger coderef is passed the package of the caller the caller level the
507 coderef needs to use if it wants more caller information. The latter is in
508 a hashref to allow for more options in the future.
510 Here is a basic example of a logger that exploits C<caller> to reproduce the
511 output of C<warn> with a logger:
514 my $var_log = Log::Contextual::SimpleLogger->new({
515 levels => [qw(trace debug info warn error fatal)],
516 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
518 my $warn_faker = sub {
519 my ($package, $args) = @_;
520 @caller_info = caller($args->{caller_level});
523 set_logger($warn_faker);
524 log_debug { 'test' };
526 The following is an example that uses the information passed to the logger
527 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
528 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
529 logger and lastly the logger for the C<A2> package to C<$l2>.
531 Note that it increases the caller level as it dispatches based on where
532 the caller of the log function, not the log function itself.
534 my $complex_dispatcher = do {
546 A2 => { -logger => $l2 },
550 my ( $package, $info ) = @_;
552 my $logger = $registry{'-logger'};
553 if (my $r = $registry{$package}) {
554 $logger = $r->{'-logger'} if $r->{'-logger'};
555 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
556 $sub =~ s/^\Q$package\E:://g;
557 $logger = $r->{$sub} if $r->{$sub};
563 set_logger $complex_dispatcher;
565 =head1 LOGGER INTERFACE
567 Because this module is ultimately pretty looking glue (glittery?) with the
568 awesome benefit of the Contextual part, users will often want to make their
569 favorite logger work with it. The following are the methods that should be
570 implemented in the logger:
585 The first six merely need to return true if that level is enabled. The latter
586 six take the results of whatever the user returned from their coderef and log
587 them. For a basic example see L<Log::Contextual::SimpleLogger>.
591 In between the loggers and the log functions is a log router that is responsible for
592 finding a logger to handle the log event and passing the log information to the
593 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
595 C<Log::Contextual> and packages that extend it will by default share a router singleton that
596 implements the with_logger() and set_logger() functions and also respects the -logger,
597 -package_logger, and -default_logger import options with their associated default value
598 functions. The router singleton is available as the return value of the router() function. Users
599 of Log::Contextual may overload router() to return instances of custom log routers that
600 could for example work with loggers that use a different interface.
604 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
608 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
612 mst - Matt S. Trout <mst@shadowcat.co.uk>
616 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
621 This library is free software and may be distributed under the same terms as