1 package Log::Contextual;
6 our $VERSION = '0.005000_03';
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';
17 require Log::Log4perl;
18 die if $Log::Log4perl::VERSION < 1.29;
19 Log::Log4perl->wrapper_register(__PACKAGE__)
22 # ____ is because tags must have at least one export and we don't want to
23 # export anything but the levels selected
26 exports(qw(____ set_logger with_logger ));
28 export_tag dlog => ('____');
29 export_tag log => ('____');
30 import_arguments qw(logger package_logger default_logger);
33 our $Router_Instance ||= do {
34 require Log::Contextual::Router;
35 Log::Contextual::Router->new
42 die 'Log::Contextual does not have a default import list';
47 sub arg_logger { $_[1] }
48 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
49 sub arg_package_logger { $_[1] }
50 sub arg_default_logger { $_[1] }
53 my ($class, $importer, $spec) = @_;
54 my $router = $class->router;
55 my $exports = $spec->exports;
59 arguments => $spec->argument_info
62 my @tags = $class->default_import($spec)
63 if $spec->config->{default};
66 die "only tags are supported for defaults at this time"
67 unless $_ =~ /^:(.*)$/;
69 $spec->config->{$1} = 1;
72 $router->before_import(%router_args);
74 if ($exports->{'&set_logger'}) {
75 die ref($router) . " does not support set_logger()"
76 unless $router->does('Log::Contextual::Role::Router::SetLogger');
78 $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
81 if ($exports->{'&with_logger'}) {
82 die ref($router) . " does not support with_logger()"
83 unless $router->does('Log::Contextual::Role::Router::WithLogger');
85 $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
88 my @levels = @{$class->arg_levels($spec->config->{levels})};
89 for my $level (@levels) {
90 if ($spec->config->{log}) {
94 my ($code, @args) = @_;
95 $router->handle_log_request(
97 caller_package => scalar(caller),
99 message_level => $level,
100 message_sub => $code,
101 message_args => \@args,
108 my ($code, @args) = @_;
109 $router->handle_log_request(
111 caller_package => scalar(caller),
113 message_level => $level,
114 message_sub => $code,
115 message_args => \@args,
120 if ($spec->config->{dlog}) {
124 my ($code, @args) = @_;
126 local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
129 $router->handle_log_request(
131 caller_package => scalar(caller),
133 message_level => $level,
134 message_sub => $wrapped,
135 message_args => \@args,
142 my ($code, $ref) = @_;
144 local $_ = Data::Dumper::Concise::Dumper($_[0]);
147 $router->handle_log_request(
149 caller_package => scalar(caller),
151 message_level => $level,
152 message_sub => $wrapped,
153 message_args => [$ref],
162 my ($class, $importer, $spec) = @_;
166 arguments => $spec->argument_info
168 $class->router->after_import(%router_args);
177 Log::Contextual - Simple logging interface with a contextual log
181 use Log::Contextual qw( :log :dlog set_logger with_logger );
182 use Log::Contextual::SimpleLogger;
183 use Log::Log4perl ':easy';
184 Log::Log4perl->easy_init($DEBUG);
186 my $logger = Log::Log4perl->get_logger;
190 log_debug { 'program started' };
194 my $minilogger = Log::Contextual::SimpleLogger->new({
195 levels => [qw( trace debug )]
200 with_logger $minilogger => sub {
201 log_trace { 'foo entered' };
202 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
204 log_trace { 'foo left' };
210 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
211 with C<Log::Contextual>:
213 use Log::Contextual qw( :log :dlog set_logger );
214 use Log::Dispatchouli;
215 my $ld = Log::Dispatchouli->new({
216 ident => 'slrtbrfst',
223 log_debug { 'program started' };
233 The logging functions take blocks, so if a log level is disabled, the
236 # the following won't run if debug is off
237 log_debug { "the new count in the database is " . $rs->count };
239 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
244 The logging functions return their arguments, so you can stick them in
245 the middle of expressions:
247 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
251 C<Log::Contextual> is an interface for all major loggers. If you log through
252 C<Log::Contextual> you will be able to swap underlying loggers later.
256 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
257 Normally you don't need to know this, but you can take advantage of it when you
262 If you just want to add logging to your extremely basic application, start with
263 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
264 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
268 This module is a simple interface to extensible logging. It exists to
269 abstract your logging interface so that logging is as painless as possible,
270 while still allowing you to switch from one logger to another.
272 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
273 but in general you should use a real logger instead of that. For something
274 more serious but not overly complicated, try L<Log::Dispatchouli> (see
275 L</SYNOPSIS> for example.)
277 =head1 A WORK IN PROGRESS
279 This module is certainly not complete, but we will not break the interface
280 lightly, so I would say it's safe to use in production code. The main result
281 from that at this point is that doing:
285 will die as we do not yet know what the defaults should be. If it turns out
286 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
287 probably make C<:log> the default. But only time and usage will tell.
289 =head1 IMPORT OPTIONS
291 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
296 When you import this module you may use C<-logger> as a shortcut for
297 L<set_logger>, for example:
299 use Log::Contextual::SimpleLogger;
300 use Log::Contextual qw( :dlog ),
301 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
303 sometimes you might want to have the logger handy for other stuff, in which
304 case you might try something like the following:
307 BEGIN { $var_log = VarLogger->new }
308 use Log::Contextual qw( :dlog ), -logger => $var_log;
312 The C<-levels> import option allows you to define exactly which levels your
313 logger supports. So the default,
314 C<< [qw(debug trace warn info error fatal)] >>, works great for
315 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
316 supporting those levels is as easy as doing
319 -levels => [qw( debug info notice warning error critical alert emergency )];
321 =head2 -package_logger
323 The C<-package_logger> import option is similar to the C<-logger> import option
324 except C<-package_logger> sets the the logger for the current package.
326 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
330 use Log::Contextual::SimpleLogger;
331 use Log::Contextual qw( :log ),
332 -package_logger => Log::Contextual::WarnLogger->new({
333 env_prefix => 'MY_PACKAGE'
336 If you are interested in using this package for a module you are putting on
337 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
339 =head2 -default_logger
341 The C<-default_logger> import option is similar to the C<-logger> import option
342 except C<-default_logger> sets the the B<default> logger for the current package.
344 Basically it sets the logger to be used if C<set_logger> is never called; so
347 use Log::Contextual::SimpleLogger;
348 use Log::Contextual qw( :log ),
349 -default_logger => Log::Contextual::WarnLogger->new({
350 env_prefix => 'MY_PACKAGE'
353 =head1 SETTING DEFAULT IMPORT OPTIONS
355 Eventually you will get tired of writing the following in every single one of
359 use Log::Log4perl ':easy';
360 BEGIN { Log::Log4perl->easy_init($DEBUG) }
362 use Log::Contextual -logger => Log::Log4perl->get_logger;
364 You can set any of the import options for your whole project if you define your
365 own C<Log::Contextual> subclass as follows:
367 package MyApp::Log::Contextual;
369 use base 'Log::Contextual';
371 use Log::Log4perl ':easy';
372 Log::Log4perl->easy_init($DEBUG)
374 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
375 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
376 sub default_import { ':log' }
378 # or maybe instead of default_logger
379 sub arg_package_logger { $_[1] }
381 # and almost definitely not this, which is only here for completeness
382 sub arg_logger { $_[1] }
384 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
385 passed the values passed in from the arguments to the subclass, so you can
386 either throw them away, honor them, die on usage, or whatever. To be clear,
387 if you define your subclass, and someone uses it as follows:
389 use MyApp::Log::Contextual -default_logger => $foo,
390 -levels => [qw(bar baz biff)];
392 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
393 will get C<[qw(bar baz biff)]>;
395 Additionally, the C<default_import> method is what happens if a user tries to
396 use your subclass with no arguments. The default just dies, but if you'd like
397 to change the default to import a tag merely return the tags you'd like to
398 import. So the following will all work:
400 sub default_import { ':log' }
402 sub default_import { ':dlog' }
404 sub default_import { qw(:dlog :log ) }
410 my $logger = WarnLogger->new;
413 Arguments: L</LOGGER CODEREF>
415 C<set_logger> will just set the current logger to whatever you pass it. It
416 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
417 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
418 top-level script. To avoid foot-shooting the function will warn if you call it
423 my $logger = WarnLogger->new;
424 with_logger $logger => sub {
426 log_fatal { 'Non Logical Universe Detected' };
428 log_info { 'All is good' };
432 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
434 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
435 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
436 C<CodeRef> if needed.
442 Arguments: C<CodeRef $returning_message, @args>
444 C<log_$level> functions all work the same except that a different method
445 is called on the underlying C<$logger> object. The basic pattern is:
447 sub log_$level (&@) {
448 if ($logger->is_$level) {
449 $logger->$level(shift->(@_));
454 Note that the function returns it's arguments. This can be used in a number of
455 ways, but often it's convenient just for partial inspection of passthrough data
457 my @friends = log_trace {
458 'friends list being generated, data from first friend: ' .
459 Dumper($_[0]->TO_JSON)
460 } generate_friend_list();
462 If you want complete inspection of passthrough data, take a look at the
463 L</Dlog_$level> functions.
465 Which functions are exported depends on what was passed to L</-levels>. The
466 default (no C<-levels> option passed) would export:
488 Arguments: C<CodeRef $returning_message, Item $arg>
490 This is really just a special case of the L</log_$level> functions. It forces
491 scalar context when that is what you need. Other than that it works exactly
494 my $friend = logS_trace {
495 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
498 See also: L</DlogS_$level>.
504 Arguments: C<CodeRef $returning_message, @args>
506 All of the following six functions work the same as their L</log_$level>
507 brethren, except they return what is passed into them and put the stringified
508 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
509 you can do cool things like the following:
511 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
513 and the output might look something like:
521 Which functions are exported depends on what was passed to L</-levels>. The
522 default (no C<-levels> option passed) would export:
544 Arguments: C<CodeRef $returning_message, Item $arg>
546 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
547 They only take a single scalar after the C<$returning_message> instead of
548 slurping up (and also setting C<wantarray>) all the C<@args>
550 my $pals_rs = DlogS_debug { "pals resultset: $_" }
551 $schema->resultset('Pals')->search({ perlers => 1 });
553 =head1 LOGGER CODEREF
555 Anywhere a logger object can be passed, a coderef is accepted. This is so
556 that the user can use different logger objects based on runtime information.
557 The logger coderef is passed the package of the caller the caller level the
558 coderef needs to use if it wants more caller information. The latter is in
559 a hashref to allow for more options in the future.
561 Here is a basic example of a logger that exploits C<caller> to reproduce the
562 output of C<warn> with a logger:
565 my $var_log = Log::Contextual::SimpleLogger->new({
566 levels => [qw(trace debug info warn error fatal)],
567 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
569 my $warn_faker = sub {
570 my ($package, $args) = @_;
571 @caller_info = caller($args->{caller_level});
574 set_logger($warn_faker);
575 log_debug { 'test' };
577 The following is an example that uses the information passed to the logger
578 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
579 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
580 logger and lastly the logger for the C<A2> package to C<$l2>.
582 Note that it increases the caller level as it dispatches based on where
583 the caller of the log function, not the log function itself.
585 my $complex_dispatcher = do {
597 A2 => { -logger => $l2 },
601 my ( $package, $info ) = @_;
603 my $logger = $registry{'-logger'};
604 if (my $r = $registry{$package}) {
605 $logger = $r->{'-logger'} if $r->{'-logger'};
606 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
607 $sub =~ s/^\Q$package\E:://g;
608 $logger = $r->{$sub} if $r->{$sub};
614 set_logger $complex_dispatcher;
616 =head1 LOGGER INTERFACE
618 Because this module is ultimately pretty looking glue (glittery?) with the
619 awesome benefit of the Contextual part, users will often want to make their
620 favorite logger work with it. The following are the methods that should be
621 implemented in the logger:
636 The first six merely need to return true if that level is enabled. The latter
637 six take the results of whatever the user returned from their coderef and log
638 them. For a basic example see L<Log::Contextual::SimpleLogger>.
642 In between the loggers and the log functions is a log router that is responsible for
643 finding a logger to handle the log event and passing the log information to the
644 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
646 C<Log::Contextual> and packages that extend it will by default share a router singleton that
647 implements the with_logger() and set_logger() functions and also respects the -logger,
648 -package_logger, and -default_logger import options with their associated default value
649 functions. The router singleton is available as the return value of the router() function. Users
650 of Log::Contextual may overload router() to return instances of custom log routers that
651 could for example work with loggers that use a different interface.
655 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
659 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
663 mst - Matt S. Trout <mst@shadowcat.co.uk>
667 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
672 This library is free software and may be distributed under the same terms as