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';
14 use Log::Contextual::Router;
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);
39 sub arg_router { return $_[1] if defined $_[1]; our $Router_Instance ||= Log::Contextual::Router->new }
40 sub arg_logger { $_[1] }
41 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
42 sub arg_package_logger { $_[1] }
43 sub arg_default_logger { $_[1] }
46 my ($class, $importer, $spec) = @_;
47 my $router = $class->arg_router;
49 die 'Log::Contextual does not have a default import list'
50 if $spec->config->{default};
52 $router->before_import(@_);
54 my @levels = @{$class->arg_levels($spec->config->{levels})};
55 for my $level (@levels) {
56 if ($spec->config->{log}) {
57 $spec->add_export("&log_$level", sub (&@) {
58 my ($code, @args) = @_;
59 $router->handle_log_request({
60 package => scalar(caller),
66 $spec->add_export("&logS_$level", sub (&@) {
67 my ($code, @args) = @_;
68 $router->handle_log_request({
69 package => scalar(caller),
76 if ($spec->config->{dlog}) {
77 $spec->add_export("&Dlog_$level", sub (&@) {
78 my ($code, @args) = @_;
80 local $_ = (@_?Data::Dumper::Concise::Dumper @_:'()');
83 $router->handle_log_request({
84 package => scalar(caller),
90 $spec->add_export("&DlogS_$level", sub (&$) {
91 my ($code, $ref) = @_;
93 local $_ = Data::Dumper::Concise::Dumper($_[0]);
96 $router->handle_log_request({
97 package => scalar(caller),
107 sub after_import { return arg_router()->after_import(@_) }
110 my $router = arg_router();
112 die ref($router) . " does not support set_logger()"
113 unless $router->does('Log::Contextual::Role::Router::SetLogger');
115 return $router->set_logger(@_);
119 my $router = arg_router();
121 die ref($router) . " does not support with_logger()"
122 unless $router->does('Log::Contextual::Role::Router::WithLogger');
124 return $router->with_logger(@_);
133 Log::Contextual - Simple logging interface with a contextual log
137 use Log::Contextual qw( :log :dlog set_logger with_logger );
138 use Log::Contextual::SimpleLogger;
139 use Log::Log4perl ':easy';
140 Log::Log4perl->easy_init($DEBUG);
142 my $logger = Log::Log4perl->get_logger;
146 log_debug { 'program started' };
150 my $minilogger = Log::Contextual::SimpleLogger->new({
151 levels => [qw( trace debug )]
154 with_logger $minilogger => sub {
155 log_trace { 'foo entered' };
156 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
158 log_trace { 'foo left' };
164 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
165 with C<Log::Contextual>:
167 use Log::Contextual qw( :log :dlog set_logger );
168 use Log::Dispatchouli;
169 my $ld = Log::Dispatchouli->new({
170 ident => 'slrtbrfst',
177 log_debug { 'program started' };
187 The logging functions take blocks, so if a log level is disabled, the
190 # the following won't run if debug is off
191 log_debug { "the new count in the database is " . $rs->count };
193 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
198 The logging functions return their arguments, so you can stick them in
199 the middle of expressions:
201 for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
205 C<Log::Contextual> is an interface for all major loggers. If you log through
206 C<Log::Contextual> you will be able to swap underlying loggers later.
210 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
211 Normally you don't need to know this, but you can take advantage of it when you
216 If you just want to add logging to your extremely basic application, start with
217 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
218 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
222 This module is a simple interface to extensible logging. It exists to
223 abstract your logging interface so that logging is as painless as possible,
224 while still allowing you to switch from one logger to another.
226 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
227 but in general you should use a real logger instead of that. For something
228 more serious but not overly complicated, try L<Log::Dispatchouli> (see
229 L</SYNOPSIS> for example.)
231 =head1 A WORK IN PROGRESS
233 This module is certainly not complete, but we will not break the interface
234 lightly, so I would say it's safe to use in production code. The main result
235 from that at this point is that doing:
239 will die as we do not yet know what the defaults should be. If it turns out
240 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
241 probably make C<:log> the default. But only time and usage will tell.
243 =head1 IMPORT OPTIONS
245 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
250 When you import this module you may use C<-logger> as a shortcut for
251 L<set_logger>, for example:
253 use Log::Contextual::SimpleLogger;
254 use Log::Contextual qw( :dlog ),
255 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
257 sometimes you might want to have the logger handy for other stuff, in which
258 case you might try something like the following:
261 BEGIN { $var_log = VarLogger->new }
262 use Log::Contextual qw( :dlog ), -logger => $var_log;
266 The C<-levels> import option allows you to define exactly which levels your
267 logger supports. So the default,
268 C<< [qw(debug trace warn info error fatal)] >>, works great for
269 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
270 supporting those levels is as easy as doing
273 -levels => [qw( debug info notice warning error critical alert emergency )];
275 =head2 -package_logger
277 The C<-package_logger> import option is similar to the C<-logger> import option
278 except C<-package_logger> sets the the logger for the current package.
280 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
284 use Log::Contextual::SimpleLogger;
285 use Log::Contextual qw( :log ),
286 -package_logger => Log::Contextual::WarnLogger->new({
287 env_prefix => 'MY_PACKAGE'
290 If you are interested in using this package for a module you are putting on
291 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
293 =head2 -default_logger
295 The C<-default_logger> import option is similar to the C<-logger> import option
296 except C<-default_logger> sets the the B<default> logger for the current package.
298 Basically it sets the logger to be used if C<set_logger> is never called; so
301 use Log::Contextual::SimpleLogger;
302 use Log::Contextual qw( :log ),
303 -default_logger => Log::Contextual::WarnLogger->new({
304 env_prefix => 'MY_PACKAGE'
307 =head1 SETTING DEFAULT IMPORT OPTIONS
309 Eventually you will get tired of writing the following in every single one of
313 use Log::Log4perl ':easy';
314 BEGIN { Log::Log4perl->easy_init($DEBUG) }
316 use Log::Contextual -logger => Log::Log4perl->get_logger;
318 You can set any of the import options for your whole project if you define your
319 own C<Log::Contextual> subclass as follows:
321 package MyApp::Log::Contextual;
323 use base 'Log::Contextual';
325 use Log::Log4perl ':easy';
326 Log::Log4perl->easy_init($DEBUG)
328 sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
329 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
331 # or maybe instead of default_logger
332 sub arg_package_logger { $_[1] }
334 # and almost definitely not this, which is only here for completeness
335 sub arg_logger { $_[1] }
337 Note the C<< $_[1] || >> in C<arg_default_logger>. All of these methods are
338 passed the values passed in from the arguments to the subclass, so you can
339 either throw them away, honor them, die on usage, or whatever. To be clear,
340 if you define your subclass, and someone uses it as follows:
342 use MyApp::Log::Contextual -default_logger => $foo,
343 -levels => [qw(bar baz biff)];
345 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
346 will get C<[qw(bar baz biff)]>;
352 my $logger = WarnLogger->new;
355 Arguments: L</LOGGER CODEREF>
357 C<set_logger> will just set the current logger to whatever you pass it. It
358 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
359 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
360 top-level script. To avoid foot-shooting the function will warn if you call it
365 my $logger = WarnLogger->new;
366 with_logger $logger => sub {
368 log_fatal { 'Non Logical Universe Detected' };
370 log_info { 'All is good' };
374 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
376 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
377 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
378 C<CodeRef> if needed.
384 Arguments: C<CodeRef $returning_message, @args>
386 C<log_$level> functions all work the same except that a different method
387 is called on the underlying C<$logger> object. The basic pattern is:
389 sub log_$level (&@) {
390 if ($logger->is_$level) {
391 $logger->$level(shift->(@_));
396 Note that the function returns it's arguments. This can be used in a number of
397 ways, but often it's convenient just for partial inspection of passthrough data
399 my @friends = log_trace {
400 'friends list being generated, data from first friend: ' .
401 Dumper($_[0]->TO_JSON)
402 } generate_friend_list();
404 If you want complete inspection of passthrough data, take a look at the
405 L</Dlog_$level> functions.
407 Which functions are exported depends on what was passed to L</-levels>. The
408 default (no C<-levels> option passed) would export:
430 Arguments: C<CodeRef $returning_message, Item $arg>
432 This is really just a special case of the L</log_$level> functions. It forces
433 scalar context when that is what you need. Other than that it works exactly
436 my $friend = logS_trace {
437 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
440 See also: L</DlogS_$level>.
446 Arguments: C<CodeRef $returning_message, @args>
448 All of the following six functions work the same as their L</log_$level>
449 brethren, except they return what is passed into them and put the stringified
450 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
451 you can do cool things like the following:
453 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
455 and the output might look something like:
463 Which functions are exported depends on what was passed to L</-levels>. The
464 default (no C<-levels> option passed) would export:
486 Arguments: C<CodeRef $returning_message, Item $arg>
488 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
489 They only take a single scalar after the C<$returning_message> instead of
490 slurping up (and also setting C<wantarray>) all the C<@args>
492 my $pals_rs = DlogS_debug { "pals resultset: $_" }
493 $schema->resultset('Pals')->search({ perlers => 1 });
495 =head1 LOGGER CODEREF
497 Anywhere a logger object can be passed, a coderef is accepted. This is so
498 that the user can use different logger objects based on runtime information.
499 The logger coderef is passed the package of the caller the caller level the
500 coderef needs to use if it wants more caller information. The latter is in
501 a hashref to allow for more options in the future.
503 Here is a basic example of a logger that exploits C<caller> to reproduce the
504 output of C<warn> with a logger:
507 my $var_log = Log::Contextual::SimpleLogger->new({
508 levels => [qw(trace debug info warn error fatal)],
509 coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
511 my $warn_faker = sub {
512 my ($package, $args) = @_;
513 @caller_info = caller($args->{caller_level});
516 set_logger($warn_faker);
517 log_debug { 'test' };
519 The following is an example that uses the information passed to the logger
520 coderef. It sets the global logger to C<$l3>, the logger for the C<A1>
521 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
522 logger and lastly the logger for the C<A2> package to C<$l2>.
524 Note that it increases the caller level as it dispatches based on where
525 the caller of the log function, not the log function itself.
527 my $complex_dispatcher = do {
539 A2 => { -logger => $l2 },
543 my ( $package, $info ) = @_;
545 my $logger = $registry{'-logger'};
546 if (my $r = $registry{$package}) {
547 $logger = $r->{'-logger'} if $r->{'-logger'};
548 my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
549 $sub =~ s/^\Q$package\E:://g;
550 $logger = $r->{$sub} if $r->{$sub};
556 set_logger $complex_dispatcher;
558 =head1 LOGGER INTERFACE
560 Because this module is ultimately pretty looking glue (glittery?) with the
561 awesome benefit of the Contextual part, users will often want to make their
562 favorite logger work with it. The following are the methods that should be
563 implemented in the logger:
578 The first six merely need to return true if that level is enabled. The latter
579 six take the results of whatever the user returned from their coderef and log
580 them. For a basic example see L<Log::Contextual::SimpleLogger>.
584 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
588 mst - Matt S. Trout <mst@shadowcat.co.uk>
592 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
597 This library is free software and may be distributed under the same terms as