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