File Coverage

blib/lib/Log/WarnDie.pm
Criterion Covered Total %
statement 46 66 69.7
branch 13 36 36.1
condition 5 15 33.3
subroutine 9 12 75.0
pod 1 1 100.0
total 74 130 56.9


line stmt bran cond sub pod time code
1             package Log::WarnDie;
2              
3 4     4   353885 use warnings;
  4         6  
  4         121  
4 4     4   15 use strict;
  4         4  
  4         64  
5              
6             # Make sure we have the modules that we need
7              
8 4     4   1811 use IO::Handle ();
  4         17981  
  4         83  
9 4     4   17 use Scalar::Util qw(blessed);
  4         4  
  4         2128  
10              
11             # The logging dispatcher that should be used
12             # The (original) error output handle
13             # Reference to the previous parameters sent
14              
15             our $DISPATCHER;
16             our $STDERR;
17             our $LAST;
18              
19             # Old settings of standard Perl logging mechanisms
20              
21             our $WARN;
22             our $DIE;
23              
24             =head1 NAME
25              
26             Log::WarnDie - Log standard Perl warnings and errors on a log handler
27              
28             =head1 VERSION
29              
30             Version 0.08
31              
32             =head1 SYNOPSIS
33              
34             use Log::WarnDie; # install to be used later
35             use Log::Dispatch;
36              
37             my $dispatcher = Log::Dispatch->new(); # can be any dispatcher!
38             $dispatcher->add( Log::Dispatch::Foo->new( # whatever output you like
39             name => 'foo',
40             min_level => 'info',
41             ) );
42              
43             use Log::WarnDie $dispatcher; # activate later
44              
45             Log::WarnDie->dispatcher( $dispatcher ); # same
46              
47             warn "This is a warning"; # now also dispatched
48             die "Sorry it didn't work out"; # now also dispatched
49              
50             no Log::WarnDie; # deactivate later
51              
52             Log::WarnDie->dispatcher( undef ); # same
53              
54             warn "This is a warning"; # no longer dispatched
55             die "Sorry it didn't work out"; # no longer dispatched
56              
57             =head1 DESCRIPTION
58              
59             The "Log::WarnDie" module offers a logging alternative for standard
60             Perl core functions. This allows you to use the features of e.g.
61             L<Log::Dispatch>, L<Log::Any> or L<Log::Log4perl> B<without> having to make extensive
62             changes to your source code.
63              
64             When loaded, it installs a __WARN__ and __DIE__ handler and intercepts any
65             output to STDERR. It also takes over the messaging functions of L<Carp>.
66             Without being further activated, the standard Perl logging functions continue
67             to be executed: e.g. if you expect warnings to appear on STDERR, they will.
68              
69             Then, when necessary, you can activate actual logging through e.g.
70             Log::Dispatch by installing a log dispatcher. From then on, any warn, die,
71             carp, croak, cluck, confess or print to the STDERR handle, will be logged
72             using the Log::Dispatch logging dispatcher. Logging can be disabled and
73             enabled at any time for critical sections of code.
74              
75             =cut
76              
77             our $VERSION = '0.08';
78              
79             =head1 SUBROUTINES/METHODS
80              
81             =cut
82              
83             #---------------------------------------------------------------------------
84              
85             # Tie subroutines need to be known at compile time, hence there here, near
86             # the start of code rather than near the end where these would normally live.
87              
88             #---------------------------------------------------------------------------
89             # TIEHANDLE
90             #
91             # Called whenever a dispatcher is activated
92             #
93             # IN: 1 class with which to bless
94             # OUT: 1 blessed object
95              
96 4     4   13 sub TIEHANDLE { bless \"$_[0]",$_[0] } #TIEHANDLE
97              
98             #---------------------------------------------------------------------------
99             # PRINT
100             #
101             # Called whenever something is printed on STDERR
102             #
103             # IN: 1 blessed object returned by TIEHANDLE
104             # 2..N whatever was needed to be printed
105              
106             sub PRINT {
107              
108             # Lose the object
109             # If there is a dispatcher
110             # Put it in the log handler if not the same as last time
111             # Reset the flag
112             # Make sure it appears on the original STDERR as well
113              
114 1     1   8 shift;
115 1 50       3 if ($DISPATCHER) {
116 1 0 33     7 $DISPATCHER->error( @_ )
      33        
117             unless $LAST and @$LAST == @_ and join( '',@$LAST ) eq join( '',@_ );
118 1         135 undef $LAST;
119             }
120 1 50       8 if($STDERR) {
121 1         12 print $STDERR @_;
122             }
123             } #PRINT
124              
125             #---------------------------------------------------------------------------
126             # PRINTF
127             #
128             # Called whenever something is printed on STDERR using printf
129             #
130             # IN: 1 blessed object returned by TIEHANDLE
131             # 2..N whatever was needed to be printed
132              
133             sub PRINTF {
134              
135             # Lose the object
136             # If there is a dispatcher
137             # Put it in the log handler if not the same as last time
138             # Reset the flag
139             # Make sure it appears on the original STDERR as well
140              
141 1     1   9 shift;
142 1 50       3 if ($DISPATCHER) {
143 1 0 33     6 $DISPATCHER->error( @_ )
      33        
144             unless $LAST and @$LAST == @_ and join( '',@$LAST ) eq join( '',@_ );
145 1         91 undef $LAST;
146             }
147 1 50       3 if($STDERR) {
148 1         35 printf $STDERR @_;
149             }
150             } #PRINTF
151              
152             #---------------------------------------------------------------------------
153             # CLOSE
154             #
155             # Called whenever something tries to close STDERR
156             #
157             # IN: 1 blessed object returned by TIEHANDLE
158             # 2..N whatever was needed to be printed
159              
160             sub CLOSE {
161              
162             # Lose the object
163             # If there is a dispatcher
164             # Put it in the log handler if not the same as last time
165             # Reset the flag
166             # Make sure it appears on the original STDERR as well
167              
168 0     0   0 my $keep = $STDERR;
169 0         0 $STDERR = undef;
170 0         0 close $keep; # So that the return status can be checked
171             } #CLOSE
172              
173             #---------------------------------------------------------------------------
174             # OPEN
175             #
176             # Called whenever something tries to (re)open STDERR
177             #
178             # IN: 1 blessed object returned by TIEHANDLE
179             # 2..N whatever was needed to be printed
180              
181             sub OPEN {
182              
183             # Lose the object
184             # If there is a dispatcher
185             # Put it in the log handler if not the same as last time
186             # Reset the flag
187             # Make sure it appears on the original STDERR as well
188              
189 0     0   0 shift;
190 0         0 my $arg1 = shift;
191 0         0 my $arg2 = shift;
192              
193 0         0 open($STDERR, $arg1, $arg2);
194             } #OPEN
195             #---------------------------------------------------------------------------
196             # At compile time
197             # Create new handle
198             # Make sure it's the same as the current STDERR
199             # Make sure the original STDERR is now handled by our sub
200              
201             BEGIN {
202 4     4   14 $STDERR = new IO::Handle;
203 4 50       66 $STDERR->fdopen( fileno( STDERR ),"w" )
204             or die "Could not open STDERR 2nd time: $!\n";
205 4         154 tie *STDERR,__PACKAGE__;
206              
207             # Save current __WARN__ setting
208             # Replace it with a sub that
209             # If there is a dispatcher
210             # Remembers the last parameters
211             # Dispatches a warning message
212             # Executes the standard system warn() or whatever was there before
213              
214 4         7 $WARN = $SIG{__WARN__};
215             $SIG{__WARN__} = sub {
216 0 0       0 if ($DISPATCHER) {
217 0         0 $LAST = \@_;
218 0 0       0 if(ref($DISPATCHER) =~ /^Log::Log4perl/) {
219 0         0 $DISPATCHER->warn( @_ );
220             } else {
221 0         0 $DISPATCHER->warning( @_ );
222             }
223             }
224 0 0       0 $WARN ? $WARN->( @_ ) : CORE::warn( @_ );
225 4         18 };
226              
227             # Save current __DIE__ setting
228             # Replace it with a sub that
229             # If there is a dispatcher
230             # Remembers the last parameters
231             # Dispatches a critical message
232             # Executes the standard system die() or whatever was there before
233              
234 4         12 $DIE = $SIG{__DIE__};
235             $SIG{__DIE__} = sub {
236 4 50       14 if ($DISPATCHER) {
237 0         0 $LAST = \@_;
238 0 0       0 if(ref($DISPATCHER) =~ /^Log::Log4perl/) {
239 0         0 $DISPATCHER->fatal( @_ );
240             } else {
241 0         0 $DISPATCHER->critical( @_ );
242             }
243             }
244             # Handle http://stackoverflow.com/questions/8078220/custom-error-handling-is-catching-errors-that-normally-are-not-displayed
245             # $DIE ? $DIE->( @_ ) : CORE::die( @_ );
246 4 50       10 if($DIE) {
247 0         0 $DIE->(@_);
248             } else {
249 4 50 33     51 return unless((defined $^S) && ($^S == 0)); # Ignore errors in eval
250 0         0 CORE::die(@_);
251             }
252 4         22 };
253              
254             # Make sure we won't be listed ourselves by Carp::
255              
256 4         627 $Carp::Internal{__PACKAGE__} = 1;
257             } #BEGIN
258              
259             # Satisfy require
260              
261             1;
262              
263             #---------------------------------------------------------------------------
264              
265             # Class methods
266              
267             #---------------------------------------------------------------------------
268              
269             =head2 dispatcher
270              
271             Class method to set and/or return the current dispatcher
272              
273             # IN: 1 class (ignored)
274             # 2 new dispatcher (optional)
275             # OUT: 1 current dispatcher
276              
277             =cut
278              
279             sub dispatcher {
280              
281             # Return the current dispatcher if no changes needed
282             # Set the new dispatcher
283              
284 4 100   4 1 1801 return $DISPATCHER unless @_ > 1;
285 1         3 $DISPATCHER = $_[1];
286              
287             # If there is a dispatcher now
288             # If the dispatcher is a Log::Dispatch er
289             # Make sure all of standard Log::Dispatch stuff becomes invisible for Carp::
290             # If there are outputs already
291             # Make sure all of the output objects become invisible for Carp::
292              
293 1 50       4 if ($DISPATCHER) {
294 1 50       4 if ($DISPATCHER->isa( 'Log::Dispatch' )) {
295             $Carp::Internal{$_} = 1
296 1         5 foreach 'Log::Dispatch','Log::Dispatch::Output';
297 1 50       4 if (my $outputs = $DISPATCHER->{'outputs'}) {
298             $Carp::Internal{$_} = 1
299 1         2 foreach map {blessed $_} values %{$outputs};
  1         7  
  1         3  
300             }
301             }
302             }
303              
304             # Return the current dispatcher
305              
306 1         2 $DISPATCHER;
307             } #dispatcher
308              
309             #---------------------------------------------------------------------------
310              
311             # Perl standard features
312              
313             #---------------------------------------------------------------------------
314             # import
315             #
316             # Called whenever a -use- is done.
317             #
318             # IN: 1 class (ignored)
319             # 2 new dispatcher (optional)
320              
321             *import = \&dispatcher;
322              
323             #---------------------------------------------------------------------------
324             # unimport
325             #
326             # Called whenever a -use- is done.
327             #
328             # IN: 1 class (ignored)
329              
330 0     0     sub unimport { import( undef ) } #unimport
331              
332             #---------------------------------------------------------------------------
333              
334             __END__
335              
336             =head1 LOG LEVELS
337              
338             The following log levels are used:
339              
340             =head2 warning
341              
342             Any C<warn>, C<Carp::carp> or C<Carp::cluck> will generate a "warning" level
343             message.
344              
345             =head2 error
346              
347             Any direct output to STDERR will generate an "error" level message.
348              
349             =head2 critical
350              
351             Any C<die>, C<Carp::croak> or C<Carp::confess> will generate a "critical"
352             level message.
353              
354             =head1 REQUIRED MODULES
355              
356             Scalar::Util (1.08)
357              
358             =head1 CAVEATS
359              
360             The following caveats may apply to your situation.
361              
362             =head2 Associated modules
363              
364             Although a module such as L<Log::Dispatch> is B<not> listed as a prerequisite,
365             the real use of this module only comes into view when such a module B<is>
366             installed. Please note that for testing this module, you will need the
367             L<Log::Dispatch::Buffer> module to also be available.
368              
369             This module has been tested with
370             L<Log::Dispatch>, L<Log::Any> and L<Log::Log4perl>.
371             In principle any object which recognises C<warning>, C<error> and C<critical> should work.
372              
373             =head2 eval
374              
375             In the current implementation of Perl, a __DIE__ handler is B<also> called
376             inside an eval. Whereas a normal C<die> would just exit the eval, the __DIE__
377             handler _will_ get called inside the eval. Which may or may not be what you
378             want. To prevent the __DIE__ handler to be called inside eval's, add the
379             following line to the eval block or string being evaluated:
380              
381             local $SIG{__DIE__} = undef;
382              
383             This disables the __DIE__ handler within the evalled block or string, and
384             will automatically enable it again upon exit of the evalled block or string.
385             Unfortunately there is no automatic way to do that for you.
386              
387             =head1 AUTHOR
388              
389             Elizabeth Mattijsen, <liz@dijkmat.nl>
390              
391             Maintained by Nigel Horne, C<< <njh at bandsman.co.uk> >>
392              
393             =head1 BUGS
394              
395             Please report any bugs or feature requests to C<bug-log-warndie at rt.cpan.org>,
396             or through the web interface at
397             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Log-WarnDie>.
398             I will be notified, and then you'll
399             automatically be notified of progress on your bug as I make changes.
400              
401             =head1 COPYRIGHT
402              
403             Copyright (c) 2004, 2007 Elizabeth Mattijsen <liz@dijkmat.nl>. All rights
404             reserved. This program is free software; you can redistribute it and/or
405             modify it under the same terms as Perl itself.
406              
407             Portions of versions 0.06 onwards, Copyright 2017 Nigel Horne
408              
409             =cut