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