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