1 package Log::Contextual;
6 our $VERSION = '0.004100';
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 set_logger_for )
34 export_tag dlog => ('____');
35 export_tag log => ('____');
36 import_arguments qw(logger_for logger package_logger default_logger);
39 my ($class, $importer, $spec) = @_;
41 die 'Log::Contextual does not have a default import list'
42 if $spec->config->{default};
44 my @levels = @{$class->arg_levels($spec->config->{levels})};
45 for my $level (@levels) {
46 if ($spec->config->{log}) {
47 $spec->add_export("&log_$level", sub (&@) {
48 _do_log( $level => _get_logger( caller ), shift @_, @_)
50 $spec->add_export("&logS_$level", sub (&@) {
51 _do_logS( $level => _get_logger( caller ), $_[0], $_[1])
54 if ($spec->config->{dlog}) {
55 $spec->add_export("&Dlog_$level", sub (&@) {
56 my ($code, @args) = @_;
57 return _do_log( $level => _get_logger( caller ), sub {
58 local $_ = (@args?Data::Dumper::Concise::Dumper @args:'()');
62 $spec->add_export("&DlogS_$level", sub (&$) {
63 my ($code, $ref) = @_;
64 _do_logS( $level => _get_logger( caller ), sub {
65 local $_ = Data::Dumper::Concise::Dumper $ref;
73 sub arg_logger { $_[1] }
74 sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
75 sub arg_package_logger { $_[1] }
76 sub arg_default_logger { $_[1] }
77 sub arg_logger_for { $_[1] }
80 my ($class, $importer, $specs) = @_;
82 if (my $l = $class->arg_logger_for($specs->config->{logger_for})) {
83 set_logger_for($_, $l->{$_}) for keys %$l
86 if (my $l = $class->arg_logger($specs->config->{logger})) {
90 if (my $l = $class->arg_package_logger($specs->config->{package_logger})) {
91 _set_package_logger_for($importer, $l)
94 if (my $l = $class->arg_default_logger($specs->config->{default_logger})) {
95 _set_default_logger_for($importer, $l)
104 sub _set_default_logger_for {
106 warn "Setting default logger!";
109 my $tag_name = $logger;
111 $Named_Logger{$tag_name}
112 or die "no such named logger '$tag_name'!"
116 if(ref $logger ne 'CODE') {
117 die 'logger was not a CodeRef or a logger object. Please try again.'
118 unless blessed($logger);
119 $logger = do { my $l = $logger; sub { $l } }
121 $Default_Logger{$_[0]} = $logger
124 sub _set_package_logger_for {
127 my $tag_name = $logger;
129 $Named_Logger{$tag_name}
130 or die "no such named logger '$tag_name'!"
134 if(ref $logger ne 'CODE') {
135 die 'logger was not a CodeRef or a logger object. Please try again.'
136 unless blessed($logger);
137 $logger = do { my $l = $logger; sub { $l } }
139 $Package_Logger{$_[0]} = $logger
145 ($Package_Logger{$package} && $Package_Logger{$package}->($package)) ||
147 ($Default_Logger{$package} && $Default_Logger{$package}->($package)) ||
148 die q( no logger set! you can't try to log something without a logger! )
153 my ($tag,$logger,$really_override) = @_;
154 if(ref $logger ne 'CODE') {
155 die 'logger was not a CodeRef or a logger object. Please try again.'
156 unless blessed($logger);
158 $logger = do { my $l = $logger; sub { $l } }
161 warn "set_logger_for (or -logger_for) called more than once for this ($tag) tag! " .
162 'this is generally a bad idea!'
163 if $Named_Logger{$tag} && !$really_override;
164 $Named_Logger{$tag} = $logger
170 my $tag_name = $logger;
171 $logger = $Named_Logger{$logger}
172 or die "no such named logger '$tag_name'!"
175 if(ref $logger ne 'CODE') {
176 die 'logger was not a CodeRef or a logger object. Please try again.'
177 unless blessed($logger);
178 $logger = do { my $l = $logger; sub { $l } }
181 warn 'set_logger (or -logger) called more than once! This is a bad idea!'
183 $Get_Logger = $logger;
190 my $tag_name = $logger;
191 $logger = $Named_Logger{$logger}
192 or die "no such named logger '$tag_name'!"
195 if(ref $logger ne 'CODE') {
196 die 'logger was not a CodeRef or a logger object. Please try again.'
197 unless blessed($logger);
198 $logger = do { my $l = $logger; sub { $l } }
200 local $Get_Logger = $logger;
210 $logger->$level($code->(@_))
211 if $logger->${\"is_$level"};
221 $logger->$level($code->($value))
222 if $logger->${\"is_$level"};
232 Log::Contextual - Simple logging interface with a contextual log
236 use Log::Contextual qw( :log :dlog set_logger with_logger );
237 use Log::Contextual::SimpleLogger;
238 use Log::Log4perl ':easy';
239 Log::Log4perl->easy_init($DEBUG);
242 my $logger = Log::Log4perl->get_logger;
246 log_debug { 'program started' };
250 my $minilogger = Log::Contextual::SimpleLogger->new({
251 levels => [qw( trace debug )]
254 with_logger $minilogger => sub {
255 log_trace { 'foo entered' };
256 my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
258 log_trace { 'foo left' };
264 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
265 with C<Log::Contextual>:
267 use Log::Contextual qw( :log :dlog set_logger );
268 use Log::Dispatchouli;
269 my $ld = Log::Dispatchouli->new({
270 ident => 'slrtbrfst',
277 log_debug { 'program started' };
281 This module is a simple interface to extensible logging. It is bundled with a
282 really basic logger, L<Log::Contextual::SimpleLogger>, but in general you
283 should use a real logger instead of that. For something more serious but not
284 overly complicated, try L<Log::Dispatchouli> (see L</SYNOPSIS> for example.)
286 The reason for this module is to abstract your logging interface so that
287 logging is as painless as possible, while still allowing you to switch from one
290 =head1 A WORK IN PROGRESS
292 This module is certainly not complete, but we will not break the interface
293 lightly, so I would say it's safe to use in production code. The main result
294 from that at this point is that doing:
298 will die as we do not yet know what the defaults should be. If it turns out
299 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
300 probably make C<:log> the default. But only time and usage will tell.
302 =head1 IMPORT OPTIONS
304 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
309 When you import this module you may use C<-logger> as a shortcut for
310 L<set_logger>, for example:
312 use Log::Contextual::SimpleLogger;
313 use Log::Contextual qw( :dlog ),
314 -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
316 sometimes you might want to have the logger handy for other stuff, in which
317 case you might try something like the following:
320 BEGIN { $var_log = VarLogger->new }
321 use Log::Contextual qw( :dlog ), -logger => $var_log;
325 The C<-levels> import option allows you to define exactly which levels your
326 logger supports. So the default,
327 C<< [qw(debug trace warn info error fatal)] >>, works great for
328 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>. But
329 supporting those levels is as easy as doing
332 -levels => [qw( debug info notice warning error critical alert emergency )];
334 =head2 -package_logger
336 The C<-package_logger> import option is similar to the C<-logger> import option
337 except C<-package_logger> sets the the logger for the current package.
339 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
343 use Log::Contextual::SimpleLogger;
344 use Log::Contextual qw( :log ),
345 -package_logger => Log::Contextual::WarnLogger->new({
346 env_prefix => 'MY_PACKAGE'
349 If you are interested in using this package for a module you are putting on
350 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
352 =head2 -default_logger
354 The C<-default_logger> import option is similar to the C<-logger> import option
355 except C<-default_logger> sets the the B<default> logger for the current package.
357 Basically it sets the logger to be used if C<set_logger> is never called; so
360 use Log::Contextual::SimpleLogger;
361 use Log::Contextual qw( :log ),
362 -default_logger => Log::Contextual::WarnLogger->new({
363 env_prefix => 'MY_PACKAGE'
366 =head1 SETTING DEFAULT IMPORT OPTIONS
368 Eventually you will get tired of writing the following in every single one of
372 use Log::Log4perl ':easy';
373 BEGIN { Log::Log4perl->easy_init($DEBUG) }
375 use Log::Contextual -logger => Log::Log4perl->get_logger;
377 You can set any of the import options for your whole project if you define your
378 own C<Log::Contextual> subclass as follows:
380 package MyApp::Log::Contextual;
382 use base 'Log::Contextual';
384 use Log::Log4perl ':easy';
385 Log::Log4perl->easy_init($DEBUG)
387 sub arg_logger { $_[1] || Log::Log4perl->get_logger }
388 sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
390 # and *maybe* even these:
391 sub arg_package_logger { $_[1] }
392 sub arg_default_logger { $_[1] }
394 Note the C<< $_[1] || >> in C<arg_logger>. All of these methods are passed the
395 values passed in from the arguments to the subclass, so you can either throw
396 them away, honor them, die on usage, or whatever. To be clear, if you define
397 your subclass, and someone uses it as follows:
399 use MyApp::Log::Contextual -logger => $foo, -levels => [qw(bar baz biff)];
401 Your C<arg_logger> method will get C<$foo> and your C<arg_levels>
402 will get C<[qw(bar baz biff)]>;
408 my $logger = WarnLogger->new;
411 Arguments: C<Ref|CodeRef $returning_logger>
413 C<set_logger> will just set the current logger to whatever you pass it. It
414 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
415 C<CodeRef> for you. C<set_logger> is really meant only to be called from a
416 top-level script. To avoid foot-shooting the function will warn if you call it
421 my $logger = WarnLogger->new;
422 with_logger $logger => sub {
424 log_fatal { 'Non Logical Universe Detected' };
426 log_info { 'All is good' };
430 Arguments: C<Ref|CodeRef $returning_logger, CodeRef $to_execute>
432 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
433 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
434 C<CodeRef> if needed.
440 Arguments: C<CodeRef $returning_message, @args>
442 All of the following six functions work the same except that a different method
443 is called on the underlying C<$logger> object. The basic pattern is:
445 sub log_$level (&@) {
446 if ($logger->is_$level) {
447 $logger->$level(shift->(@_));
452 Note that the function returns it's arguments. This can be used in a number of
453 ways, but often it's convenient just for partial inspection of passthrough data
455 my @friends = log_trace {
456 'friends list being generated, data from first friend: ' .
457 Dumper($_[0]->TO_JSON)
458 } generate_friend_list();
460 If you want complete inspection of passthrough data, take a look at the
461 L</Dlog_$level> functions.
465 log_trace { 'entered method foo with args ' join q{,}, @args };
469 log_debug { 'entered method foo' };
473 log_info { 'started process foo' };
477 log_warn { 'possible misconfiguration at line 10' };
481 log_error { 'non-numeric user input!' };
485 log_fatal { '1 is never equal to 0!' };
491 Arguments: C<CodeRef $returning_message, Item $arg>
493 This is really just a special case of the L</log_$level> functions. It forces
494 scalar context when that is what you need. Other than that it works exactly
497 my $friend = logS_trace {
498 'I only have one friend: ' . Dumper($_[0]->TO_JSON)
501 See also: L</DlogS_$level>.
507 Arguments: C<CodeRef $returning_message, @args>
509 All of the following six functions work the same as their L</log_$level>
510 brethren, except they return what is passed into them and put the stringified
511 (with L<Data::Dumper::Concise>) version of their args into C<$_>. This means
512 you can do cool things like the following:
514 my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
516 and the output might look something like:
526 my ($foo, $bar) = Dlog_trace { "entered method foo with args: $_" } @_;
530 Dlog_debug { "random data structure: $_" } { foo => $bar };
534 return Dlog_info { "html from method returned: $_" } "<html>...</html>";
538 Dlog_warn { "probably invalid value: $_" } $foo;
542 Dlog_error { "non-numeric user input! ($_)" } $port;
546 Dlog_fatal { '1 is never equal to 0!' } 'ZOMG ZOMG' if 1 == 0;
552 Arguments: C<CodeRef $returning_message, Item $arg>
554 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
555 They only take a single scalar after the C<$returning_message> instead of
556 slurping up (and also setting C<wantarray>) all the C<@args>
558 my $pals_rs = DlogS_debug { "pals resultset: $_" }
559 $schema->resultset('Pals')->search({ perlers => 1 });
561 =head1 LOGGER INTERFACE
563 Because this module is ultimately pretty looking glue (glittery?) with the
564 awesome benefit of the Contextual part, users will often want to make their
565 favorite logger work with it. The following are the methods that should be
566 implemented in the logger:
581 The first six merely need to return true if that level is enabled. The latter
582 six take the results of whatever the user returned from their coderef and log
583 them. For a basic example see L<Log::Contextual::SimpleLogger>.
587 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
591 mst - Matt S. Trout <mst@shadowcat.co.uk>
595 Copyright (c) 2010 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
600 This library is free software and may be distributed under the same terms as