0195e690e8686f0944701977b3e12016a599ba7a
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
1 package Log::Contextual;
2
3 use strict;
4 use warnings;
5
6 our $VERSION = '0.005005';
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 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 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 See L<Log::Contextual::Easy::Default> for an example of a subclass of
428 C<Log::Contextual> that makes use of default import options.
429
430 =head1 FUNCTIONS
431
432 =head2 set_logger
433
434  my $logger = WarnLogger->new;
435  set_logger $logger;
436
437 Arguments: L</LOGGER CODEREF>
438
439 C<set_logger> will just set the current logger to whatever you pass it.  It
440 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
441 C<CodeRef> for you.  C<set_logger> is really meant only to be called from a
442 top-level script.  To avoid foot-shooting the function will warn if you call it
443 more than once.
444
445 =head2 with_logger
446
447  my $logger = WarnLogger->new;
448  with_logger $logger => sub {
449     if (1 == 0) {
450        log_fatal { 'Non Logical Universe Detected' };
451     } else {
452        log_info  { 'All is good' };
453     }
454  };
455
456 Arguments: L</LOGGER CODEREF>, C<CodeRef $to_execute>
457
458 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
459 As with L</set_logger>, C<with_logger> will wrap C<$returning_logger> with a
460 C<CodeRef> if needed.
461
462 =head2 log_$level
463
464 Import Tag: C<:log>
465
466 Arguments: C<CodeRef $returning_message, @args>
467
468 C<log_$level> functions all work the same except that a different method
469 is called on the underlying C<$logger> object.  The basic pattern is:
470
471  sub log_$level (&@) {
472    if ($logger->is_$level) {
473      $logger->$level(shift->(@_));
474    }
475    @_
476  }
477
478 Note that the function returns it's arguments.  This can be used in a number of
479 ways, but often it's convenient just for partial inspection of passthrough data
480
481  my @friends = log_trace {
482    'friends list being generated, data from first friend: ' .
483      Dumper($_[0]->TO_JSON)
484  } generate_friend_list();
485
486 If you want complete inspection of passthrough data, take a look at the
487 L</Dlog_$level> functions.
488
489 Which functions are exported depends on what was passed to L</-levels>.  The
490 default (no C<-levels> option passed) would export:
491
492 =over 2
493
494 =item log_trace
495
496 =item log_debug
497
498 =item log_info
499
500 =item log_warn
501
502 =item log_error
503
504 =item log_fatal
505
506 =back
507
508 =head2 logS_$level
509
510 Import Tag: C<:log>
511
512 Arguments: C<CodeRef $returning_message, Item $arg>
513
514 This is really just a special case of the L</log_$level> functions.  It forces
515 scalar context when that is what you need.  Other than that it works exactly
516 same:
517
518  my $friend = logS_trace {
519    'I only have one friend: ' .  Dumper($_[0]->TO_JSON)
520  } friend();
521
522 See also: L</DlogS_$level>.
523
524 =head2 Dlog_$level
525
526 Import Tag: C<:dlog>
527
528 Arguments: C<CodeRef $returning_message, @args>
529
530 All of the following six functions work the same as their L</log_$level>
531 brethren, except they return what is passed into them and put the stringified
532 (with L<Data::Dumper::Concise>) version of their args into C<$_>.  This means
533 you can do cool things like the following:
534
535  my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
536
537 and the output might look something like:
538
539  names: "fREW"
540  "fRIOUX"
541  "fROOH"
542  "fRUE"
543  "fiSMBoC"
544
545 Which functions are exported depends on what was passed to L</-levels>.  The
546 default (no C<-levels> option passed) would export:
547
548 =over 2
549
550 =item Dlog_trace
551
552 =item Dlog_debug
553
554 =item Dlog_info
555
556 =item Dlog_warn
557
558 =item Dlog_error
559
560 =item Dlog_fatal
561
562 =back
563
564 =head2 DlogS_$level
565
566 Import Tag: C<:dlog>
567
568 Arguments: C<CodeRef $returning_message, Item $arg>
569
570 Like L</logS_$level>, these functions are a special case of L</Dlog_$level>.
571 They only take a single scalar after the C<$returning_message> instead of
572 slurping up (and also setting C<wantarray>) all the C<@args>
573
574  my $pals_rs = DlogS_debug { "pals resultset: $_" }
575    $schema->resultset('Pals')->search({ perlers => 1 });
576
577 =head1 LOGGER CODEREF
578
579 Anywhere a logger object can be passed, a coderef is accepted.  This is so
580 that the user can use different logger objects based on runtime information.
581 The logger coderef is passed the package of the caller the caller level the
582 coderef needs to use if it wants more caller information.  The latter is in
583 a hashref to allow for more options in the future.
584
585 Here is a basic example of a logger that exploits C<caller> to reproduce the
586 output of C<warn> with a logger:
587
588  my @caller_info;
589  my $var_log = Log::Contextual::SimpleLogger->new({
590     levels  => [qw(trace debug info warn error fatal)],
591     coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" }
592  });
593  my $warn_faker = sub {
594     my ($package, $args) = @_;
595     @caller_info = caller($args->{caller_level});
596     $var_log
597  };
598  set_logger($warn_faker);
599  log_debug { 'test' };
600
601 The following is an example that uses the information passed to the logger
602 coderef.  It sets the global logger to C<$l3>, the logger for the C<A1>
603 package to C<$l1>, except the C<lol> method in C<A1> which uses the C<$l2>
604 logger and lastly the logger for the C<A2> package to C<$l2>.
605
606 Note that it increases the caller level as it dispatches based on where
607 the caller of the log function, not the log function itself.
608
609  my $complex_dispatcher = do {
610
611     my $l1 = ...;
612     my $l2 = ...;
613     my $l3 = ...;
614
615     my %registry = (
616        -logger => $l3,
617        A1 => {
618           -logger => $l1,
619           lol     => $l2,
620        },
621        A2 => { -logger => $l2 },
622     );
623
624     sub {
625        my ( $package, $info ) = @_;
626
627        my $logger = $registry{'-logger'};
628        if (my $r = $registry{$package}) {
629           $logger = $r->{'-logger'} if $r->{'-logger'};
630           my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1);
631           $sub =~ s/^\Q$package\E:://g;
632           $logger = $r->{$sub} if $r->{$sub};
633        }
634        return $logger;
635     }
636  };
637
638  set_logger $complex_dispatcher;
639
640 =head1 LOGGER INTERFACE
641
642 Because this module is ultimately pretty looking glue (glittery?) with the
643 awesome benefit of the Contextual part, users will often want to make their
644 favorite logger work with it.  The following are the methods that should be
645 implemented in the logger:
646
647  is_trace
648  is_debug
649  is_info
650  is_warn
651  is_error
652  is_fatal
653  trace
654  debug
655  info
656  warn
657  error
658  fatal
659
660 The first six merely need to return true if that level is enabled.  The latter
661 six take the results of whatever the user returned from their coderef and log
662 them.  For a basic example see L<Log::Contextual::SimpleLogger>.
663
664 =head1 LOG ROUTING
665
666 In between the loggers and the log functions is a log router that is responsible for
667 finding a logger to handle the log event and passing the log information to the
668 logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
669
670 C<Log::Contextual> and packages that extend it will by default share a router singleton that
671 implements the with_logger() and set_logger() functions and also respects the -logger,
672 -package_logger, and -default_logger import options with their associated default value
673 functions. The router singleton is available as the return value of the router() function. Users
674 of Log::Contextual may overload router() to return instances of custom log routers that
675 could for example work with loggers that use a different interface.
676
677 =head1 AUTHOR
678
679 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
680
681 =head1 CONTRIBUTORS
682
683 =encoding utf8
684
685 triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
686
687 voj - Jakob Voß <voss@gbv.de>
688
689 =head1 DESIGNER
690
691 mst - Matt S. Trout <mst@shadowcat.co.uk>
692
693 =head1 COPYRIGHT
694
695 Copyright (c) 2012 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
696 above.
697
698 =head1 LICENSE
699
700 This library is free software and may be distributed under the same terms as
701 Perl 5 itself.
702
703 =cut
704