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