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