File Coverage

blib/lib/Log/Log4perl/Tiny.pm
Criterion Covered Total %
statement 379 406 93.3
branch 164 230 71.3
condition 21 38 55.2
subroutine 40 42 95.2
pod 22 22 100.0
total 626 738 84.8


line stmt bran cond sub pod time code
1             package Log::Log4perl::Tiny;
2              
3 27     27   1635577 use strict;
  27         296  
  27         731  
4 27     27   128 use warnings;
  27         39  
  27         998  
5             { our $VERSION = '1.8.0'; }
6              
7 27     27   124 use Carp;
  27         43  
  27         1232  
8 27     27   12411 use POSIX ();
  27         150540  
  27         2479  
9              
10             our ($TRACE, $DEBUG, $INFO, $WARN, $ERROR, $FATAL, $OFF, $DEAD);
11             my ($_instance, %name_of, %format_for, %id_for);
12             my $LOGDIE_MESSAGE_ON_STDERR = 1;
13              
14             sub import {
15 33     33   11455 my ($exporter, @list) = @_;
16 33         119 my ($caller, $file, $line) = caller();
17 27     27   186 no strict 'refs';
  27         48  
  27         75815  
18              
19 33 50       92 if (grep { $_ eq ':full_or_fake' } @list) {
  53         173  
20 0         0 @list = grep { $_ ne ':full_or_fake' } @list;
  0         0  
21 0         0 my $sue = 'use Log::Log4perl (@list)';
22 0 0       0 eval "
23             package $caller;
24             $sue;
25             1;
26             " and return;
27 0         0 unshift @list, ':fake';
28             } ## end if (grep { $_ eq ':full_or_fake'...})
29              
30 33         117 my (%done, $level_set);
31             ITEM:
32 33         73 for my $item (@list) {
33 320 100       579 next ITEM if $done{$item};
34 310         432 $done{$item} = 1;
35 310 100       821 if ($item =~ /^[a-zA-Z]/mxs) {
    100          
    100          
    100          
    100          
    100          
    50          
36 234         251 *{$caller . '::' . $item} = \&{$exporter . '::' . $item};
  234         940  
  234         490  
37             }
38             elsif ($item eq ':levels') {
39 26         51 for my $level (qw( TRACE DEBUG INFO WARN ERROR FATAL OFF DEAD )) {
40 208         233 *{$caller . '::' . $level} = \${$exporter . '::' . $level};
  208         558  
  208         419  
41             }
42             }
43             elsif ($item eq ':subs') {
44 15         57 push @list, qw(
45             ALWAYS TRACE DEBUG INFO WARN ERROR FATAL
46             LOGWARN LOGDIE LOGEXIT LOGCARP LOGCLUCK LOGCROAK LOGCONFESS
47             get_logger
48             );
49             } ## end elsif ($item eq ':subs')
50             elsif ($item =~ /\A : (mimic | mask | fake) \z/mxs) {
51              
52             # module name as a string below to trick Module::ScanDeps
53 15 100       136 if (!'Log::Log4perl'->can('easy_init')) {
54 13         29 $INC{'Log/Log4perl.pm'} = __FILE__;
55 13     2   45 *Log::Log4perl::import = sub { };
56             *Log::Log4perl::easy_init = sub {
57 12     12   3647 my ($pack, $conf) = @_;
58 12 100       59 if (ref $conf) {
    100          
59 9         57 $_instance = __PACKAGE__->new($conf);
60             $_instance->level($conf->{level})
61 9 50       58 if exists $conf->{level};
62             $_instance->format($conf->{format})
63 9 100       61 if exists $conf->{format};
64             $_instance->format($conf->{layout})
65 9 50       98 if exists $conf->{layout};
66             $_instance->filter($conf->{filter})
67 9 100       98 if exists $conf->{filter};
68             } ## end if (ref $conf)
69             elsif (defined $conf) {
70 2         5 $_instance->level($conf);
71             }
72 13         44 };
73             } ## end if (!'Log::Log4perl'->...)
74             } ## end elsif ($item =~ /\A : (mimic | mask | fake) \z/mxs)
75             elsif ($item eq ':easy') {
76 14         34 push @list, qw( :levels :subs :fake );
77             }
78             elsif (lc($item) eq ':dead_if_first') {
79 5         12 get_logger()->_set_level_if_first($DEAD);
80 5         11 $level_set = 1;
81             }
82             elsif (lc($item) eq ':no_extra_logdie_message') {
83 1         2 $LOGDIE_MESSAGE_ON_STDERR = 0;
84             }
85             } ## end ITEM: for my $item (@list)
86              
87 33 100       90 if (!$level_set) {
88 28         92 my $logger = get_logger();
89 28         131 $logger->_set_level_if_first($INFO);
90 28         107 $logger->level($logger->level());
91             }
92              
93 33         9802 return;
94             } ## end sub import
95              
96             sub new {
97 39     39 1 1784 my $package = shift;
98 39 100       164 my %args = ref($_[0]) ? %{$_[0]} : @_;
  9         43  
99              
100 39 50       168 $args{format} = $args{layout} if exists $args{layout};
101              
102 39         143 my $channels_input = [fh => \*STDERR];
103 39 100       129 if (exists $args{channels}) {
104 1         3 $channels_input = $args{channels};
105             }
106             else {
107 38         92 for my $key (qw< file_append file_create file_insecure file fh >) {
108 183 100       356 next unless exists $args{$key};
109 4         13 $channels_input = [$key => $args{$key}];
110 4         10 last;
111             }
112             } ## end else [ if (exists $args{channels...})]
113 39         115 my $channels = build_channels($channels_input);
114 39 100       154 $channels = $channels->[0] if @$channels == 1; # remove outer shell
115              
116 39         182 my $self = bless {
117             fh => $channels,
118             level => $INFO,
119             }, $package;
120              
121 39         101 for my $accessor (qw( level fh format filter )) {
122 156 100       340 next unless defined $args{$accessor};
123 20         73 $self->$accessor($args{$accessor});
124             }
125              
126 39 100       357 $self->format('[%d] [%5p] %m%n') unless exists $self->{format};
127              
128 39 100       110 if (exists $args{loglocal}) {
129 1         3 my $local = $args{loglocal};
130 1         8 $self->loglocal($_, $local->{$_}) for keys %$local;
131             }
132              
133 39         1227 return $self;
134             } ## end sub new
135              
136             sub build_channels {
137 39 50 33 39 1 252 my @pairs = (@_ && ref($_[0])) ? @{$_[0]} : @_;
  39         529  
138 39         97 my @channels;
139 39         108 while (@pairs) {
140 42         160 my ($key, $value) = splice @pairs, 0, 2;
141              
142             # some initial validation
143 42 50       120 croak "build_channels(): undefined key in list"
144             unless defined $key;
145 42 50       96 croak "build_channels(): undefined value for key $key"
146             unless defined $value;
147              
148             # analyze the key-value pair and set the channel accordingly
149 42         71 my ($channel, $set_autoflush);
150 42 100       284 if ($key =~ m{\A(?: fh | sub | code | channel )\z}mxs) {
    100          
    50          
    0          
151 38         62 $channel = $value;
152             }
153             elsif ($key eq 'file_append') {
154 2 50       71 open $channel, '>>', $value
155             or croak "open('$value') for appending: $!";
156 2         8 $set_autoflush = 1;
157             }
158             elsif ($key eq 'file_create') {
159 2 50       149 open $channel, '>', $value
160             or croak "open('$value') for creating: $!";
161 2         10 $set_autoflush = 1;
162             }
163             elsif ($key =~ m{\A file (?: _insecure )? \z}mxs) {
164 0 0       0 open $channel, $value
165             or croak "open('$value'): $!";
166 0         0 $set_autoflush = 1;
167             }
168             else {
169 0         0 croak "unsupported channel key '$key'";
170             }
171              
172             # autoflush new filehandle if applicable
173 42 100       135 if ($set_autoflush) {
174 4         17 my $previous = select($channel);
175 4         15 $|++;
176 4         13 select($previous);
177             }
178              
179             # record the channel, on to the next
180 42         133 push @channels, $channel;
181             } ## end while (@pairs)
182 39         126 return \@channels;
183             } ## end sub build_channels
184              
185 93   66 93 1 12781 sub get_logger { return $_instance ||= __PACKAGE__->new(); }
186 2     2 1 84 sub LOGLEVEL { return get_logger()->level(@_); }
187              
188             sub LEVELID_FOR {
189 7     7 1 979 my $level = shift;
190 7 50       35 return $id_for{$level} if exists $id_for{$level};
191 0         0 return;
192             } ## end sub LEVELID_FOR
193              
194             sub LEVELNAME_FOR {
195 7     7 1 4047 my $id = shift;
196 7 50       35 return $name_of{$id} if exists $name_of{$id};
197 0 0       0 return $id if exists $id_for{$id};
198 0         0 return;
199             } ## end sub LEVELNAME_FOR
200              
201             sub loglocal {
202 11     11 1 1774 my $self = shift;
203 11         16 my $key = shift;
204 11         22 my $retval = delete $self->{loglocal}{$key};
205 11 100       35 $self->{loglocal}{$key} = shift if @_;
206 11         30 return $retval;
207             } ## end sub loglocal
208 4     4 1 3349 sub LOGLOCAL { return get_logger->loglocal(@_) }
209              
210             sub filter {
211 4     4 1 6 my $self = shift;
212 4 100       10 $self->{filter} = shift if @_;
213 4         9 return $self->{filter};
214             }
215 2     2 1 456 sub FILTER { return get_logger->filter(@_) }
216              
217             sub format {
218 95     95 1 25774 my $self = shift;
219              
220 95 50       350 if (@_) {
221 95         240 $self->{format} = shift;
222 95         269 $self->{args} = \my @args;
223             my $replace = sub {
224 218 100   218   498 if (defined $_[2]) { # op with options
225 7         26 my ($num, $opts, $op) = @_[0 .. 2];
226 7         16 push @args, [$op, $opts];
227 7         55 return "%$num$format_for{$op}[0]";
228             }
229 211 100       395 if (defined $_[4]) { # op without options
230 207         674 my ($num, $op) = @_[3, 4];
231 207         416 push @args, [$op];
232 207         1544 return "%$num$format_for{$op}[0]";
233             }
234              
235             # not an op
236 4 100 100     17 my $char = ((!defined($_[5])) || ($_[5] eq '%')) ? '' : $_[5];
237 4         30 return '%%' . $char; # keep the percent AND the char, if any
238 95         563 };
239              
240             # transform into real format
241 95         223 my ($with_options, $standalone) = ('', '');
242 95         460 for my $key (keys %format_for) {
243 1615   100     3178 my $type = $format_for{$key}[2] || '';
244 1615 100       2148 $with_options .= $key if $type;
245 1615 100       2620 $standalone .= $key if $type ne 'required';
246             }
247              
248             # quotemeta or land on impossible character class if empty
249             $_ = length($_) ? quotemeta($_) : '^\\w\\W'
250 95 50       472 for ($with_options, $standalone);
251 95         2249 $self->{format} =~ s<
252             % # format marker
253             (?:
254             (?: # something with options
255             ( -? \d* (?:\.\d+)? ) # number
256             ( (?:\{ .*? \}) ) # options
257             ([$with_options]) # specifier
258             )
259             | (?:
260             ( -? \d* (?:\.\d+)? ) # number
261             ([$standalone]) # specifier
262             )
263             | (.) # just any char
264             | \z # just the end of it!
265             )
266             >
267 218         542 {
268             $replace->($1, $2, $3, $4, $5, $6);
269             }gsmex;
270 95         239 } ## end if (@_)
271             return $self->{format};
272             } ## end sub format
273              
274             *layout = \&format;
275              
276 111     111 1 262 sub emit_log {
277 111         166 my ($self, $message) = @_;
278 111 100       318 my $fh = $self->{fh};
279             for my $channel ((ref($fh) eq 'ARRAY') ? (@$fh) : ($fh)) {
280             (ref($channel) eq 'CODE')
281 114 100       261 ? $channel->($message, $self)
  94         467  
282             : print {$channel} $message;
283 111         403 }
284             return $message;
285             } ## end sub emit_log
286              
287 136     136 1 191 sub log {
288 136 100       313 my $self = shift;
289             return if $self->{level} == $DEAD;
290 134         231  
291 134 100       338 my $level = shift;
292             return if $level > $self->{level};
293              
294             my %data_for = (
295             level => $level,
296 111 100       475 message => \@_,
297             (exists($self->{loglocal}) ? (loglocal => $self->{loglocal}) : ()),
298             );
299 111         188 my $message = sprintf $self->{format},
  248         732  
  111         262  
300             map { $format_for{$_->[0]}[1]->(\%data_for, @$_); } @{$self->{args}};
301 111 100       344  
302             $message = $self->{filter}->($message) if $self->{filter};
303 111         289  
304             return $self->emit_log($message);
305             } ## end sub log
306 2     2 1 12  
307             sub ALWAYS { return $_instance->log($OFF, @_); }
308              
309 0   0 0   0 sub _exit {
310 0 0       0 my $self = shift || $_instance;
311 0 0       0 exit $self->{logexit_code} if defined $self->{logexit_code};
312             exit $Log::Log4perl::LOGEXIT_CODE
313 0         0 if defined $Log::Log4perl::LOGEXIT_CODE;
314             exit 1;
315             } ## end sub _exit
316              
317 4     4 1 15 sub logwarn {
318             my $self = shift;
319 4         6  
320 4 50 33     11 my @message;
321             @message = __expand_message_list({message => \@_})
322             if $self->is_warn() || $LOGDIE_MESSAGE_ON_STDERR;
323 4         36  
324             $self->warn(@message);
325 4 50       13  
326             if ($LOGDIE_MESSAGE_ON_STDERR) {
327 4 50       11 # default warning when nothing is passed to warn
328             push @message, "Warning: something's wrong" unless @message;
329              
330 4         24 # add 'at line ' unless argument ends in "\n";
331 4 50       21 my (undef, $file, $line) = caller(1);
332             push @message, sprintf " at %s line %d.\n", $file, $line
333             if substr($message[-1], -1, 1) ne "\n";
334              
335 4         39 # go for it!
336             CORE::warn(@message);
337             }
338              
339 4         21 return
340             } ## end sub logwarn
341              
342 1     1 1 12 sub logdie {
343             my $self = shift;
344 1         2  
345 1 50 33     5 my @message;
346             @message = __expand_message_list({message => \@_})
347             if $self->is_fatal() || $LOGDIE_MESSAGE_ON_STDERR;
348 1         11  
349             $self->fatal(@message);
350 1 50       4  
351             if ($LOGDIE_MESSAGE_ON_STDERR) {
352 1 50       4 # default die message when nothing is passed to die
353             push @message, "Died" unless @message;
354              
355 1         7 # add 'at line ' unless argument ends in "\n";
356 1 50       8 my (undef, $file, $line) = caller(1);
357             push @message, sprintf " at %s line %d.\n", $file, $line
358             if substr($message[-1], -1, 1) ne "\n";
359              
360 1         8 # go for it!
361             CORE::die(@message);
362             }
363 0         0  
364             $self->_exit();
365             } ## end sub logdie
366              
367 0     0 1 0 sub logexit {
368 0         0 my $self = shift;
369 0         0 $self->fatal(@_);
370             $self->_exit();
371             }
372              
373 10     10   17 sub _carpstuff {
374 10         15 my $self = shift;
375 10         15 my $renderer = shift;
376 10         37 my $emitter = shift;
377             my $log_level = shift;
378 10         49  
379             my $emit_log = $self->can("is_$log_level")->($self);
380 10         59  
381 10         31 require Carp;
382 10         17 local $Carp::Internal{'' . __PACKAGE__} = 1;
383             local $Carp::CarpLevel = $Carp::CarpLevel + 2;
384 10         15  
385 10 50 33     48 my @message;
386             @message = __expand_message_list({message => \@_})
387             if $emit_log || $LOGDIE_MESSAGE_ON_STDERR;
388 10 50       41  
389 10         1792 if ($emit_log) { # avoid unless we're allowed to emit
390 10         365 my $message = Carp->can($renderer)->(@message);
391 10         55 my $method = $self->can($log_level);
392             $self->$method($_) for split m{\n}mxs, $message;
393 10 100       33 }
394 8         952 if ($LOGDIE_MESSAGE_ON_STDERR) {
395             Carp->can($emitter)->(@message);
396             }
397 7         247  
398             return;
399             }
400              
401 4     4 1 19 sub logcarp {
402 4         17 my $self = shift;
403             return $self->_carpstuff(qw< shortmess carp warn >, @_);
404             } ## end sub logcarp
405              
406 2     2 1 11 sub logcluck {
407 2         7 my $self = shift;
408             return $self->_carpstuff(qw< longmess cluck warn >, @_);
409             } ## end sub logcluck
410              
411 3     3 1 6 sub logcroak {
412 3         17 my $self = shift;
413 1         3 $self->_carpstuff(qw< shortmess croak fatal >, @_);
414             $self->_exit();
415             } ## end sub logcroak
416              
417 1     1 1 3 sub logconfess {
418 1         4 my $self = shift;
419 0         0 $self->_carpstuff(qw< longmess confess fatal >, @_);
420             $self->_exit();
421             } ## end sub logconfess
422              
423 130     130 1 8537 sub level {
424 130 50       289 my $self = shift;
425 130 100       315 $self = $_instance unless ref $self;
426 91         143 if (@_) {
427 91 50       223 my $level = shift;
428 91         178 return unless exists $id_for{$level};
429 91         171 $self->{level} = $id_for{$level};
430             $self->{_count}++;
431 130         277 } ## end if (@_)
432             return $self->{level};
433             } ## end sub level
434              
435 33     33   85 sub _set_level_if_first {
436 33 100       100 my ($self, $level) = @_;
437 28         87 if (!$self->{_count}) {
438 28         48 $self->level($level);
439             delete $self->{_count};
440 33         130 }
441             return;
442             } ## end sub _set_level_if_first
443              
444             sub __expand_message_list {
445             join(
446 84 50   84   199 (defined $, ? $, : ''),
  91 100       396  
  84         186  
447             map { ref($_) eq 'CODE' ? $_->() : $_; } @{shift->{message}}
448             );
449             }
450              
451             BEGIN {
452              
453             # Time tracking's start time. Used to be tied to $^T but Log::Log4perl
454 27     27   100 # does differently and uses Time::HiRes if available
455 27         127 my $has_time_hires;
  0         0  
456 27         69 my $gtod = sub { return (time(), 0) };
457 27         14626 eval {
458 27         32122 require Time::HiRes;
459 27         116 $has_time_hires = 1;
460             $gtod = \&Time::HiRes::gettimeofday;
461             };
462 27         262  
463             my $start_time = [$gtod->()];
464              
465 27         50 # For supporting %R
466             my $last_log = $start_time;
467              
468 27         2661 # Timezones are... differently supported somewhere
469             my $strftime_has_tz_offset =
470 27 50       157 POSIX::strftime('%z', localtime()) =~ m<\A [-+] \d{4} \z>mxs;
471 0         0 if (! $strftime_has_tz_offset) {
472             require Time::Local;
473             }
474              
475 27     27   282 { # alias to the one in Log::Log4perl, for easier switching towards that
  27         59  
  27         37629  
  27         46  
476 27         99 no strict 'refs';
477             *caller_depth = *Log::Log4perl::caller_depth;
478 27         46 }
479 27   50     203 our $caller_depth;
480             $caller_depth ||= 0;
481              
482             # %format_for idea from Log::Tiny by J. M. Adler
483 1         8 %format_for = ( # specifiers according to Log::Log4perl
484             c => [s => sub { 'main' }],
485             C => [
486 5         29 s => sub {
487 5         24 my ($internal_package) = caller 0;
488 5         9 my $max_i = 5;
489 5         8 my $i = 1;
490 5         16 my $package;
491 13         48 while ($i <= $max_i) {
492 13 50       29 ($package) = caller $i;
493 13 100       29 return '*undef*' unless defined $package;
494 8         13 last if $package ne $internal_package;
495             ++$i;
496 5 50       30 } ## end while ($i <= 4)
497 5 100       19 return '*undef' if $i > $max_i;
498 5         20 ($package) = caller($i += $caller_depth) if $caller_depth;
499             return $package;
500             },
501             ],
502             d => [
503 27   50     41 s => sub {
  27         223  
504 27         1883 my ($epoch) = @{shift->{tod} ||= [$gtod->()]};
505             return POSIX::strftime('%Y/%m/%d %H:%M:%S', localtime($epoch));
506             },
507             ],
508             D => [
509 6         13 s => sub {
510 6 100       17 my ($data, $op, $options) = @_;
511 6         15 $options = '{}' unless defined $options;
512 6         24 $options = substr $options, 1, length($options) - 2;
  4         12  
513 6   100     12 my %flag_for = map { $_ => 1 } split /\s*,\s*/, lc($options);
  6         35  
514 6         17 my ($s, $u) = @{$data->{tod} ||= [$gtod->()]};
515             $u = substr "000000$u", -6, 6; # padding left with 0
516 6 100       94 return POSIX::strftime("%Y-%m-%d %H:%M:%S.$u+0000", gmtime $s)
517             if $flag_for{utc};
518 4         128  
519 4 50       161 my @localtime = localtime $s;
520             return POSIX::strftime("%Y-%m-%d %H:%M:%S.$u%z", @localtime)
521             if $strftime_has_tz_offset;
522 0         0  
523 0         0 my $sign = '+';
524 0 0       0 my $offset = Time::Local::timegm(@localtime) - $s;
525 0         0 ($sign, $offset) = ('-', -$offset) if $offset < 0;
526             my $z = sprintf '%s%02d%02d',
527             $sign, # sign
528             int($offset / 3600), # hours
529 0         0 (int($offset / 60) % 60); # minutes
530             return POSIX::strftime("%Y-%m-%d %H:%M:%S.$u$z", @localtime);
531             },
532             'optional'
533             ],
534             e => [
535 3         7 s => sub {
536 3   50     20 my ($data, $op, $options) = @_;
537 3 50       8 $data->{tod} ||= [$gtod->()]; # guarantee consistency here
538 3         8 my $local = $data->{loglocal} or return '';
539 3 50       8 my $key = substr $options, 1, length($options) - 2;
540 3         6 return '' unless exists $local->{$key};
541 3 50       6 my $target = $local->{$key};
542 3 100       12 return '' unless defined $target;
543 2 50       7 my $reft = ref $target or return $target;
544 2         6 return '' unless $reft eq 'CODE';
545             return $target->($data, $op, $options);
546             },
547             'required',
548             ],
549             F => [
550 5         27 s => sub {
551 5         14 my ($internal_package) = caller 0;
552 5         10 my $i = 1;
553 5         18 my ($package, $file);
554 13         43 while ($i <= 4) {
555 13 50       29 ($package, $file) = caller $i;
556 13 100       27 return '*undef*' unless defined $package;
557 8         15 last if $package ne $internal_package;
558             ++$i;
559 5 50       13 } ## end while ($i <= 4)
560 5 100       16 return '*undef' if $i > 4;
561 5         17 (undef, $file) = caller($i += $caller_depth) if $caller_depth;
562             return $file;
563             },
564             ],
565             H => [
566 1 50       3 s => sub {
  1         12  
  1         7  
567             eval { require Sys::Hostname; Sys::Hostname::hostname() }
568             || '';
569             },
570             ],
571             l => [
572 3         19 s => sub {
573 3         8 my ($internal_package) = caller 0;
574 3         6 my $i = 1;
575 3         12 my ($package, $filename, $line);
576 6         26 while ($i <= 4) {
577 6 50       17 ($package, $filename, $line) = caller $i;
578 6 100       17 return '*undef*' unless defined $package;
579 3         46 last if $package ne $internal_package;
580             ++$i;
581 3 50       11 } ## end while ($i <= 4)
582 3 100       10 return '*undef' if $i > 4;
583             (undef, $filename, $line) = caller($i += $caller_depth)
584 3         12 if $caller_depth;
585 3 50       10 my (undef, undef, undef, $subroutine) = caller($i + 1);
586 3         23 $subroutine = "main::" unless defined $subroutine;
587             return sprintf '%s %s (%d)', $subroutine, $filename, $line;
588             },
589             ],
590             L => [
591 5         25 d => sub {
592 5         11 my ($internal_package) = caller 0;
593 5         13 my $i = 1;
594 5         20 my ($package, $line);
595 13         41 while ($i <= 4) {
596 13 50       31 ($package, undef, $line) = caller $i;
597 13 100       28 return -1 unless defined $package;
598 8         13 last if $package ne $internal_package;
599             ++$i;
600 5 50       15 } ## end while ($i <= 4)
601 5 100       14 return -1 if $i > 4;
602             (undef, undef, $line) = caller($i += $caller_depth)
603 5         20 if $caller_depth;
604             return $line;
605             },
606             ],
607             m => [s => \&__expand_message_list,],
608             M => [
609 16         60 s => sub {
610 16         31 my ($internal_package) = caller 0;
611 16         28 my $max_i = 5;
612 16         36 my $i = 1;
613 68         183 while ($i <= $max_i) {
614 68 50       132 my ($package) = caller $i;
615 68 100       110 return '*undef*' unless defined $package;
616 52         72 last if $package ne $internal_package;
617             ++$i;
618 16 50       30 } ## end while ($i <= 4)
619 16 100       30 return '*undef' if $i > $max_i;
620 16         47 $i += $caller_depth if $caller_depth;
621 16 50       36 my (undef, undef, undef, $subroutine) = caller($i + 1);
622 16         37 $subroutine = "main::" unless defined $subroutine;
623             return $subroutine;
624             },
625 57         261 ],
626 40         144 n => [s => sub { "\n" },],
627 1         7 p => [s => sub { $name_of{shift->{level}} },],
628             P => [d => sub { $$ },],
629             r => [
630 3   50     6 d => sub {
  3         33  
631 3         8 my ($s, $u) = @{shift->{tod} ||= [$gtod->()]};
632 3         17 $s -= $start_time->[0];
633 3 50       18 my $m = int(($u - $start_time->[1]) / 1000);
634 3         16 ($s, $m) = ($s - 1, $m + 1000) if $m < 0;
635             return $m + 1000 * $s;
636             },
637             ],
638             R => [
639 3   100     5 d => sub {
  3         20  
640 3         7 my ($sx, $ux) = @{shift->{tod} ||= [$gtod->()]};
641 3         9 my $s = $sx - $last_log->[0];
642 3 50       10 my $m = int(($ux - $last_log->[1]) / 1000);
643 3         9 ($s, $m) = ($s - 1, $m + 1000) if $m < 0;
644 3         23 $last_log = [$sx, $ux];
645             return $m + 1000 * $s;
646             },
647             ],
648             T => [
649 3         19 s => sub {
650 3         7 my ($internal_package) = caller 0;
651 3         12 my $level = 1;
652 6         20 while ($level <= 4) {
653 6 50       16 my ($package) = caller $level;
654 6 100       16 return '*undef*' unless defined $package;
655 3         7 last if $package ne $internal_package;
656             ++$level;
657 3 50       10 } ## end while ($level <= 4)
658             return '*undef' if $level > 4;
659              
660             # usage of Carp::longmess() and substitutions is mostly copied
661             # from Log::Log4perl for better alignment and easier
662 3         10 # transition to the "bigger" module
663             local $Carp::CarpLevel =
664 3         362 $Carp::CarpLevel + $level + $caller_depth;
665 3         600 chomp(my $longmess = Carp::longmess());
666 3         11 $longmess =~ s{(?:\A\s*at.*?\n|^\s*)}{}mxsg;
667 3         17 $longmess =~ s{\n}{, }g;
668             return $longmess;
669 27         1469 },
670             ],
671             );
672              
673 27     27   233 # From now on we're going to play with GLOBs...
  27         64  
  27         9389  
674             no strict 'refs';
675 27         118  
676             for my $name (qw( FATAL ERROR WARN INFO DEBUG TRACE )) {
677              
678 162         663 # create the ->level methods
679 134     134   1591 *{__PACKAGE__ . '::' . lc($name)} = sub {
680 134         486 my $self = shift;
681 162         562 return $self->log($$name, @_);
682             };
683              
684 162         862 # create ->is_level and ->isLevelEnabled methods as well
685 162         514 *{__PACKAGE__ . '::is' . ucfirst(lc($name)) . 'Enabled'} =
686 87 100 66 87   18218 *{__PACKAGE__ . '::is_' . lc($name)} = sub {
687 57         228 return 0 if $_[0]->{level} == $DEAD || $$name > $_[0]->{level};
688 162         409 return 1;
689             };
690             } ## end for my $name (qw( FATAL ERROR WARN INFO DEBUG TRACE ))
691 27         76  
692             for my $name (
693             qw(
694             FATAL ERROR WARN INFO DEBUG TRACE
695             LOGWARN LOGDIE LOGEXIT
696             LOGCARP LOGCLUCK LOGCROAK LOGCONFESS
697             )
698             )
699 351         1262 {
700 21     21   2664 *{__PACKAGE__ . '::' . $name} = sub {
701 351         1185 $_instance->can(lc $name)->($_instance, @_);
702             };
703             } ## end for my $name (qw( FATAL ERROR WARN INFO DEBUG TRACE...))
704 27         55  
705 54         193 for my $accessor (qw( fh logexit_code )) {
706 110     110   3029194 *{__PACKAGE__ . '::' . $accessor} = sub {
707 110 50       288 my $self = shift;
708 110 100       532 $self = $_instance unless ref $self;
709 110         236 $self->{$accessor} = shift if @_;
710 54         172 return $self->{$accessor};
711             };
712             } ## end for my $accessor (qw( fh logexit_code ))
713 27         58  
714 27         56 my $index = -1;
715 216         685 for my $name (qw( DEAD OFF FATAL ERROR WARN INFO DEBUG TRACE )) {
716 216         419 $name_of{$$name = $index} = $name;
717 216         454 $id_for{$name} = $index;
718 216         322 $id_for{$index} = $index;
719             ++$index;
720             } ## end for my $name (qw( DEAD OFF FATAL ERROR WARN INFO DEBUG TRACE ))
721 27         124  
722             get_logger(); # initialises $_instance;
723             } ## end BEGIN
724              
725             1; # Magic true value required at end of module