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