method reorg
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
1 package Log::Contextual;
2
3 use strict;
4 use warnings;
5
6 our $VERSION = '0.00100';
7
8 require Exporter;
9 use Data::Dumper::Concise;
10
11 BEGIN { our @ISA = qw(Exporter) }
12
13 my @dlog = (qw(
14    Dlog_debug DlogS_debug
15    Dlog_trace DlogS_trace
16    Dlog_warn DlogS_warn
17    Dlog_info DlogS_info
18    Dlog_error DlogS_error
19    Dlog_fatal DlogS_fatal
20  ));
21
22 my @log = (qw(
23    log_debug
24    log_trace
25    log_warn
26    log_info
27    log_error
28    log_fatal
29  ));
30
31 our @EXPORT_OK = (
32    @dlog, @log,
33    qw( set_logger with_logger )
34 );
35
36 our %EXPORT_TAGS = (
37    dlog => \@dlog,
38    log  => \@log,
39    all  => [@dlog, @log],
40 );
41
42 sub import {
43    my $package = shift;
44    die 'Log::Contextual does not have a default import list'
45       unless @_;
46
47    for my $idx ( 0 .. $#_ ) {
48       if ( $_[$idx] eq '-logger' ) {
49          set_logger($_[$idx + 1]);
50          splice @_, $idx, 2;
51          last;
52       }
53    }
54    $package->export_to_level(1, $package, @_);
55 }
56
57 our $Get_Logger;
58
59 sub set_logger {
60    my $logger = $_[0];
61    $logger = do { my $l = $logger; sub { $l } }
62       if ref $logger ne 'CODE';
63    $Get_Logger = $logger;
64 }
65
66 sub with_logger {
67    my $logger = $_[0];
68    $logger = do { my $l = $logger; sub { $l } }
69       if ref $logger ne 'CODE';
70    local $Get_Logger = $logger;
71    $_[1]->();
72 }
73
74
75
76 sub log_trace (&@) {
77    my $log  = $Get_Logger->();
78    my $code = shift;
79    $log->trace($code->(@_))
80       if $log->is_trace;
81    @_
82 }
83
84 sub log_debug (&@) {
85    my $log  = $Get_Logger->();
86    my $code = shift;
87    $log->debug($code->(@_))
88       if $log->is_debug;
89    @_
90 }
91
92 sub log_info (&@) {
93    my $log  = $Get_Logger->();
94    my $code = shift;
95    $log->info($code->(@_))
96       if $log->is_info;
97    @_
98 }
99
100 sub log_warn (&@) {
101    my $log  = $Get_Logger->();
102    my $code = shift;
103    $log->warn($code->(@_))
104       if $log->is_warn;
105    @_
106 }
107
108 sub log_error (&@) {
109    my $log  = $Get_Logger->();
110    my $code = shift;
111    $log->error($code->(@_))
112       if $log->is_error;
113    @_
114 }
115
116 sub log_fatal (&@) {
117    my $log  = $Get_Logger->();
118    my $code = shift;
119    $log->fatal($code->(@_))
120       if $log->is_fatal;
121    @_
122 }
123
124
125
126 sub Dlog_trace (&@) {
127   my $code = shift;
128   my @values = @_;
129   return log_trace {
130      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
131   } @values
132 }
133
134 sub Dlog_debug (&@) {
135   my $code = shift;
136   my @values = @_;
137   log_debug {
138      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
139   } @values
140 }
141
142 sub Dlog_info (&@) {
143   my $code = shift;
144   my @values = @_;
145   log_info {
146      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
147   } @values
148 }
149
150 sub Dlog_warn (&@) {
151   my $code = shift;
152   my @values = @_;
153   log_warn {
154      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
155   } @values
156 }
157
158 sub Dlog_error (&@) {
159   my $code = shift;
160   my @values = @_;
161   log_error {
162      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
163   } @values
164 }
165
166 sub Dlog_fatal (&@) {
167   my $code = shift;
168   my @values = @_;
169   log_fatal {
170      do { local $_ = Data::Dumper::Concise::Dumper @values; $code->() };
171   } @values
172 }
173
174
175
176 sub DlogS_trace (&$) {
177   my $code = $_[0];
178   my $value = $_[1];
179   log_trace {
180      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
181   };
182   $value
183 }
184
185 sub DlogS_debug (&$) {
186   my $code = $_[0];
187   my $value = $_[1];
188   log_debug {
189      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
190   };
191   $value
192 }
193
194 sub DlogS_info (&$) {
195   my $code = $_[0];
196   my $value = $_[1];
197   log_info {
198      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
199   };
200   $value
201 }
202
203 sub DlogS_warn (&$) {
204   my $code = $_[0];
205   my $value = $_[1];
206   log_warn {
207      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
208   };
209   $value
210 }
211
212 sub DlogS_error (&$) {
213   my $code = $_[0];
214   my $value = $_[1];
215   log_error {
216      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
217   };
218   $value
219 }
220
221 sub DlogS_fatal (&$) {
222   my $code = $_[0];
223   my $value = $_[1];
224   log_fatal {
225      do { local $_ = Data::Dumper::Concise::Dumper $value; $code->() };
226   };
227   $value
228 }
229
230 1;
231
232 __END__
233
234 =head1 NAME
235
236 Log::Contextual - Simple logging interface with a contextual log
237
238 =head1 SYNOPSIS
239
240  use Log::Log4perl;
241  use Log::Contextual qw( :log :dlog set_logger with_logger );
242
243  my $logger  = sub { Log::Log4perl->get_logger };
244
245  set_logger { $logger };
246
247  log_debug { 'program started' };
248
249  sub foo {
250    with_logger(Log::Contextual::SimpleLogger->new({
251        levels => [qw( trace debug )]
252      }) => sub {
253      log_trace { 'foo entered' };
254      my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @_;
255      # ...
256      log_trace { 'foo left' };
257    });
258  }
259
260 =head1 DESCRIPTION
261
262 This module is a simple interface to extensible logging.  It is bundled with a
263 really basic logger, L<Log::Contextual::SimpleLogger>, but in general you
264 should use a real logger instead of that.  For something more serious but not
265 overly complicated, take a look at L<Log::Dispatchouli>.
266
267 =head1 OPTIONS
268
269 When you import this module you may use C<-logger> as a shortcut for
270 L<set_logger>, for example:
271
272  use Log::Contextual::SimpleLogger;
273  use Log::Contextual qw( :dlog ),
274    -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] });
275
276 sometimes you might want to have the logger handy for other stuff, in which
277 case you might try something like the following:
278
279  my $var_log;
280  BEGIN { $var_log = VarLogger->new }
281  use Log::Contextual qw( :dlog ), -logger => $var_log;
282
283 =head1 A WORK IN PROGRESS
284
285 This module is certainly not complete, but we will not break the interface
286 lightly, so I would say it's safe to use in production code.  The main result
287 from that at this point is that doing:
288
289  use Log::Contextual;
290
291 will die as we do not yet know what the defaults should be.  If it turns out
292 that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll
293 probably make C<:log> the default.  But only time and usage will tell.
294
295 =head1 FUNCTIONS
296
297 =head2 set_logger
298
299  my $logger = WarnLogger->new;
300  set_logger $logger;
301
302 Arguments: Ref|CodeRef $returning_logger
303
304 C<set_logger> will just set the current logger to whatever you pass it.  It
305 expects a C<CodeRef>, but if you pass it something else it will wrap it in a
306 C<CodeRef> for you.
307
308 =head2 with_logger
309
310  my $logger = WarnLogger->new;
311  with_logger $logger => sub {
312     if (1 == 0) {
313        log_fatal { 'Non Logical Universe Detected' };
314     } else {
315        log_info  { 'All is good' };
316     }
317  };
318
319 Arguments: Ref|CodeRef $returning_logger, CodeRef $to_execute
320
321 C<with_logger> sets the logger for the scope of the C<CodeRef> C<$to_execute>.
322 As with L<set_logger>, C<with_logger> will wrap C<$returning_logger> with a
323 C<CodeRef> if needed.
324
325 =head2 log_$level
326
327 Import Tag: ":log"
328
329 Arguments: CodeRef $returning_message
330
331 All of the following six functions work the same except that a different method
332 is called on the underlying C<$logger> object.  The basic pattern is:
333
334  sub log_$level (&) {
335    if ($logger->is_$level) {
336      $logger->$level(shift->());
337    }
338  }
339
340 =head3 log_trace
341
342  log_trace { 'entered method foo with args ' join q{,}, @args };
343
344 =head3 log_debug
345
346  log_debug { 'entered method foo' };
347
348 =head3 log_info
349
350  log_info { 'started process foo' };
351
352 =head3 log_warn
353
354  log_warn { 'possible misconfiguration at line 10' };
355
356 =head3 log_error
357
358  log_error { 'non-numeric user input!' };
359
360 =head3 log_fatal
361
362  log_fatal { '1 is never equal to 0!' };
363
364 =head2 Dlog_$level
365
366 Import Tag: ":dlog"
367
368 Arguments: CodeRef $returning_message, @args
369
370 All of the following six functions work the same as their L<log_$level>
371 brethren, except they return what is passed into them and put the stringified
372 (with L<Data::Dumper::Concise>) version of their args into C<$_>.  This means
373 you can do cool things like the following:
374
375  my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all;
376
377 and the output might look something like:
378
379  names: "fREW"
380  "fRIOUX"
381  "fROOH"
382  "fRUE"
383  "fiSMBoC"
384
385 =head3 Dlog_trace
386
387  my ($foo, $bar) = Dlog_trace { "entered method foo with args: $_" } @_;
388
389 =head3 Dlog_debug
390
391  Dlog_debug { "random data structure: $_" } { foo => $bar };
392
393 =head3 Dlog_info
394
395  return Dlog_info { "html from method returned: $_" } "<html>...</html>";
396
397 =head3 Dlog_warn
398
399  Dlog_warn { "probably invalid value: $_" } $foo;
400
401 =head3 Dlog_error
402
403  Dlog_error { "non-numeric user input! ($_)" } $port;
404
405 =head3 Dlog_fatal
406
407  Dlog_fatal { '1 is never equal to 0!' } 'ZOMG ZOMG' if 1 == 0;
408
409 =head2 DlogS_$level
410
411 Import Tag: ":dlog"
412
413 Arguments: CodeRef $returning_message, Item $arg
414
415 All of the following six functions work the same as the related L<Dlog_$level>
416 functions, except they only take a single scalar after the
417 C<$returning_message> instead of slurping up (and also setting C<wantarray>)
418 all the C<@args>
419
420  my $pals_rs = DlogS_debug { "pals resultset: $_" }
421    $schema->resultset('Pals')->search({ perlers => 1 });
422
423 =head3 DlogS_trace
424
425  my ($foo, $bar) =
426    DlogS_trace { "entered method foo with first arg $_" } $_[0], $_[1];
427
428 =head3 DlogS_debug
429
430  DlogS_debug { "random data structure: $_" } { foo => $bar };
431
432 =head3 DlogS_info
433
434  return DlogS_info { "html from method returned: $_" } "<html>...</html>";
435
436 =head3 DlogS_warn
437
438  DlogS_warn { "probably invalid value: $_" } $foo;
439
440 =head3 DlogS_error
441
442  DlogS_error { "non-numeric user input! ($_)" } $port;
443
444 =head3 DlogS_fatal
445
446  DlogS_fatal { '1 is never equal to 0!' } 'ZOMG ZOMG' if 1 == 0;
447
448 =head1 LOGGER INTERFACE
449
450 Because this module is ultimately pretty looking glue (glittery?) with the
451 awesome benefit of the Contextual part, users will often want to make their
452 favorite logger work with it.  The following are the methods that should be
453 implemented in the logger:
454
455  is_trace
456  is_debug
457  is_info
458  is_warn
459  is_error
460  is_fatal
461  trace
462  debug
463  info
464  warn
465  error
466  fatal
467
468 The first six merely need to return true if that level is enabled.  The latter
469 six take the results of whatever the user returned from their coderef and log
470 them.  For a basic example see L<Log::Contextual::SimpleLogger>.
471
472 =head1 AUTHOR
473
474 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
475
476 =head1 DESIGNER
477
478 mst - Matt S. Trout <mst@shadowcat.co.uk>
479
480 =head1 COPYRIGHT
481
482 Copyright (c) 2010 the Log::Contextual L</AUTHOR> and L</DESIGNER> as listed
483 above.
484
485 =head1 LICENSE
486
487 This library is free software and may be distributed under the same terms as
488 Perl 5 itself.
489
490 =cut
491