e438ef0131c4bbd3bbb4d38b0b6645929116c85d
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
1 package Log::Contextual;
2
3 use strict;
4 use warnings;
5
6 our $VERSION = '0.006000';
7 $VERSION = eval $VERSION
8   if $VERSION =~ /_/;    # numify for warning-free dev releases
9
10 my @levels = qw(debug trace warn info error fatal);
11
12 use Exporter::Declare;
13 use Exporter::Declare::Export::Generator;
14 use Data::Dumper::Concise;
15 use Scalar::Util 'blessed';
16
17 my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
18
19 my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
20
21 eval {
22    require Log::Log4perl;
23    die if $Log::Log4perl::VERSION < 1.29;
24    Log::Log4perl->wrapper_register(__PACKAGE__)
25 };
26
27 # ____ is because tags must have at least one export and we don't want to
28 # export anything but the levels selected
29 sub ____ { }
30
31 exports('____', @dlog, @log, qw( set_logger with_logger ));
32
33 export_tag dlog => ('____');
34 export_tag log  => ('____');
35 import_arguments qw(logger package_logger default_logger);
36
37 sub router {
38    our $Router_Instance ||= do {
39       require Log::Contextual::Router;
40       Log::Contextual::Router->new
41      }
42 }
43
44 sub default_import {
45    my ($class) = shift;
46
47    die 'Log::Contextual does not have a default import list';
48
49    ()
50 }
51
52 sub arg_logger         { $_[1] }
53 sub arg_levels         { $_[1] || [qw(debug trace warn info error fatal)] }
54 sub arg_package_logger { $_[1] }
55 sub arg_default_logger { $_[1] }
56
57 sub before_import {
58    my ($class, $importer, $spec) = @_;
59    my $router      = $class->router;
60    my $exports     = $spec->exports;
61    my %router_args = (
62       exporter  => $class,
63       target    => $importer,
64       arguments => $spec->argument_info
65    );
66
67    my @tags = $class->default_import($spec)
68      if $spec->config->{default};
69
70    for (@tags) {
71       die "only tags are supported for defaults at this time"
72         unless $_ =~ /^:(.*)$/;
73
74       $spec->config->{$1} = 1;
75    }
76
77    $router->before_import(%router_args);
78
79    if ($exports->{'&set_logger'}) {
80       die ref($router) . " does not support set_logger()"
81         unless $router->does('Log::Contextual::Role::Router::SetLogger');
82
83       $spec->add_export('&set_logger', sub { $router->set_logger(@_) })
84    }
85
86    if ($exports->{'&with_logger'}) {
87       die ref($router) . " does not support with_logger()"
88         unless $router->does('Log::Contextual::Role::Router::WithLogger');
89
90       $spec->add_export('&with_logger', sub { $router->with_logger(@_) })
91    }
92
93    my @levels = @{$class->arg_levels($spec->config->{levels})};
94    for my $level (@levels) {
95       if ($spec->config->{log} || $exports->{"&log_$level"}) {
96          $spec->add_export(
97             "&log_$level",
98             sub (&@) {
99                my ($code, @args) = @_;
100                $router->handle_log_request(
101                   exporter       => $class,
102                   caller_package => scalar(caller),
103                   caller_level   => 1,
104                   message_level  => $level,
105                   message_sub    => $code,
106                   message_args   => \@args,
107                );
108                return @args;
109             });
110       }
111       if ($spec->config->{log} || $exports->{"&logS_$level"}) {
112          $spec->add_export(
113             "&logS_$level",
114             sub (&@) {
115                my ($code, @args) = @_;
116                $router->handle_log_request(
117                   exporter       => $class,
118                   caller_package => scalar(caller),
119                   caller_level   => 1,
120                   message_level  => $level,
121                   message_sub    => $code,
122                   message_args   => \@args,
123                );
124                return $args[0];
125             });
126       }
127       if ($spec->config->{dlog} || $exports->{"&Dlog_$level"}) {
128          $spec->add_export(
129             "&Dlog_$level",
130             sub (&@) {
131                my ($code, @args) = @_;
132                my $wrapped = sub {
133                   local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
134                   &$code;
135                };
136                $router->handle_log_request(
137                   exporter       => $class,
138                   caller_package => scalar(caller),
139                   caller_level   => 1,
140                   message_level  => $level,
141                   message_sub    => $wrapped,
142                   message_args   => \@args,
143                );
144                return @args;
145             });
146       }
147       if ($spec->config->{dlog} || $exports->{"&DlogS_$level"}) {
148          $spec->add_export(
149             "&DlogS_$level",
150             sub (&$) {
151                my ($code, $ref) = @_;
152                my $wrapped = sub {
153                   local $_ = Data::Dumper::Concise::Dumper($_[0]);
154                   &$code;
155                };
156                $router->handle_log_request(
157                   exporter       => $class,
158                   caller_package => scalar(caller),
159                   caller_level   => 1,
160                   message_level  => $level,
161                   message_sub    => $wrapped,
162                   message_args   => [$ref],
163                );
164                return $ref;
165             });
166       }
167    }
168 }
169
170 sub after_import {
171    my ($class, $importer, $spec) = @_;
172    my %router_args = (
173       exporter  => $class,
174       target    => $importer,
175       arguments => $spec->argument_info
176    );
177    $class->router->after_import(%router_args);
178 }
179
180 for (qw(set with)) {
181    no strict 'refs';
182    my $sub = "${_}_logger";
183    *{"Log::Contextual::$sub"} = sub {
184       die "$sub is no longer a direct sub in Log::Contextual.  "
185         . 'Note that this feature was never tested nor documented.  '
186         . "Please fix your code to import $sub instead of trying to use it directly"
187      }
188 }
189
190 1;
191
192 __END__
193
194 =head1 NAME
195
196 Log::Contextual - Simple logging interface with a contextual log
197
198 =head1 SYNOPSIS
199
200  use Log::Contextual qw( :log :dlog set_logger with_logger );
201  use Log::Contextual::SimpleLogger;
202  use Log::Log4perl ':easy';
203  Log::Log4perl->easy_init($DEBUG);
204
205  my $logger  = Log::Log4perl->get_logger;
206
207  set_logger $logger;
208
209  log_debug { 'program started' };
210
211  sub foo {
212
213    my $minilogger = Log::Contextual::SimpleLogger->new({
214      levels => [qw( trace debug )]
215    });
216
217    my @args = @_;
218
219    with_logger $minilogger => sub {
220      log_trace { 'foo entered' };
221      my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args;
222      # ...
223      log_trace { 'foo left' };
224    };
225  }
226
227  foo();
228
229 Beginning with version 1.008 L<Log::Dispatchouli> also works out of the box
230 with C<Log::Contextual>:
231
232  use Log::Contextual qw( :log :dlog set_logger );
233  use Log::Dispatchouli;
234  my $ld = Log::Dispatchouli->new({
235     ident     => 'slrtbrfst',
236     to_stderr => 1,
237     debug     => 1,
238  });
239
240  set_logger $ld;
241
242  log_debug { 'program started' };
243
244 =head1 DESCRIPTION
245
246 Major benefits:
247
248 =over 2
249
250 =item * Efficient
251
252 The logging functions take blocks, so if a log level is disabled, the
253 block will not run:
254
255  # the following won't run if debug is off
256  log_debug { "the new count in the database is " . $rs->count };
257
258 Similarly, the C<D> prefixed methods only C<Dumper> the input if the level is
259 enabled.
260
261 =item * Handy
262
263 The logging functions return their arguments, so you can stick them in
264 the middle of expressions:
265
266  for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... }
267
268 =item * Generic
269
270 C<Log::Contextual> is an interface for all major loggers.  If you log through
271 C<Log::Contextual> you will be able to swap underlying loggers later.
272
273 =item * Powerful
274
275 C<Log::Contextual> chooses which logger to use based on L<< user defined C<CodeRef>s|/LOGGER CODEREF >>.
276 Normally you don't need to know this, but you can take advantage of it when you
277 need to later
278
279 =item * Scalable
280
281 If you just want to add logging to your extremely basic application, start with
282 L<Log::Contextual::SimpleLogger> and then as your needs grow you can switch to
283 L<Log::Dispatchouli> or L<Log::Dispatch> or L<Log::Log4perl> or whatever else.
284
285 =back
286
287 This module is a simple interface to extensible logging.  It exists to
288 abstract your logging interface so that logging is as painless as possible,
289 while still allowing you to switch from one logger to another.
290
291 It is bundled with a really basic logger, L<Log::Contextual::SimpleLogger>,
292 but in general you should use a real logger instead of that.  For something
293 more serious but not overly complicated, try L<Log::Dispatchouli> (see
294 L</SYNOPSIS> for example.)
295
296 =head1 A WORK IN PROGRESS
297
298 This module is certainly not complete, but we will not break the interface
299 lightly, so I would say it's safe to use in production code.  The main result
300 from that at this point is that doing:
301
302  use Log::Contextual;
303
304 will die as we do not yet know what the defaults should be.  If it turns out
305 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
306 probably make C<:log> the default.  But only time and usage will tell.
307
308 =head1 IMPORT OPTIONS
309
310 See L</SETTING DEFAULT IMPORT OPTIONS> for information on setting these project
311 wide.
312
313 =head2 -logger
314
315 When you import this module you may use C<-logger> as a shortcut for
316 L</set_logger>, for example:
317
318  use Log::Contextual::SimpleLogger;
319  use Log::Contextual qw( :dlog ),
320    -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
321
322 sometimes you might want to have the logger handy for other stuff, in which
323 case you might try something like the following:
324
325  my $var_log;
326  BEGIN { $var_log = VarLogger->new }
327  use Log::Contextual qw( :dlog ), -logger => $var_log;
328
329 =head2 -levels
330
331 The C<-levels> import option allows you to define exactly which levels your
332 logger supports.  So the default,
333 C<< [qw(debug trace warn info error fatal)] >>, works great for
334 L<Log::Log4perl>, but it doesn't support the levels for L<Log::Dispatch>.  But
335 supporting those levels is as easy as doing
336
337  use Log::Contextual
338    -levels => [qw( debug info notice warning error critical alert emergency )];
339
340 =head2 -package_logger
341
342 The C<-package_logger> import option is similar to the C<-logger> import option
343 except C<-package_logger> sets the logger for the current package.
344
345 Unlike L</-default_logger>, C<-package_logger> cannot be overridden with
346 L</set_logger>.
347
348  package My::Package;
349  use Log::Contextual::SimpleLogger;
350  use Log::Contextual qw( :log ),
351    -package_logger => Log::Contextual::WarnLogger->new({
352       env_prefix => 'MY_PACKAGE'
353    });
354
355 If you are interested in using this package for a module you are putting on
356 CPAN we recommend L<Log::Contextual::WarnLogger> for your package logger.
357
358 =head2 -default_logger
359
360 The C<-default_logger> import option is similar to the C<-logger> import option
361 except C<-default_logger> sets the B<default> logger for the current package.
362
363 Basically it sets the logger to be used if C<set_logger> is never called; so
364
365  package My::Package;
366  use Log::Contextual::SimpleLogger;
367  use Log::Contextual qw( :log ),
368    -default_logger => Log::Contextual::WarnLogger->new({
369       env_prefix => 'MY_PACKAGE'
370    });
371
372 =head1 SETTING DEFAULT IMPORT OPTIONS
373
374 Eventually you will get tired of writing the following in every single one of
375 your packages:
376
377  use Log::Log4perl;
378  use Log::Log4perl ':easy';
379  BEGIN { Log::Log4perl->easy_init($DEBUG) }
380
381  use Log::Contextual -logger => Log::Log4perl->get_logger;
382
383 You can set any of the import options for your whole project if you define your
384 own C<Log::Contextual> subclass as follows:
385
386  package MyApp::Log::Contextual;
387
388  use base 'Log::Contextual';
389
390  use Log::Log4perl ':easy';
391  Log::Log4perl->easy_init($DEBUG)
392
393  sub arg_default_logger { $_[1] || Log::Log4perl->get_logger }
394  sub arg_levels { [qw(debug trace warn info error fatal custom_level)] }
395  sub default_import { ':log' }
396
397  # or maybe instead of default_logger
398  sub arg_package_logger { $_[1] }
399
400  # and almost definitely not this, which is only here for completeness
401  sub arg_logger { $_[1] }
402
403 Note the C<< $_[1] || >> in C<arg_default_logger>.  All of these methods are
404 passed the values passed in from the arguments to the subclass, so you can
405 either throw them away, honor them, die on usage, or whatever.  To be clear,
406 if you define your subclass, and someone uses it as follows:
407
408  use MyApp::Log::Contextual -default_logger => $foo,
409                             -levels => [qw(bar baz biff)];
410
411 Your C<arg_default_logger> method will get C<$foo> and your C<arg_levels>
412 will get C<[qw(bar baz biff)]>;
413
414 Additionally, the C<default_import> method is what happens if a user tries to
415 use your subclass with no arguments.  The default just dies, but if you'd like
416 to change the default to import a tag merely return the tags you'd like to
417 import.  So the following will all work:
418
419  sub default_import { ':log' }
420
421  sub default_import { ':dlog' }
422
423  sub default_import { qw(:dlog :log ) }
424
425 See L<Log::Contextual::Easy::Default> for an example of a subclass of
426 C<Log::Contextual> that makes use of default import options.
427
428 =head1 FUNCTIONS
429
430 =head2 set_logger
431
432  my $logger = WarnLogger->new;
433  set_logger $logger;
434
435 Arguments: L</LOGGER CODEREF>
436
437 C<set_logger> will just set the current logger to whatever you pass it.  It
438 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
439 C<CodeRef> for you.  C<set_logger> is really meant only to be called from a
440 top-level script.  To avoid foot-shooting the function will warn if you call it
441 more than once.
442
443 =head2 with_logger
444
445  my $logger = WarnLogger->new;
446  with_logger $logger => sub {
447     if (1 == 0) {
448        log_fatal { 'Non Logical Universe Detected' };
449     } else {
450        log_info  { 'All is good' };
451     }
452  };
453
454 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
455
456 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
457 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
458 C<CodeRef> if needed.
459
460 =head2 log_$level
461
462 Import Tag: C<:log>
463
464 Arguments: C<CodeRef $returning_message, @args>
465
466 C<log_$level> functions all work the same except that a different method
467 is called on the underlying C<$logger> object.  The basic pattern is:
468
469  sub log_$level (&@) {
470    if ($logger->is_$level) {
471      $logger->$level(shift->(@_));
472    }
473    @_
474  }
475
476 Note that the function returns it's arguments.  This can be used in a number of
477 ways, but often it's convenient just for partial inspection of passthrough data
478
479  my @friends = log_trace {
480    'friends list being generated, data from first friend: ' .
481      Dumper($_[0]->TO_JSON)
482  } generate_friend_list();
483
484 If you want complete inspection of passthrough data, take a look at the
485 L</Dlog_$level> functions.
486
487 Which functions are exported depends on what was passed to L</-levels>.  The
488 default (no C<-levels> option passed) would export:
489
490 =over 2
491
492 =item log_trace
493
494 =item log_debug
495
496 =item log_info
497
498 =item log_warn
499
500 =item log_error
501
502 =item log_fatal
503
504 =back
505
506 =head2 logS_$level
507
508 Import Tag: C<:log>
509
510 Arguments: C<CodeRef $returning_message, Item $arg>
511
512 This is really just a special case of the L</log_$level> functions.  It forces
513 scalar context when that is what you need.  Other than that it works exactly
514 same:
515
516  my $friend = logS_trace {
517    'I only have one friend: ' .  Dumper($_[0]->TO_JSON)
518  } friend();
519
520 See also: L</DlogS_$level>.
521
522 =head2 Dlog_$level
523
524 Import Tag: C<:dlog>
525
526 Arguments: C<CodeRef $returning_message, @args>
527
528 All of the following six functions work the same as their L</log_$level>
529 brethren, except they return what is passed into them and put the stringified
530 (with L<Data::Dumper::Concise>) version of their args into C<$_>.  This means
531 you can do cool things like the following:
532
533  my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
534
535 and the output might look something like:
536
537  names: "fREW"
538  "fRIOUX"
539  "fROOH"
540  "fRUE"
541  "fiSMBoC"
542
543 Which functions are exported depends on what was passed to L</-levels>.  The
544 default (no C<-levels> option passed) would export:
545
546 =over 2
547
548 =item Dlog_trace
549
550 =item Dlog_debug
551
552 =item Dlog_info
553
554 =item Dlog_warn
555
556 =item Dlog_error
557
558 =item Dlog_fatal
559
560 =back
561
562 =head2 DlogS_$level
563
564 Import Tag: C<:dlog>
565
566 Arguments: C<CodeRef $returning_message, Item $arg>
567
568 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
569 They only take a single scalar after the C<$returning_message> instead of
570 slurping up (and also setting C<wantarray>) all the C<@args>
571
572  my $pals_rs = DlogS_debug { "pals resultset: $_" }
573    $schema->resultset('Pals')->search({ perlers => 1 });
574
575 =head1 LOGGER CODEREF
576
577 Anywhere a logger object can be passed, a coderef is accepted.  This is so
578 that the user can use different logger objects based on runtime information.
579 The logger coderef is passed the package of the caller the caller level the
580 coderef needs to use if it wants more caller information.  The latter is in
581 a hashref to allow for more options in the future.
582
583 Here is a basic example of a logger that exploits C<caller> to reproduce the
584 output of C<warn> with a logger:
585
586  my @caller_info;
587  my $var_log = Log::Contextual::SimpleLogger->new({
588     levels  => [qw(trace debug info warn error fatal)],
589     coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
590  });
591  my $warn_faker = sub {
592     my ($package, $args) = @_;
593     @caller_info = caller($args->{caller_level});
594     $var_log
595  };
596  set_logger($warn_faker);
597  log_debug { 'test' };
598
599 The following is an example that uses the information passed to the logger
600 coderef.  It sets the global logger to C<$l3>, the logger for the C<A1>
601 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
602 logger and lastly the logger for the C<A2> package to C<$l2>.
603
604 Note that it increases the caller level as it dispatches based on where
605 the caller of the log function, not the log function itself.
606
607  my $complex_dispatcher = do {
608
609     my $l1 = ...;
610     my $l2 = ...;
611     my $l3 = ...;
612
613     my %registry = (
614        -logger => $l3,
615        A1 => {
616           -logger => $l1,
617           lol     => $l2,
618        },
619        A2 => { -logger => $l2 },
620     );
621
622     sub {
623        my ( $package, $info ) = @_;
624
625        my $logger = $registry{'-logger'};
626        if (my $r = $registry{$package}) {
627           $logger = $r->{'-logger'} if $r->{'-logger'};
628           my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
629           $sub =~ s/^\Q$package\E:://g;
630           $logger = $r->{$sub} if $r->{$sub};
631        }
632        return $logger;
633     }
634  };
635
636  set_logger $complex_dispatcher;
637
638 =head1 LOGGER INTERFACE
639
640 Because this module is ultimately pretty looking glue (glittery?) with the
641 awesome benefit of the Contextual part, users will often want to make their
642 favorite logger work with it.  The following are the methods that should be
643 implemented in the logger:
644
645  is_trace
646  is_debug
647  is_info
648  is_warn
649  is_error
650  is_fatal
651  trace
652  debug
653  info
654  warn
655  error
656  fatal
657
658 The first six merely need to return true if that level is enabled.  The latter
659 six take the results of whatever the user returned from their coderef and log
660 them.  For a basic example see L<Log::Contextual::SimpleLogger>.
661
662 =head1 LOG ROUTING
663
664 In between the loggers and the log functions is a log router that is responsible for
665 finding a logger to handle the log event and passing the log information to the
666 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
667
668 C<Log::Contextual> and packages that extend it will by default share a router singleton that
669 implements the with_logger() and set_logger() functions and also respects the -logger,
670 -package_logger, and -default_logger import options with their associated default value
671 functions. The router singleton is available as the return value of the router() function. Users
672 of Log::Contextual may overload router() to return instances of custom log routers that
673 could for example work with loggers that use a different interface.
674
675 =head1 AUTHOR
676
677 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
678
679 =head1 CONTRIBUTORS
680
681 =encoding utf8
682
683 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
684
685 voj - Jakob Voß <voss@gbv.de>
686
687 =head1 DESIGNER
688
689 mst - Matt S. Trout <mst@shadowcat.co.uk>
690
691 =head1 COPYRIGHT
692
693 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
694 above.
695
696 =head1 LICENSE
697
698 This library is free software and may be distributed under the same terms as
699 Perl 5 itself.
700
701 =cut
702