File Coverage

blib/lib/Easy/Log.pm
Criterion Covered Total %
statement 614 974 63.0
branch 154 498 30.9
condition 51 242 21.0
subroutine 119 136 87.5
pod 12 28 42.8
total 950 1878 50.5


line stmt bran cond sub pod time code
1             package Easy::Log;
2             # -t STDOUT -t STDERR ???
3             my $prefix_dev_backstack = 2;
4 1     1   20706 use Easy::Log::Filter;
  1         5  
  1         8  
5             my $filter_file;
6             our $this_package;
7             BEGIN {
8             # this little but of cruft really sucks, but neither 'require' nor 'do' are bahaving as I would expect(akin to a c #include)
9             #require '/home/lengthe/cvs/adg/util/general/Log/Filter.pm';
10             #require Easy::Log::Filter;
11             #do Easy::Log::Filter;
12 1     1   579 $filter_file = __PACKAGE__ eq 'Easy::Log' ? __FILE__ : ( $INC{'Easy/Log.pm'} or die "Couldn't find location of Easy/Log.pm package" );
13 1         9 $filter_file =~ s|Log.pm|Log/Filter.pm|;
14 1 50       7 print STDERR "filter_file=$filter_file\n" if $ENV{LOG_FILTER_DEBUG};
15 1         3 my $eval = 'package ' . __PACKAGE__ . ';';
16             # this is somewhat evil, but I need to do it to get filtering in THIS package, as well as packages that use this package
17 1 50       90 open(FILTER, "<$filter_file") or die $!;
18 1         171 $eval .= '#' . join("", ); #`cat $filter_file`; # the '#' here comments out the first line of the filter package 'package Easy::Log::Filter;'
19 1         57 close FILTER;
20 1         7 $eval =~ /(.*)/ms; # for untainting in case taint mode is on
21 1         15 $eval = $1;
22 1 50       6 print STDERR "EVAL:#########################\n$eval\n########################\n" if $ENV{LOG_FILTER_DEBUG};
23 1 50 50 1 0 225 eval "{ $eval }";
  1 50 50 1 0 12  
  1 50 50 1 0 2  
  1 0 33 1   4  
  11 50 33 4630   199  
  1 0 0 4630   9  
  1 0   0   2  
  1 0       4  
  28 0       2266  
  11 0       24  
  1 0       5  
  1 0       20  
  1 0       6  
  1 50       5  
  1 50       4  
  1 50       40  
  1 50       7  
  1 50       7  
  1 50       4  
  1 50       1  
  1 50       11  
  0 50       0  
  0 50       0  
  0 50       0  
  1 50       4  
  1 50       7  
  1 50       2  
  0 100       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  1         4  
  1         8  
  1         10  
  1         4  
  1         3  
  1         7  
  1         4  
  1         7  
  1         7  
  1         7  
  1         4  
  1         9  
  1         10  
  1         46  
  1         9  
  1         2  
  1         9  
  4630         7824  
  4630         5693  
  4630         4587  
  4630         9102  
  4630         4446  
  4630         10291  
  4630         5200  
  4630         8443  
  4630         4225  
  4630         7850  
  4630         6086  
  4630         15110  
  4630         4788  
  4630         7539  
  4630         8138  
  4630         13279  
  4630         4862  
  4630         4558  
  4630         4591  
  4630         8580  
  4630         4455  
  4630         10029  
  4630         4762  
  4630         8153  
  4630         4267  
  4630         6836  
  4630         5633  
  4630         9535  
  4630         4682  
  4630         6645  
  4630         8565  
  4630         20586  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
24 1 50       8 (print STDERR '$this_package: ', $this_package, '(', __PACKAGE__, ')', "\n") if $ENV{LOG_FILTER_DEBUG};
25 1 50       37 $@ and die $@;
26             #die;
27             }
28              
29             #
30 1     1   9 use strict;
  1         1  
  1         61  
31 1     1   1069 use Data::Dumper;
  1         10799  
  1         131  
32 1     1   1021 use IO::File;
  1         3118  
  1         297  
33 1     1   9 use Fcntl qw(:flock);
  1         2  
  1         195  
34 1     1   7 use Carp qw( cluck confess );
  1         2  
  1         74  
35 1     1   7 use File::Spec;
  1         2  
  1         102  
36              
37             if ( $ENV{LOG_USE_CARP} and $ENV{LOG_USE_CARP} eq 'YES' ) {
38             # big ugly stack traces when we encounter a 'warn' or a 'die'
39             $SIG{__WARN__} = \&cluck;
40             $SIG{__DIE__} = \&confess;
41             }
42              
43 1     1   7 use Exporter;
  1         2  
  1         465  
44             our ( %EXPORT_TAGS, @ISA, @EXPORT_OK, @EXPORT, $VERSION );
45             @ISA = qw( Exporter );
46              
47             $VERSION = '0.02_00';
48              
49             %EXPORT_TAGS = (
50             # available constants for log level text names, these will never be filtered nor will warnings about them ever be made
51             # basically, these are for production level logging (as opposed to the 'shorthand' log levels below in "log_level_[not_]filtered"
52             # as such they can still be used to put the program in DEBUG mode (etc), but for more formalized debugging
53             #log_level => [ Easy::Log::Filter->LOG_LEVELS() ],
54             log_level => [ LOG_LEVELS() ],
55             # global logging object
56             log => [ qw( $log log ) ],
57             # convenient log level aliases that WILL BE FILTERED if appropriate (MUST begin with a $ [eg regular SCALAR variable]
58             #log_level_filtered => [ map { "\$$_" } Easy::Log::Filter->DEFAULT_FILTER() ],
59             ll_filtered => [ map { "\$$_" } DEFAULT_FILTER() ],
60             # same as above, but without '$', these will not be filtered, but if $ENV{WARN_FILTER} is set, warnings about unfiltered log messages will show up
61             # this is useful for debugging when you may want a particular message to be displayed (simply delete the '$')
62             #log_level_not_filtered => [ Easy::Log::Filter->DEFAULT_FILTER() ],
63             ll_not_filtered => [ DEFAULT_FILTER() ],
64             # these are utility methods for output formatting
65             misc => [ qw(space pad dump _caller $hostname ) ],
66             );
67              
68             $EXPORT_TAGS{all} = [ map {@{$_}} values %EXPORT_TAGS ];
69             $EXPORT_TAGS{initialize} = [ @{$EXPORT_TAGS{log_level}} ];
70             $EXPORT_TAGS{basic} = [ map { @{$EXPORT_TAGS{$_}} } qw( log_level log ll_filtered ll_not_filtered) ];
71             @EXPORT_OK = @{$EXPORT_TAGS{'all'}};
72             @EXPORT = ();
73              
74 1     1   8 use constant MESSAGE => 'MESSAGE'; # this will send an email to the appointed person
  1         2  
  1         99  
75 1     1   8 use constant DEFAULT => 'DEFAULT';
  1         4  
  1         71  
76 1     1   8 use constant LOUD => 'LOUD';
  1         2  
  1         65  
77 1     1   7 use constant CLEAN => 'CLEAN';
  1         2  
  1         66  
78 1     1   8 use constant EMERG => 'EMERG';
  1         7  
  1         101  
79 1     1   8 use constant ALERT => 'ALERT';
  1         3  
  1         83  
80 1     1   7 use constant QUIT => 'QUIT';
  1         3  
  1         183  
81 1     1   9 use constant EXIT => 'QUIT'; # synonym for QUIT
  1         3  
  1         78  
82 1     1   6 use constant CRIT => 'CRIT';
  1         2  
  1         78  
83 1     1   6 use constant FATAL => 'FATAL'; # synonym for CRIT
  1         2  
  1         66  
84 1     1   7 use constant FAIL => 'FAIL'; # synonym for CRIT
  1         2  
  1         67  
85 1     1   8 use constant ERROR => 'ERROR';
  1         1  
  1         65  
86 1     1   8 use constant WARN => 'WARN';
  1         2  
  1         71  
87 1     1   8 use constant NOTICE => 'NOTICE';
  1         8  
  1         154  
88 1     1   8 use constant INFO => 'INFO';
  1         2  
  1         70  
89 1     1   7 use constant DEBUG99 => 'DEBUG99';
  1         2  
  1         74  
90 1     1   6 use constant DEBUG9 => 'DEBUG9';
  1         2  
  1         74  
91 1     1   7 use constant DEBUG8 => 'DEBUG8';
  1         2  
  1         74  
92 1     1   7 use constant DEBUG7 => 'DEBUG7';
  1         1  
  1         70  
93 1     1   7 use constant DEBUG6 => 'DEBUG6';
  1         2  
  1         72  
94 1     1   7 use constant DEBUG5 => 'DEBUG5';
  1         1  
  1         75  
95 1     1   7 use constant DEBUG4 => 'DEBUG4';
  1         1  
  1         61  
96 1     1   7 use constant DEBUG3 => 'DEBUG3';
  1         2  
  1         68  
97 1     1   8 use constant DEBUG2 => 'DEBUG2';
  1         1  
  1         66  
98 1     1   6 use constant DEBUG1 => 'DEBUG1';
  1         43  
  1         68  
99 1     1   13 use constant DEBUG0 => 'DEBUG0';
  1         1  
  1         61  
100 1     1   6 use constant DEBUG => 'DEBUG';
  1         2  
  1         70  
101 1     1   7 use constant TRACE => 'TRACE';
  1         1  
  1         68  
102 1     1   8 use constant SPEW => 'SPEW';
  1         1  
  1         80  
103              
104 1     1   6 use constant D_MESSAGE => 'D_MESSAGE'; # this will send an email to the appointed person
  1         2  
  1         62  
105 1     1   7 use constant D_DEFAULT => 'D_DEFAULT';
  1         3  
  1         75  
106 1     1   6 use constant D_LOUD => 'D_LOUD';
  1         1  
  1         61  
107 1     1   6 use constant D_CLEAN => 'D_CLEAN';
  1         2  
  1         73  
108 1     1   7 use constant D_EMERG => 'D_EMERG';
  1         2  
  1         78  
109 1     1   7 use constant D_ALERT => 'D_ALERT';
  1         2  
  1         75  
110 1     1   7 use constant D_CRIT => 'D_CRIT';
  1         2  
  1         77  
111 1     1   7 use constant D_FATAL => 'D_FATAL';
  1         8  
  1         234  
112 1     1   9 use constant D_FAIL => 'D_FAIL';
  1         2  
  1         73  
113 1     1   7 use constant D_QUIT => 'D_QUIT';
  1         2  
  1         75  
114 1     1   7 use constant D_EXIT => 'D_EXIT';
  1         1  
  1         62  
115 1     1   6 use constant D_ERROR => 'D_ERROR';
  1         2  
  1         68  
116 1     1   8 use constant D_WARN => 'D_WARN';
  1         1  
  1         72  
117 1     1   7 use constant D_NOTICE => 'D_NOTICE';
  1         3  
  1         60  
118 1     1   7 use constant D_INFO => 'D_INFO';
  1         2  
  1         158  
119 1     1   7 use constant D_DEBUG99 => 'D_DEBUG99';
  1         2  
  1         74  
120 1     1   8 use constant D_DEBUG9 => 'D_DEBUG9';
  1         1  
  1         69  
121 1     1   7 use constant D_DEBUG8 => 'D_DEBUG8';
  1         2  
  1         72  
122 1     1   7 use constant D_DEBUG7 => 'D_DEBUG7';
  1         1  
  1         65  
123 1     1   5 use constant D_DEBUG6 => 'D_DEBUG6';
  1         2  
  1         110  
124 1     1   7 use constant D_DEBUG5 => 'D_DEBUG5';
  1         2  
  1         72  
125 1     1   6 use constant D_DEBUG4 => 'D_DEBUG4';
  1         2  
  1         62  
126 1     1   7 use constant D_DEBUG3 => 'D_DEBUG3';
  1         2  
  1         90  
127 1     1   7 use constant D_DEBUG2 => 'D_DEBUG2';
  1         1  
  1         67  
128 1     1   8 use constant D_DEBUG1 => 'D_DEBUG1';
  1         1  
  1         68  
129 1     1   8 use constant D_DEBUG0 => 'D_DEBUG0';
  1         1  
  1         74  
130 1     1   8 use constant D_DEBUG => 'D_DEBUG';
  1         922  
  1         69  
131 1     1   6 use constant D_TRACE => 'D_TRACE';
  1         2  
  1         66  
132 1     1   7 use constant D_SPEW => 'D_SPEW';
  1         1  
  1         84  
133              
134              
135              
136             # the following, when used as log levels in code calling this package with qw(:all)
137             # these may not be worth the clutter
138             # I have also made identically named scalars which if used will cause the log messages to be filtered out
139             # WARNING: without the `$' the log message WILL NOT be filtered out!
140 1     1   7 use constant ll => D_DEFAULT;
  1         1  
  1         71  
141 1     1   7 use constant mll => D_MESSAGE;
  1         1  
  1         70  
142 1     1   7 use constant lll => D_LOUD;
  1         1  
  1         71  
143 1     1   7 use constant cll => D_CLEAN;
  1         2  
  1         79  
144 1     1   7 use constant qll => D_QUIT;
  1         2  
  1         74  
145 1     1   6 use constant ell => D_ERROR;
  1         2  
  1         67  
146 1     1   6 use constant all => D_ALERT;
  1         2  
  1         71  
147 1     1   6 use constant wll => D_WARN;
  1         2  
  1         84  
148 1     1   7 use constant nll => D_NOTICE;
  1         1  
  1         81  
149 1     1   9 use constant ill => D_INFO;
  1         1  
  1         86  
150 1     1   8 use constant dl99 => D_DEBUG99;
  1         2  
  1         77  
151 1     1   6 use constant dl9 => D_DEBUG9;
  1         2  
  1         89  
152 1     1   7 use constant dl8 => D_DEBUG8;
  1         2  
  1         77  
153 1     1   7 use constant dl7 => D_DEBUG7;
  1         2  
  1         75  
154 1     1   6 use constant dl6 => D_DEBUG6;
  1         2  
  1         77  
155 1     1   6 use constant dl5 => D_DEBUG5;
  1         1  
  1         81  
156 1     1   7 use constant dl4 => D_DEBUG4;
  1         1  
  1         75  
157 1     1   8 use constant dl3 => D_DEBUG3;
  1         2  
  1         76  
158 1     1   6 use constant dl2 => D_DEBUG2;
  1         1  
  1         77  
159 1     1   6 use constant dl1 => D_DEBUG1;
  1         1  
  1         70  
160 1     1   7 use constant dl0 => D_DEBUG0;
  1         2  
  1         74  
161 1     1   6 use constant dll => D_DEBUG;
  1         2  
  1         76  
162 1     1   7 use constant tll => D_TRACE;
  1         1  
  1         70  
163 1     1   6 use constant sll => D_SPEW;
  1         1  
  1         17452  
164              
165              
166             our ( $p_space, $p_pad ) = ( 8, 8 );
167             our $STACK_TRACE = $ENV{LOG_STACK_TRACE} || 0;
168              
169             our ( $DUMPER, $log_level, $log, $intlog );
170              
171             # if we have big warngings set to true for any particular log level then we'll issue a perl 'warn'ing
172             our %BIG_WARN_DEFAULTS = ( ( map { ("DEBUG$_" => 0); } ( 0 .. 9 ) ),
173             ( map { ($_ => 0);} qw( MESSAGE LOUD CLEAN QUIT EXIT EMERG ALERT CRIT FATAL FAIL ERROR WARN NOTICE INFO DEBUG TRACE SPEW ) ),
174             ( qw( WARN 0 ERROR 0 CRIT 1 FATAL 1 FAIL 0 ) )
175             );
176             #our %BIG_WARN_ON = map { print STDERR qq'BIG_WARN_ON_$_ => ', ( defined $ENV{"BIG_WARN_ON_$_"} ? $ENV{"BIG_WARN_ON_$_"} : 'undef' ), "\n"; ( $_ => ( defined $ENV{"BIG_WARN_ON_$_"} ? $ENV{"BIG_WARN_ON_$_"} : ( $BIG_WARN_DEFAULTS{$_} || 0 ) )); } keys %BIG_WARN_DEFAULTS;
177             our %BIG_WARN_ON = map { ( $_ => ( defined $ENV{"BIG_WARN_ON_$_"} ? $ENV{"BIG_WARN_ON_$_"} : ( $BIG_WARN_DEFAULTS{$_} || 0 ) )); } keys %BIG_WARN_DEFAULTS;
178             # these were(are?) actually apache constants for logging levels I think anything that gets in that
179             # is preceded with a '_' gets [0] (numerical value) these return the uppercase(?) version of
180             # themselves
181             our %LOG_CODE = ( STDERR => 0x00E0,
182             STDOUT => 0x00E0,
183             CLEAN => 0x00E0,
184             MESSAGE => 0x00E0,
185             LOUD => 0x00E0,
186             CRIT => 0x00E0,
187             FATAL => 0x00E0,
188             FAIL => 0x00E0,
189             QUIT => 0x00E0,
190             EXIT => 0x00E0,# synonym for QUIT
191             EMERG => 0x00E0,
192             ALERT => 0x0080,
193             ERROR => 0x0070,
194             WARN => 0x0060,
195             NOTICE => 0x0050,
196             INFO => 0x0040,
197             DEBUG99 => 0x0040, # this is the same as INFO, but will cause the line number and package to be printed with EVERY log call if LOG_LEVEL is set to anything that matched '.*DEBUG.*'
198             (map { ("DEBUG$_" => ( 0x0030 + $_ )); } ( 0 .. 9 )),
199             DEBUG => 0x0030,
200             TRACE => 0x0020,
201             SPEW => 0x0010,
202             DEFAULT => 0x0030,# set equal to DEBUG
203             );
204             # translate between our more expanded selection of logging levels to what apache understands
205             our %APACHE_LEVELS = ( DEFAULT => INFO,
206             TRACE => DEBUG,
207             SPEW => DEBUG,
208             DEBUG => DEBUG,
209             (map { ("DEBUG$_" => 'DEBUG'); } ( 0 .. 9, 99 )),
210             INFO => INFO,
211             WARN => WARN,
212             NOTICE => NOTICE,
213             CRIT => CRIT,
214             FATAL => CRIT,
215             FAIL => CRIT,
216             QUIT => CRIT,
217             EXIT => CRIT,
218             ERROR => ERROR,
219             ALERT => ALERT,
220             EMERG => EMERG,
221             LOUD => ERROR,
222             CLEAN => ERROR,
223             );
224              
225             our ( $ll, $lll, $qll, $cll, $ell, $all, $wll, $nll, $ill, $dll, $tll, $sll, $mll, $dl0, $dl1, $dl2, $dl3, $dl4, $dl5, $dl6, $dl7, $dl8, $dl9, $dl99 )
226             = ( ll, lll, qll, cll, ell, all, wll, nll, ill, dll, tll, sll, mll, dl0, dl1, dl2, dl3, dl4, dl5, dl6, dl7, dl8, dl9, dl99 );
227             our $n;
228             our %LEVEL_FHS = map { ($_ => 'STDERR'); } qw(EMERG ALERT CRIT FATAL FAIL ERROR WARN QUIT);
229              
230             #%ALWAYS_LOG is for log levels that should never be dropped, even if the package is blocked from logging
231             our %ALWAYS_LOG = qw(
232             CLEAN 1
233             CRIT 1
234             FATAL 1
235             FAIL 1
236             QUIT 1
237             ERROR 1
238             ALERT 1
239             EMERG 1
240             MESSAGE 1
241             STDOUT 1
242             STDERR 1
243             );
244             foreach my $log_level ( LOG_LEVELS ) {
245             $ALWAYS_LOG{$log_level} ||= 0;
246             }
247             our $default_log_level = 'INFO';
248             our $default_indent = 1;
249             our $default_pad = 0;
250             $log_level = $ENV{LOG_LEVEL} ||= ( [ map {$ENV{$_}?$_:()}(@{$EXPORT_TAGS{log_level}}) ]->[0] || $default_log_level );
251             # message terminator (sometimes we DON'T want newlines!)
252              
253             our $default_handle_fatals = 1;
254             our $default_unbuffer = 1;
255             our $default_fh = $ENV{LOG_FILE_DEFAULT} || $ENV{DEFAULT_LOG_FILE} || 'STDOUT';
256             our %init = ( log_file => $ENV{LOG_FILE} || $default_fh ,
257             log_level => $log_level,
258             dump_refs => (exists $ENV{LOG_DUMP_REFS} ) ? $ENV{LOG_DUMP_REFS} : 1 ,
259             handle_fatals => (exists $ENV{LOG_HANDLE_FATALS}) ? $ENV{LOG_HANDLE_FATALS} : $default_handle_fatals,
260             exclusive => $ENV{LOG_EXCLUSIVE} || '',
261             unbuffer => (exists $ENV{LOG_UNBUFFER} ? $ENV{LOG_UNBUFFER} : $default_unbuffer),
262             #prefix => \&_prefix_default,
263             );
264              
265             our %FHS_NO = (); # store list of filehandles indexed by fileno()
266             our %FHS_NA = (); # store list of filehandles indexed by file name
267             our %FHN_NO = (); # corresponding list of filenames for our filehandles indexed by fileno()
268             # OK .. I'm not sure, but trying to use STDIN may be totally retarded
269             #@LEVEL_FHS{qw( STDIN STDOUT STDERR )} = ( \*STDIN , \*STDOUT, \*STDERR );
270             @FHS_NA{qw( STDIN STDOUT STDERR )} = ( \*STDIN , \*STDOUT, \*STDERR );
271             @FHN_NO{(map { fileno($_); } @FHS_NA{qw( STDIN STDOUT STDERR )})} = qw( STDIN STDOUT STDERR );
272             @FHS_NO{keys %FHN_NO} = values %FHN_NO;
273             foreach my $fh ( @FHS_NA{qw( STDOUT STDERR )} ) { $log->{unbuffer} ? _unbuffer( $fh ) : (); }
274              
275              
276             $log = $this_package->new();
277             $intlog = $this_package->new( { prefix => \&_prefix_dev } );
278              
279             our $hostname = `hostname`;
280             #print STDERR '$hostname: ', $hostname;
281             chomp $hostname;
282             $intlog->write($dll, '$hostname: ', $hostname );
283              
284             our @userinfo = getpwuid $<;
285             our $username = $userinfo[0];
286              
287             my @pathinfo = (File::Spec->splitpath( File::Spec->rel2abs( $0 )));
288             $intlog->write({prefix=>undef},$sll, '@pathinfo: ', \@pathinfo );
289              
290             my $path_base = $0;
291             my @o = split( m|/|, $path_base );
292             $intlog->write($dll, '@o: ', \@o );
293             my $max_path_seg = 3;
294             my $num_path_seg = scalar @o;
295             #my $path_abbrev = ( $num_path_seg > $max_path_seg ) ? join('/', map {''} ( 1 .. ( $num_path_seg - $max_path_seg ))), '...', @o[$#o - 1 .. $#o ] ) : $path_base;
296             #my $path_abbrev = ( $num_path_seg > $max_path_seg ) ? join('/', (@o[0 .. 2], map {''} ( 4 .. ( $num_path_seg - $max_path_seg ))), '...', @o[$#o - 1 .. $#o ] ) : $path_base;
297             my $path_abbrev = ( $num_path_seg > $max_path_seg ) ? join('/', @o[0 .. 2], '...', @o[$#o - 1 .. $#o ] ) : $path_base;
298              
299             #my $xxx = $intlog;
300             #$xxx->write('STDERR', '%ENV{BIG_WARN_ON_XXX}: ', { map { $_ => ( $ENV{"BIG_WARN_ON_$_"} || 0 ) } keys%BIG_WARN_DEFAULTS } );
301             #$xxx->write('STDERR', '%BIG_WARN_DEFAULTS: ', \%BIG_WARN_DEFAULTS );
302             #$xxx->write('STDERR', '%BIG_WARN_ON: ', \%BIG_WARN_ON );
303              
304             # we don't normally want a stack trace on every log call
305             # enable on any particular call with: $intlog->write({st=>1},$lll, ':');
306             # enable on all calls with: $log->stack_trace( 1 );
307              
308              
309             *always_log = \*ALWAYS_LOG;
310             sub ALWAYS_LOG {
311 1     1 0 6 my $self = shift;
312 1         2 my $log_level = shift;
313 1 50       50 $log_level or return %ALWAYS_LOG;
314 0         0 $log_level =~ s/^D_//;
315 0         0 return $ALWAYS_LOG{$log_level};
316             }
317              
318              
319             #$intlog->write($lll, '%LOG_CODE: ', "\n", map { (space($_->[0]), ' => ', pad( $_->[1]), "\n") } sort { $a->[1] <=> $b->[1]; } map { [ $_ => $LOG_CODE{$_} ]; } keys %LOG_CODE );
320             #$intlog->packages('!' . $this_package); # uncomment this to disable all internal logging
321              
322             $ENV{LOG_PACKAGES} ||= '';
323             if ( $ENV{LOG_PACKAGES} ) {
324             $log->packages($ENV{LOG_PACKAGES});
325             $intlog->packages($ENV{LOG_PACKAGES});
326             }
327              
328              
329             # the following two sets of exported variables/subs are for development debugging purposes and are
330             # filtered out at compile time, unless $ENV{LOG_FILTER} is appropriately set. I'm thinking that since
331             # these are for development debugging that they should maybe have some different significance when
332             # it comes to descriptive output. Currently all log messages output the &{$log->{prefix}}(). Perhaps
333             # we should use a bitmask to determine whether or not a log should be output and additionally what
334             # kind of prefix it has. This would allow these to mimic the "production" log levels (in value)
335             # while also allowing us to have more descriptive prefix (caller, etc...) when they are used for
336             # development debugging
337              
338             *log_code = \*LOG_CODE;
339             sub LOG_CODE {
340 1     1 0 15 my $self = shift;
341 1         5 my $log_level = shift;
342 1 50       26 $log_level or return %LOG_CODE;
343 0         0 $log_level =~ s/^D_//;
344 0         0 return $LOG_CODE{$log_level};
345             }
346              
347 0 0   0 1 0 sub n { exists $_[1] ? $_[0]->{ n } = $_[1] : $_[0]->{ n }; }
348 0 0   0 1 0 sub log { exists $_[1] ? $_[0]->{ log } = $_[1] : $_[0]->{ log }; }
349             #sub log {
350             # if ( $_[0] and UNIVERSAL::isa( $_[0], __PACKAGE__ ) ) {
351             # return exists $_[1] ? $_[0]->{ log } = $_[1] : $_[0]->{ log };
352             # } else {
353             # return $log;
354             # }
355             #}
356 62 50   62 1 35912 sub log_level { exists $_[1] ? $_[0]->{ log_level } = $_[1] : $_[0]->{ log_level }; }
357 6 50   6 1 41 sub dump_refs { exists $_[1] ? $_[0]->{ dump_refs } = $_[1] : $_[0]->{ dump_refs }; }
358 7 50   7 1 74 sub handle_fatals { exists $_[1] ? $_[0]->{ handle_fatals } = $_[1] : $_[0]->{ handle_fatals }; }
359 6 50   6 1 42 sub exclusive { exists $_[1] ? $_[0]->{ exclusive } = $_[1] : $_[0]->{ exclusive }; }
360 0 0   0 1 0 sub stack_trace { exists $_[1] ? $_[0]->{ stack_trace } = $_[1] : $_[0]->{ stack_trace }; }
361 0 0   0 1 0 sub email { exists $_[1] ? $_[0]->{ email } = $_[1] : $_[0]->{ email }; }
362 2 50   2 1 19 sub prefix { exists $_[1] ? $_[0]->{ prefix } = $_[1] : $_[0]->{ prefix }; }
363 0 0   0 0 0 sub terse { exists $_[1] ? $_[0]->{ terse } = $_[1] : $_[0]->{ terse }; }
364 6 50   6 0 37 sub unbuffer { exists $_[1] ? $_[0]->{ unbuffer } = $_[1] : $_[0]->{ unbuffer }; }
365             *autoflush = \&unbuffer;
366             sub log_file {
367             # this needs to be able to take a file handle as well as a filename or symbolic filehandle name (eg 'STDOUT')
368             # I was going to set up something here to be able to pass in a whole list of LEVEL => $file pairs, but on second though, just call the method repeatedly
369 56     56 1 321 my $self = shift;
370 56   50     110 my $level = shift || '';
371             #my @caller = _caller();
372             # print STDERR __LINE__, "-" x 80, "\n", @caller, "\n";# if $ENV{LOG_PACKAGES_DEBUG};
373             # print STDERR __LINE__, " LEVEL=$level\n";# if $ENV{LOG_PACKAGES_DEBUG};
374 56   100     119 my $dest = shift || '';
375             # print STDERR __LINE__, " DEST=$dest\n";# if $ENV{LOG_PACKAGES_DEBUG};
376 56         61 my $key = 'log_file';
377             # print STDERR __LINE__, " KEY=$key\n";# if $ENV{LOG_PACKAGES_DEBUG};
378 56 100       207 my $valid_level = scalar map { $_ eq $level ? 1 : (); } LOG_LEVELS() if $level;
  3136 50       5071  
379 56 100 66     449 if ( $level and not $valid_level ) {
    50 33        
380 8 50       21 if ( $dest ) {
381             #houston we have a problem
382             } else {
383 8         14 $dest = $level;
384             }
385             } elsif ( $level and $valid_level ) {
386 48         85 $key .= "_$level";
387             }
388            
389 56 50       111 if ( $dest ) {
390 56         168 $self->{$key} = $dest;
391             }
392             # print STDERR __LINE__, " VALID_LEVEL=$valid_level\n";# if $ENV{LOG_PACKAGES_DEBUG};
393             # print STDERR __LINE__, " LEVEL=$level\n";# if $ENV{LOG_PACKAGES_DEBUG};
394             # print STDERR __LINE__, " DEST=$dest\n";# if $ENV{LOG_PACKAGES_DEBUG};
395             # print STDERR __LINE__, " KEY=$key\n";# if $ENV{LOG_PACKAGES_DEBUG};
396             # print STDERR __LINE__, " RETURN=$self->{$key}\n";# if $ENV{LOG_PACKAGES_DEBUG};
397             # print STDERR __LINE__, "-" x 80, "\n";# if $ENV{LOG_PACKAGES_DEBUG};
398 56         383 return $self->{$key};
399             }
400             sub log_file_multiplex {
401 0     0 0 0 my $self = shift;
402             # I should change this to accept filehandles as well
403 0 0       0 if ( scalar @_ > 2 ) {
404 0         0 die "
405             Called with too many arguments
406             the several ways this could be called, maximum of 2 arguments allowed
407             0: () ===> with no arguments, return the log_file unadorned with a specific log_level
408             1: ===> set the log_file for any LEVEL not otherwise spoken for to the specified FILE (or 'STDERR', 'STDOUT')
409             2: ===> return the log_file for the LEVEL specified
410             3: [ , ] ===> set the log_file for any LEVEL not otherwise spoken for to be multiplexed across the specified files in list [ FILE1, FILE2, ..., FILEn]
411             4: [ , , ..., ] ===> return the log_file for the list of LEVELs specified
412             5: => ===> set the log_file for the LEVEL specified to FILE
413             6: => [ , , ..., ] ===> set the log_file for the LEVEL specified to multiplex across files in list [ FILE1, FILE2, ..., FILEn]
414             7: [ , ] => ===> set the log_file for the LEVELS specified to the same file FILE
415             8: [ , ] => [ , , ..., ] ===> set the log_file for the LEVELS specified to multiplex across files in list [ FILE1, FILE2, ..., FILEn]
416             ";
417             }
418 0         0 my $key = 'log_file';
419             #$key = 'log_file_multiplex';
420            
421 0   0     0 my $level = shift || '';
422 0   0     0 my $dest = shift || '';
423 0 0 0     0 if ( not $level and not $dest ) {
424             ######
425 0         0 return $self->{$key};
426             ######
427             ######################################
428             }
429            
430 0         0 my $reflevel;
431             my $refdest;
432 0 0       0 unless ( ref $level eq 'ARRAY' ) {
433 0         0 $reflevel = 0;
434 0         0 $level = [ $level ];
435             } else {
436 0         0 $reflevel = 1;
437             }
438            
439 0 0 0     0 if ( $level and not $dest ) {
440             # check to see if this is specifying just a level, or just a dest
441 0 0       0 my $valid_level = scalar map { $_ eq $level->[0] ? 1 : (); } LOG_LEVELS() if $level->[0];
  0 0       0  
442 0 0       0 if ( $valid_level ) {
443 0         0 my @return;
444 0         0 foreach my $l ( @$level ) {
445 0 0       0 my $vl = scalar map { $_ eq $l ? 1 : (); } LOG_LEVELS();
  0         0  
446 0 0       0 unless ( $vl ) {
447 0         0 die "
448             Something is awry with the arguments you passed:
449             " . join(', ', @$level ) . "
450             ";
451             } else {
452 0         0 push @return, $self->{$key}{$l};
453             }
454             }
455             ######
456 0 0       0 return $reflevel ? \@return : $return[0];
457             ######
458             ######################################
459             } else {
460             # if the arg is not a valid log level then it must be a destination file or filehandle
461 0         0 $refdest = $reflevel;
462 0         0 $dest = $level;
463 0         0 undef $level;
464             }
465             }
466            
467 0 0       0 unless ( ref $dest eq 'ARRAY' ) {
468 0         0 $refdest = 0;
469 0         0 $dest = [ $dest ];
470             } else {
471 0 0       0 $refdest = defined $refdest ? $refdest : 0;
472             }
473            
474 0 0 0     0 if ( $dest and not $level ) {
475             # we got only one argument and it was a destination without the level specified
476             # this means by default we want to multiplex across the files given
477 0         0 $self->{$key} = $dest;
478             ######
479 0         0 return $self->{$key};
480             ######
481             ######################################
482             }
483            
484             # here we have both level and dest, which should each now be array refs
485 0         0 foreach my $l ( @$level ) {
486 0         0 my $k = "${key}_$l";
487 0         0 my $pd = $self->{$k};
488             # check to see where $pd and $dest do not agree, close all filehandles in$pd which are not also in $dest
489 0         0 $self->{$k} = $dest;
490             }
491 0         0 return $self->{$key};
492             }
493              
494             sub packages {
495             # this sets up lists of DO and DONT log for packages specified at runtime
496             # if any DO log lists are set up then we will log ONLY from packages who appear in the DO list EVEN IF they are also in the DONT list
497             # if any DONT log lists are set up then we will NEVER log from packages in the DONT log list UNLESS they are in the DO log list
498 0     0 0 0 my $self = shift;
499 0 0       0 if ( exists $_[0] ) {
500 0         0 my @new_packages = @_;
501 0   0     0 my $packages = $self->{packages_array} ||= [];
502 0   0     0 my $do_log = $packages->[0] ||= [];
503 0   0     0 my $dont_log = $packages->[1] ||= [];
504 0         0 foreach my $package_set ( @new_packages ) {
505 0         0 my @package_set = split(/\#/, $package_set );
506 0         0 foreach my $package ( @package_set ) {
507 0 0 0     0 next unless ($package and $package !~ /^\s+$/);
508 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$package: ' , $package, "\n" if $ENV{LOG_PACKAGES_DEBUG};
509 0 0       0 if ( $package =~ s/^\!// ) {
510             #it's a dont
511 0 0       0 unless( grep { /^$package$/ } @$dont_log ) {
  0         0  
512 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", 'DONT ::: $package: \'' , $package, "'\n" if $ENV{LOG_PACKAGES_DEBUG};
513 0         0 push @$dont_log, $package;
514             }
515             } else {
516 0 0       0 unless( grep { /^$package$/ } @$do_log ) {
  0         0  
517 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", 'DO ::: $package: \'' , $package, "'\n" if $ENV{LOG_PACKAGES_DEBUG};
518 0         0 push @$do_log, $package;
519             }
520             }
521             }
522             }
523 0 0       0 if ( my $packages = $self->{packages_array} ) {
524 0         0 my $do_log = $packages->[0];
525 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$do_log: ' , scalar @$do_log , " :: '", join('|', @$do_log) , "'\n" if $ENV{LOG_PACKAGES_DEBUG};
526 0         0 my $dont_log = $packages->[1];
527 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$dont_log: ', scalar @$dont_log, " :: '", join('|', @$dont_log), "'\n" if $ENV{LOG_PACKAGES_DEBUG};
528 0   0     0 my $packages_rx = $self->{packages} ||= [];
529 0 0       0 my $do_log_rx = scalar @$do_log ? [ map { qr/$_/; } @$do_log ] : []; #scalar @$do_log ? join('|', @$do_log ) : undef;
  0         0  
530 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$do_log_rx: ' , scalar @$do_log_rx , " :: '", join('|', @$do_log_rx) , "'\n" if $ENV{LOG_PACKAGES_DEBUG};
531 0 0       0 my $dont_log_rx = scalar @$dont_log ? [ map { qr/$_/; } @$dont_log ] : []; #scalar @$dont_log ? join('|', @$dont_log ) : undef;
  0         0  
532 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$dont_log_rx: ', scalar @$dont_log_rx, " :: '", join('|', @$dont_log_rx), "'\n" if $ENV{LOG_PACKAGES_DEBUG};
533 0         0 $packages_rx->[0] = $do_log_rx;
534 0         0 $packages_rx->[1] = $dont_log_rx;
535             }
536             }
537 0         0 return $self->{packages};
538             }
539              
540             sub clone {
541 0     0 1 0 my $self = shift;
542 0         0 my $VAR1 = $self->dump( @_ );
543 0         0 my $clone = eval $VAR1;
544 0 0 0     0 $clone->{prefix} = $self->{prefix} if ( UNIVERSAL::isa( $clone, $this_package ) and ref $self->{prefix} eq 'CODE' );
545 0         0 return $clone;
546             }
547              
548              
549              
550             #print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY! ... ", $log->dump([ \@_ ]);
551             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $log->dump([ \@_ ]);
552             sub new {
553             #print STDERR _caller();
554 6     6 0 17 my $self = shift;
555 6   33     35 my $class = ref $self || $self || $this_package;
556 6         25 $self = bless {}, $class;
557 6         27 $self->init( @_ );
558 6         16 return $self;
559             }
560              
561             sub init {
562 6     6 0 11 my $self = shift;
563 6         7 my $init = shift;
564 6 100       23 if ( defined $init ) {
565 4 50       17 unless ( ref $init eq 'HASH' ) {
566 0         0 unshift @_, $init;
567 0         0 $init = { @_ };
568             }
569             } else {
570 2         5 $init = {};
571             }
572 6         66 $init = { %init , %$init }; # override defaults with init args passed in
573 6         44 while ( my ( $key, $value ) = each %$init ) {
574 37 50       69 next unless $key;
575             #$self->{$key} = $value;
576 37         120 $self->$key( $value );
577             }
578 6         30 while ( my ( $level, $fh ) = each %LEVEL_FHS ) {
579 48         100 $self->log_file( $level => $fh );
580             }
581             #print STDERR "$self: ", &dump( $self, -d => $self );
582 6         27 return $self;
583             };
584              
585             sub dump {
586 0     0 0 0 my $DUMP = '';
587 0         0 my $self = shift;
588 0 0       0 (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), Dumper(\@_), "\n") if $ENV{LOG_INTERNAL_DUMP_DEBUG};
589 0   0     0 my $class = ref $self || $self;
590 0         0 my ( $dumps, $names );
591 0         0 my ( $pure, $deep, $indent, $id, $terse, $pad, $deparse );
592 0 0 0     0 if ( $_[0] and $_[0] =~ /^-/ ) {
593 0         0 my $args = { @_ };
594 0   0     0 $dumps = $args->{-d} || $args->{-dump} || $self;
595 0   0     0 $names = $args->{-n} || $args->{-names} || undef;
596 0 0       0 $dumps = [ $dumps ] unless ( ref $names eq 'ARRAY' );
597 0   0     0 $pure = $args->{-pure} || 0 ;
598 0   0     0 $deep = $args->{-deep} || 0 ;
599 0 0       0 $indent = ( defined $args->{-indent} ? $args->{-indent} : $default_indent );
600 0   0     0 $id = $args->{-id} || 0;
601 0   0     0 $terse = $args->{-terse} || 0 ;
602 0   0     0 $pad = $args->{-p} || $args->{-pad} || ' ' x $default_pad;
603 0   0     0 $deparse = $args->{-deparse} || 0;
604 0 0 0     0 if ( $terse and not defined $indent ) {
605 0         0 $indent = 0;
606             }
607             } else {
608 0   0     0 $dumps = shift || $self;
609 0   0     0 $names = shift || undef;
610 0   0     0 $pure = shift || 0;
611 0   0     0 $deep = shift || 0;
612 0   0     0 $indent = shift || $default_indent;
613 0   0     0 $id = shift || 0;
614 0   0     0 $terse = shift || 0;
615 0   0     0 $pad = shift || ' ' x $default_pad;
616 0   0     0 $deparse = shift || 0;
617             }
618 0 0       0 (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), Dumper([( $pure, $deep, $indent, $id, $terse)]), "\n") if $ENV{LOG_INTERNAL_DUMP_DEBUG};
619            
620 0 0 0     0 ( defined $dumps ) and ( ref $dumps eq 'ARRAY' ) or ( $dumps = [ $dumps ] );
621 0 0 0     0 ( defined $names ) and ( ref $names eq 'ARRAY' ) or ( $names = [ $names ] );
622 0 0       0 if ( $id ) {
623 0         0 for( my $i = 0; $i <= $#$dumps; $i++ ) {
624 0         0 my $d = $dumps->[$i];
625 0 0       0 my $n = ref $d ? $d : \$d;
626 0         0 $names->[$i] = $n;
627             }
628             }
629 0         0 my $dumper = Data::Dumper->new( $dumps , $names );
630 0 0       0 $dumper->Pad ( $pad ) if defined $pad;
631 0 0       0 $dumper->Purity ( $pure ) if defined $pure;
632 0 0       0 $dumper->Deepcopy( $deep ) if defined $deep;
633 0 0       0 $dumper->Terse ( $terse ) if defined $terse;
634 0 0       0 $dumper->Indent ( $indent ) if defined $indent;
635 0 0       0 $dumper->Deparse ( $deparse ) if defined $deparse;
636 0         0 $DUMP = $dumper->Dump();
637 0         0 return $DUMP
638             }
639              
640              
641             #sub _prepare_message {
642             # my $self = shift;
643             # my $level = shift;
644             # my $args = shift;
645             # my @inmsg = @_;
646             # my $dump_refs = exists $args->{dump_refs} ? $args->{dump_refs}
647             # : exists $self->{dump_refs} ? $self->{dump_refs}
648             # : $level eq 'SPEW';
649             # my @outmsg = ();
650             # my $tmp;
651             #
652             # $level = $args->{level} || $level;
653             # my $log_level = $args->{log_level} || $self->{log_level} || $ENV{LOG_LEVEL};
654             # print STDERR __LINE__, " LOG_LEVEL='$log_level', LEVEL='$level', \$args->{prefix}='$args->{prefix}'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
655             # my $prefix = exists $args->{prefix} ? $args->{prefix}
656             # : $log_level =~ /^D_/ ? \&_prefix_dev
657             # : $level =~ /CLEAN/ ? ''
658             # : defined $self->{prefix} ? $self->{prefix}
659             # : $level =~ /^D/ ? \&_prefix_dev
660             # : $log_level =~ /(SPEW)/ ? \&_prefix_dev
661             # #: $level =~ /QUIT/ ? \&_prefix_dev
662             # : $level =~ /CRIT/ ? \&_prefix_dev
663             # : $level =~ /FATAL/ ? \&_prefix_dev
664             # : $level =~ /FAIL/ ? \&_prefix_dev
665             # : \&_prefix_default;
666             # my @prefix;
667             # my @prefix_out;
668             # my $add_dev_prefix;
669             # my $log_file = $args->{log_file} || $self->log_file( $level ) || $self->log_file();
670             # if ( exists $args->{prefix}
671             # and $log_level =~ /^D_/
672             # and $log_file =~ /^(STDOUT|STDERR)$/
673             # ) {
674             # $add_dev_prefix = 1;
675             # }
676             # push @prefix, \&_prefix_dev if $add_dev_prefix;
677             # push @prefix, $prefix if defined $prefix;
678             # # really we should have somethings that checks the %args for ALL of the possible settings
679             # my $st = $STACK_TRACE;
680             # $STACK_TRACE = exists $args->{stack_trace} ? $args->{stack_trace}
681             # : defined $self->{stack_trace} ? $self->{stack_trace}
682             # : $STACK_TRACE;
683             #
684             # my $code_resolve_cnt_max = 10;
685             # foreach my $p ( @prefix ) {
686             # my $code_resolve_cnt = 0;
687             # CORE_PREFIX:
688             # while ( ref $p eq 'CODE' ) {
689             # $p = &$p( $level, $args );
690             # last CODE_PREFIX if ( $code_resolve_cnt++ > $code_resolve_cnt_max );
691             # }
692             # unshift @inmsg, $p;
693             # #unshift @prefix_out, $p;
694             # }
695             # $STACK_TRACE = $st;# restore the previous setting
696             #
697             # # my $prefix_length = [ split("\n", join( '', @prefix_out)) ];
698             # # $prefix_length = $prefix_length->[-1];
699             # # $prefix_length = length $prefix_length;
700             # my ($msg, $d);
701             # INMSG: while ( scalar @inmsg ) {
702             # $tmp = undef;
703             # $msg = shift @inmsg;
704             # defined $msg or $msg = 'undef';#'(UNDEFINED ELEMENT IN LOG MESSAGE ARGUMENTS)';
705             # my $code_resolve_cnt = 0;
706             # CHECK_REF:
707             # if (( my $ref = ref $msg ) and $dump_refs ) {
708             # # this next line of cruft is here so you can pass arguments to ->dump() without having to prepend with a minus sign
709             # my @extra_args = map { $_ =~ /^(terse|deep|pure|id|indent)$/ ? ( "-$_" => $args->{$_} ) : ( $_ => $args->{$_} ) } keys %$args;
710             # (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@extra_args], -n =>['extra_args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
711             # if ( $ref eq 'CODE' ) {
712             # $d = &$msg();
713             # $msg = $d;
714             # goto CHECK_REF unless ( ref $msg eq 'CODE' and $code_resolve_cnt++ > $code_resolve_cnt_max );
715             # } else {
716             # #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length + length $msg) ));
717             # #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length) ));
718             # #$d =~ s/^\s+//;
719             # #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x $prefix_length ) );
720             # #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
721             # $d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
722             # }
723             # $msg = $d;
724             # }
725             # push @outmsg, $msg;
726             # }
727             # if ( $add_dev_prefix
728             # and $outmsg[-1] !~ /\n$/ms
729             # ) {
730             # push @outmsg, "\n";
731             # };
732             # return @outmsg;
733             #}
734              
735             *_prefix_default = \&_prefix_prod;
736              
737             sub _time {
738 926     926   26539 my @lt = localtime();
739             #( 0, 1, 2, 3, 4, 5, 6, 7, 8)
740             #($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
741 926 50       3758 join('',$lt[5]+1900, map { length $_ < 2 ? "0$_" : $_; } (($lt[4]+1),($lt[3])) ) . ' ' . join('', map { length $_ < 2 ? "0$_" : $_;} @lt[2,1,0]),
  1852 100       7590  
  2778         9659  
742             }
743              
744             sub _prefix_prod {
745 926 50   926   2542 print STDERR __LINE__, " 'prefix_prod'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
746 926         1132 my $level = shift;
747 926         4223 return '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  2778         77120  
748             "$username\@$hostname:$$",
749             _time(),
750             uc $level
751             )."] "
752             ;
753             }
754              
755             sub _prefix_brief {
756 0 0   0   0 print STDERR __LINE__, " 'prefix_brief'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
757 0         0 my $level = shift;
758 0         0 return '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  0         0  
759             "$username\@$hostname:$$",
760             _time(),
761             )."] "
762             ;
763             }
764              
765             sub _prefix_dev {
766 926 50   926   2304 print STDERR __LINE__, " 'prefix_dev_long'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
767 926         1219 my $level = shift;
768 926         937 my $args = shift;
769 926   50     3171 my $backstack = $args->{backstack} || 0;
770             #"$username\@$hostname:$$:$path_abbrev:$path_base",
771 926         3355 my $return = '--['.join("]\n--[",map { space(pad($_, $p_pad), $p_space), }
  1852         59613  
772             #__PACKAGE__->_caller($backstack + 3), # we need a 3 here to ignore (skip over) the subroutine calls within the logging module itself
773             # was 3 before we inlined something
774             __PACKAGE__->_caller($backstack + $prefix_dev_backstack), # we need a 2 here to ignore (skip over) the subroutine calls within the logging module itself
775             )."] "
776             . "\n"
777             ;
778 926         3621 $return .= _prefix_prod( $level, $args, @_ );
779 926 100       4147 $return .= "\n" if ( $level =~ /CLEAN/ );
780 926         2239 return $return;
781             }
782              
783             my %level_cache = ();
784             sub _check_level {
785 0     0   0 my $self = shift;
786 0         0 my $msg = shift;
787 0         0 my $args = {};
788 0         0 my $level = shift @$msg;
789 0 0 0     0 ref $level eq 'HASH'
790             and ($args=$level)
791             and $level=shift @$msg;
792 0         0 my $map_level = $level;
793 0         0 $map_level =~ s/^D_//;
794             #print "LEVEL : '$level'\n";
795             #print "MAP_LEVEL: '$map_level'\n";
796 0   0     0 $args->{log_file} ||= $self->{"log_file_$level"} || $self->{"log_file"};
      0        
797 0   0     0 my $log_level = $args->{log_level} ||= $self->{log_level} || DEFAULT;
      0        
798 0         0 my $map_log_level = $log_level;
799 0         0 $map_log_level =~ s/^D_//;
800 0         0 my ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
801 0 0       0 print STDERR "\nLEVELS: $log_level:$map_log_level:$_log_level ... $level:$map_level:$_level\n" if $ENV{LOG_LEVEL_DEBUG};
802            
803 0 0       0 if ( not defined $_level ) {
804 0         0 $intlog->write({stack_trace => 1 }, ERROR, "Illegal log level '$level' setting it to 'DEFAULT'");
805 0         0 unshift @$msg, ( $level = 'DEFAULT' );
806 0 0       0 return $self->_check_level( $msg ) unless exists $level_cache{$level};
807 0         0 $intlog->write( ERROR, "Illegal log level '$level' trouble setting it to $level");
808 0         0 return undef;
809             }
810            
811 0         0 my @return = ($level, $_level, $log_level, $_log_level, $args);
812             #_actually_log( $self, -level => LOUD, -FH => \*STDOUT, -message => \@return );
813 0         0 return @return;
814             }
815              
816             sub write {
817             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $intlog->dump([ \@_ ]);
818            
819             # print STDERR $this_package," :: ", join(', ', caller()), "\n";
820 12545     12545 1 1787745 my $self = shift;
821 12545 50       28076 ref $self or $self = $log;
822 12545 50       29135 (print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [$_[0]], -n =>['_args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
823 12545         30697 my @msg = @_;
824             #my ($level, $_level, $log_level, $_log_level, $args) = $self->_check_level( \@msg );
825 12545         12648 my ($level, $_level, $log_level, $_log_level, $args);
826 0         0 my $use_level;
827 0         0 my $map_level;
828 12545         17081 CHECK_LEVEL:
829             #sub _check_level {
830             {
831             #my $self = shift;
832             #my $msg = shift;
833 12545         10579 my $msg = \@msg;
834             #my $args = {};
835 12545         17699 $args = {};
836             #my $level = shift @$msg;
837 12545         16319 $level = shift @$msg;
838 12545 100 66     46913 ref $level eq 'HASH'
839             and ($args=$level)
840             and $level=shift @$msg;
841              
842 12545   33     45269 $use_level = $args->{level} || $level;
843 12545         12432 $map_level = $use_level;
844 12545         33918 $map_level =~ s/^D_//;
845             #print "LEVEL : '$level'\n";
846             #print "MAP_LEVEL: '$map_level'\n";
847 12545   33     52858 $args->{log_file} ||= $self->{"log_file_$level"} || $self->{"log_file"};
      66        
848 12545   50     57872 $log_level = $args->{log_level} || $self->{log_level} || $ENV{LOG_LEVEL} || 'DEFAULT';
849 12545         12236 my $map_log_level = $log_level;
850 12545         19130 $map_log_level =~ s/^D_//;
851             #my ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
852 12545         27148 ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
853 12545 50       26752 print STDERR "\nLEVELS: $log_level:$map_log_level:$_log_level ... $level:$map_level:$_level\n" if $ENV{LOG_LEVEL_DEBUG};
854            
855 12545 50       29091 if ( not defined $_level ) {
856 0         0 $intlog->write({stack_trace => 1 }, ERROR, "Illegal log level '$level' setting it to 'DEFAULT'");
857 0         0 unshift @$msg, ( $level = 'DEFAULT' );
858             #return $self->_check_level( $msg ) unless exists $level_cache{$level};
859 0 0       0 if ( not exists $level_cache{$level} ) {
860 0         0 goto CHECK_LEVEL;
861             #($level, $_level, $log_level, $_log_level, $args) = $self->_check_level( $msg );
862             } else {
863 0         0 $intlog->write( ERROR, "Illegal log level '$level' trouble setting it to $level");
864 0         0 return undef;
865             }
866             }
867            
868             # my @return = ($level, $_level, $log_level, $_log_level, $args);
869             # #_actually_log( $self, -level => LOUD, -FH => \*STDOUT, -message => \@return );
870             # return @return;
871             }
872             # this needs to be set up to log at any of severa levels which may be set simultaneously
873             # eg log at WARN and TRACE
874             # log levels should be a list
875             # ie @_log_levels rather than $_log_level
876 12545   50     42221 my $backstack = $args->{backstack} || 0;
877 12545         15265 my $return = \@msg;
878 12545         12135 my $status = 1;
879 12545 50       26715 (print STDERR 'XXXXXX ', $this_package, " STDERR ", __LINE__, " ::: OH MY! status=$status ... \$ALWAYS_LOG{$map_level}: '", $ALWAYS_LOG{$map_level}, "' :: ", __PACKAGE__->_caller(), $self->dump(-d=> [$args], -n =>['args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
880 12545 100       26337 if( not $ALWAYS_LOG{$map_level} ) {
881 8400 50       18623 if ( my $e = $self->{exclusive} ) {
882 0 0       0 $level =~ /$e/
883             or $status = 0;# or return join( '', @$return );
884             } else {
885 8400 100       18236 $_level >= $_log_level
886             or $status = 0;
887             #or return join( '', map { defined $_ ? $_ : 'undef' } @$return );
888             }
889             }
890 12545 50       24235 (print STDERR 'XXXXXX ', $this_package, " STDERR ", __LINE__, " ::: OH MY! status=$status ... \$ALWAYS_LOG{$map_level}: '", $ALWAYS_LOG{$map_level}, "' :: ", __PACKAGE__->_caller(), $self->dump(-d=> [$args], -n =>['args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
891 12545 50 66     35141 if ( #not $ALWAYS_LOG{$map_level} and
892             $status
893             and my $packages = $self->{packages}
894             ) {
895 0         0 my $do_match;
896             my $dont_match;
897 0         0 my $do_log_rx = $packages->[0];
898 0         0 my $dont_log_rx = $packages->[1];
899              
900 0         0 my $log_called_package = _log_called_package(1)->[0];
901             #print STDERR __PACKAGE__, ":", __LINE__, ": ", "LOG CALLED PACKAGE: '$log_called_package'\n";
902 0 0       0 if ( scalar @$do_log_rx ) {
903 0         0 foreach my $do_rx ( @$do_log_rx ) {
904 0 0       0 if ( $log_called_package =~ /^($do_rx)$/ ) {
905             #print STDERR "DO LOG: $do_log_rx\n";
906             #$do_match = ( $do_match and length $do_match > length $do_rx ) ? $do_match : $do_rx;
907 0         0 $do_match = $do_rx;
908             }
909             }
910 0 0       0 $do_match or $status = 0;
911             }
912            
913 0 0 0     0 if ( $status and scalar @$dont_log_rx ) {
914 0         0 foreach my $dont_rx ( @$dont_log_rx ) {
915 0 0 0     0 if ( $status
916             #and not $do_match
917             #and ( not $do_match or ( $dont_log_rx =~ /$do_log_rx/ ))
918             and $log_called_package =~ /^($dont_rx)$/
919             ) {
920             #$dont_match = ( $dont_match and length $dont_match > length $dont_rx ) ? $dont_match : $dont_rx;
921 0         0 $dont_match = $dont_rx;
922 0         0 $status = 0;
923             }
924             }
925             }
926            
927 0 0 0     0 if ( $do_match and $dont_match ) {
928             # if it matches on both DO and DONT, what are we supposed to do? Here we simply say that the match with the lengthiest regex wins
929 0 0       0 $status = ( length $do_match > length $dont_match ) ? 1 : 0 ;
930 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", "DO status=$status ($do_match): $do_log_rx\n" if $ENV{LOG_PACKAGES_DEBUG};
931 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", "DONT status=$status ($dont_match): $dont_log_rx\n" if $ENV{LOG_PACKAGES_DEBUG};
932             }
933             }
934            
935 12545 50       25585 print STDERR __LINE__, " LOG_LEVEL='$log_level', LEVEL='$level', MAP_LEVEL='$map_level', \$args->{prefix}='$args->{prefix}'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
936 12545 100       20574 if ( $status ) {
937             #warn "STATUS: $status ::: $level:$_level ... $log_level:$_log_level";
938             # this is an effort at in-lining some subroutines
939             #@msg = $self->_prepare_message( $level, $args, @msg );
940             #sub _prepare_message {
941             {
942             # my $self = shift;
943             # my $level = shift;
944             # my $args = shift;
945             # my @inmsg = @_;
946 4989         4306 my @inmsg = @msg;
  4989         9901  
947 4989 50       15838 my $dump_refs = exists $args->{dump_refs} ? $args->{dump_refs}
    50          
948             : exists $self->{dump_refs} ? $self->{dump_refs}
949             : $level eq 'SPEW';
950 4989         5822 my @outmsg = ();
951 4989         4972 my $tmp;
952            
953 4989 0       25639 my $prefix = exists $args->{prefix} ? $args->{prefix}
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    50          
954             : $log_level =~ /^D_/ ? \&_prefix_dev
955             : $use_level =~ /CLEAN/ ? ''
956             : defined $self->{prefix} ? $self->{prefix}
957             : $use_level =~ /^D/ ? \&_prefix_dev
958             : $log_level =~ /SPEW/ ? \&_prefix_dev
959             #: $use_level =~ /QUIT/ ? \&_prefix_dev
960             : $use_level =~ /CRIT/ ? \&_prefix_dev
961             : $use_level =~ /FATAL/ ? \&_prefix_dev
962             : $use_level =~ /FAIL/ ? \&_prefix_dev
963             : \&_prefix_default;
964 4989         5130 my @prefix;
965             my @prefix_out;
966 0         0 my $add_dev_prefix;
967 4989   33     11911 my $log_file = $args->{log_file} || $self->log_file( $level ) || $self->log_file();
968 4989 0 33     12190 if ( exists $args->{prefix}
      33        
969             and $log_level =~ /^D_/
970             and $log_file =~ /^(STDOUT|STDERR)$/
971             ) {
972 0         0 $add_dev_prefix = 1;
973             }
974 4989 50       8724 push @prefix, \&_prefix_dev if $add_dev_prefix;
975 4989 50       14012 push @prefix, $prefix if defined $prefix;
976 4989         5401 my $code_resolve_cnt = 0;
977 4989         4617 my $code_resolve_cnt_max = 10;
978             # really we should have somethings that checks the %args for ALL of the possible settings
979 4989         4626 my $st = $STACK_TRACE;
980 4989 50       13800 $STACK_TRACE = exists $args->{stack_trace} ? $args->{stack_trace}
    50          
981             : defined $self->{stack_trace} ? $self->{stack_trace}
982             : $STACK_TRACE;
983            
984 4989         7473 foreach my $p ( @prefix ) {
985             CODE_PREFIX:
986 4989         11426 while ( ref $p eq 'CODE' ) {
987 926         2190 $p = &$p( $level, $args );
988 926 50       3701 last CODE_PREFIX if ( $code_resolve_cnt++ > $code_resolve_cnt_max );
989             }
990 4989         14426 unshift @inmsg, $p;
991             #unshift @prefix_out, $p;
992             }
993 4989         6873 $STACK_TRACE = $st;# restore the previous setting
994              
995             # my $prefix_length = [ split("\n", join( '', @prefix_out)) ];
996             # $prefix_length = $prefix_length->[-1];
997             # $prefix_length = length $prefix_length;
998 4989         4323 my ($msg, $d);
999 4989         9561 INMSG: while ( scalar @inmsg ) {
1000 14966         14497 $tmp = undef;
1001 14966         15652 $msg = shift @inmsg;
1002 14966 50       24008 defined $msg or $msg = 'undef';#'(UNDEFINED ELEMENT IN LOG MESSAGE ARGUMENTS)';
1003 14966         12300 my $code_resolve_cnt = 0;
1004             CHECK_REF:
1005 14966 50 33     30821 if (( my $ref = ref $msg ) and $dump_refs ) {
1006             # this next line of cruft is here so you can pass arguments to ->dump() without having to prepend with a minus sign
1007 0 0       0 my @extra_args = map { $_ =~ /^(terse|deep|pure|id|indent|deparse)$/ ? ( "-$_" => $args->{$_} ) : ( $_ => $args->{$_} ) } keys %$args;
  0         0  
1008 0 0       0 (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@extra_args], -n =>['extra_args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
1009 0 0       0 if ( $ref eq 'CODE' ) {
1010 0         0 $d = &$msg();
1011 0         0 $msg = $d;
1012 0 0 0     0 goto CHECK_REF unless ( ref $msg eq 'CODE' and $code_resolve_cnt++ > $code_resolve_cnt_max );
1013             } else {
1014             #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length + length $msg) ));
1015             #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length) ));
1016             #$d =~ s/^\s+//;
1017             #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x $prefix_length ) );
1018             #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
1019 0         0 $d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -xxindent => 1, -deparse => 1, @extra_args );
1020             }
1021 0         0 $msg = $d;
1022             }
1023 14966         29827 push @outmsg, $msg;
1024             }
1025 4989 0 33     10582 if ( $add_dev_prefix
      33        
1026             and $outmsg[-1] !~ /\n$/ms
1027             and not defined $args->{n}
1028             ) {
1029 0         0 push @outmsg, "\n";
1030             };
1031             #return @outmsg;
1032 4989         16208 @msg = @outmsg;
1033             }
1034              
1035 4989 100 50     16212 $n = exists $args->{n} ? $args->{n} : ($self->{n} || "\n");
1036 4989 50       13088 (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY! ... \$ALWAYS_LOG{$use_level}: '", $ALWAYS_LOG{$use_level}, "' :: ", __PACKAGE__->_caller(), $self->dump(-d=> [$args], -n =>['args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
1037 4989 50       9516 unless ( $args->{dont_actually_log} ) {
1038             #$return = $self->_actually_log( %$args, -level => $use_level, -message => $return );
1039 4989         38749 %$args = ( %$args, -level => $level, -message => $return );
1040             #sub _actually_log {
1041             {
1042            
1043             #print STDERR $this_package, " ", __LINE__, " ::: OH MY! ... ", $_[0]->dump([ \@_ ]);
1044             #my $self = shift;
1045             #(warn $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@_], -n =>['_']), "\n") if $ENV{LOG_INTERNAL_DEBUG};
1046             #my $args = { @_ };
1047 4989   33     7149 $args->{-terse} ||= $self->{terse};
  4989         21141  
1048 4989   50     9872 $args->{-level} ||= INFO;
1049 4989   50     9995 $args->{-message} ||= ' - -- NO MESSAGE -- - ';
1050 4989         16382 my $fh = $self->fh( %$args );
1051 4989 50       9992 if ( not $fh ) {
1052 0         0 my $log_file = $self->log_file($args->{-level});
1053              
1054 0         0 my $error_level = FATAL;
1055 0 0       0 if ( not $log->handle_fatals() ) {
1056 0         0 $error_level = ERROR;
1057             }
1058 0         0 $intlog->write($error_level, "No filehandle for `", $args->{-level}, "' on `", $log_file, "'", \%FHS_NA);
1059 0 0       0 exit 1 if $log->handle_fatals();
1060             #return undef;
1061 0         0 $return = undef;
1062             }
1063             else {
1064             #print "MESSAGE: $message\n";
1065             #return $self->_WRITE( %$args, -FH => $fh );
1066 4989         20307 $return = $self->_WRITE( -FH => $fh, %$args );
1067             }
1068             };
1069              
1070 4989 50       11507 defined $return or $status = undef;
1071             }
1072             # if ( $use_level eq MESSAGE ) {
1073             # if ( my $email = $args->{email} ? $args->{email} : $self->{email} ) {
1074             # # we should send a message to the bloke?
1075             # } else {
1076             # #$intlog->write(ERROR, "No email address specified to send MESSAGE: $return");
1077             # $self->write(ALERT, "No email address specified to send MESSAGE: $return") unless $self->{DEBUG}{NO_ALERT};
1078             # }
1079             # }
1080 4989         6130 $n = undef;
1081             }
1082 12545 50       29269 ref $return eq 'ARRAY' and $return = join('', map { defined $_ ? $_ : 'undef' } @$return);
  33928 100       68370  
1083             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $intlog->dump([ \@_ ]);
1084 12545 100       132580 return wantarray ? ( $status, $return ) : $status ;
1085             }
1086              
1087             sub _actually_log {
1088             #print STDERR $this_package, " ", __LINE__, " ::: OH MY! ... ", $_[0]->dump([ \@_ ]);
1089 0     0   0 my $self = shift;
1090             #(warn $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@_], -n =>['_']), "\n") if $ENV{LOG_INTERNAL_DEBUG};
1091 0         0 my $args = { @_ };
1092 0   0     0 $args->{-terse} ||= $self->{terse};
1093 0   0     0 $args->{-level} ||= INFO;
1094 0   0     0 $args->{-message} ||= ' - -- NO MESSAGE -- - ';
1095 0         0 my $fh = $self->fh( %$args );
1096 0 0       0 unless ( $fh ) {
1097 0         0 my $log_file = $self->log_file($args->{-level});
1098              
1099 0         0 my $error_level = FATAL;
1100 0 0       0 if ( not $log->handle_fatals() ) {
1101 0         0 $error_level = ERROR;
1102             }
1103 0         0 $intlog->write($error_level, "No filehandle for `$args->{-level}' on $log_file");
1104             #exit 1;
1105 0         0 return undef;
1106             }
1107             #print "MESSAGE: $message\n";
1108 0         0 return $self->_WRITE( %$args, -FH => $fh );
1109             };
1110              
1111             #@f{qw(package filename line subroutine hasargs wantarray evaltext is_require hints bitmask )}=caller();
1112             my @showf = qw(package filename line subroutine hasargs wantarray evaltext is_require );
1113             sub called_from {
1114 0     0 0 0 my $self = shift;
1115 0 0 0     0 my $f = exists $_[0] ? (shift) : (( ref $self ? 2 : $self ) || 2);
1116 0         0 $intlog->write($dll, '$f: ', $f );
1117 0         0 my $lcpa = $self->_log_called_package( $f );
1118 0         0 $intlog->write($dll, '$lcpa: ', $lcpa );
1119 0         0 my $lcp = $lcpa->[0];
1120 0         0 $intlog->write($dll, '$lcp: ', $lcp );
1121 0         0 return $lcp;
1122             }
1123              
1124             sub _log_called_package {
1125 2778     2778   2909 my $self = shift;
1126 2778   50     9516 my $f = shift || ( ref $self ? 0 : $self ) || 0;
1127 2778         4374 my $nf = $f + 1;
1128 2778         3041 my $log_called_package = '';
1129 2778         2591 my $log_called_file = '';
1130 2778         3258 my @caller = ();
1131 2778         11255 my @f = caller($f);
1132 2778         4731 my ( $package, $filename, $line, $subroutine ) = @f;
1133             #print '( $package, $filename, $line, $subroutine ) = ', "( $package, $filename, $line, $subroutine ) [$f]\n";
1134 2778         6568 my @nf = caller($nf);
1135 2778         3373 my ( $npackage, $nfilename, $nline, $nsubroutine ) = @nf;
1136             #print '( $npackage, $nfilename, $nline, $nsubroutine ) = ', "( $npackage, $nfilename, $nline, $nsubroutine ) [$nf]\n";
1137 2778 100       5915 if ( $nsubroutine ) {
    100          
1138 926         2012 $log_called_package = "$nsubroutine:$line";
1139 926         1640 $log_called_file = "$filename:$line";
1140             } elsif ( $package ) {
1141 926         1621 $log_called_package = "$package:$line";
1142 926         1668 $log_called_file = "$filename:$line";
1143             }
1144 2778         9223 return [ $log_called_package, $log_called_file, \@f, \@nf ];
1145             }
1146              
1147             sub _caller {
1148 926     926   3312 my $self = shift;
1149 926   50     2080 my $f = shift || 0;
1150 926         1408 my @caller = ();
1151 926 50       2042 if ( $STACK_TRACE ) {
1152             # I wonder if there is a single call to give me a stack trace like I want, I know Carp will cluck() but why didn't I use that in the first place?
1153             # did I just do my own for some easier to read formatting?
1154 0         0 my $s = 0;
1155 0         0 my %mes;
1156 0 0       0 my @mes = ({map{$mes{$_}=!$mes{$_}?length$_:($mes{$_}$_);}@showf});
  0 0       0  
  0         0  
1157 0         0 my $width = 0;
1158 0         0 my $depth = 0;
1159 0         0 while (1) {
1160 0         0 my %f;
1161 0         0 $depth = $f + ++$s;
1162 0         0 @f{ @showf, qw( hints bitmask )}= caller($depth);
1163             # this is probably a stupid way to break out of this loop, we basically keep stepping back up the stack until there is nothing left
1164 0 0       0 last unless join('',map{$f{$_}?$f{$_}:''}(@showf));
  0 0       0  
1165 0         0 $width=0;
1166 0         0 my $x = 0;
1167             #push @mes, "$s => \n\t", join("\n\t",map{(space( $_ . "(" . $x++ . ")") . " => " . ($f{$_}?$f{$_}:'undef')) }@showf), "\n";
1168 0 0 0     0 foreach (@showf) {$f{$_} ||= 'undef';$mes{$_}=!$mes{$_}?length$f{$_}:($mes{$_}
  0 0       0  
  0         0  
  0         0  
1169 0         0 $mes[$depth] = \%f;
1170             }
1171 0         0 my ($c, @c);
1172 0         0 my $sep = '';
1173 0 0       0 my @m = ( '_' x $width,"\n", join("", "\n", map { if($_){$c=$_;@c=map{(space($c->{$_},$mes{$_}+2,$sep) . ' | ');}@showf;$sep='';(@c,"\n");}else{()}}@mes),'_' x $width,"\n",);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1174 0         0 push @caller, @m;
1175             }
1176 926         1867 my $log_called_f = _log_called_package( $f );
1177 926 50       2923 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1178 926         1880 my $log_called_at = _log_called_package( $f + 1 );
1179 926 50       2557 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1180 926 50       2079 if ( not $log_called_at->[0] ) {
1181 0         0 $log_called_at = $log_called_f;
1182             }
1183 926         2193 my $called_called_from = _log_called_package( $f + 2 );
1184 926 50       2371 if ( not $called_called_from->[0] ) {
1185 926         1406 $called_called_from = $log_called_at;
1186             }
1187 926 50       2791 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1188 926 50       2102 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1189 926 50       2019 print STDERR 'called_called_from: ', $self->dump( [ $called_called_from ] ), "\n" if $ENV{LOG_DEBUG};
1190 926         2673 push @caller, "log call at $log_called_at->[0] in file $log_called_at->[1]";
1191             #push @caller, "$log_called_at->[0] called from $called_called_from->[0] in file $called_called_from->[1]";
1192 926         2142 push @caller, "called from $called_called_from->[0] in file $called_called_from->[1]";
1193 926 50       6074 return wantarray ? @caller : join('', @caller );
1194             }
1195              
1196             LOGS: { # a cache of open log objects for output
1197             # this may not be too desirable in the end because
1198             # you lose individual control of the log level, file ... and such
1199             # although I may be able to fix that
1200             my %LOGS = ( STDOUT => $this_package->object( { log_file => 'STDOUT', log_level => $log_level } ),
1201             STDIN => $this_package->object( { log_file => 'STDIN' , log_level => $log_level } ),
1202             STDERR => $this_package->object( { log_file => 'STDERR', log_level => $log_level } ),
1203             );
1204            
1205             # unless otherwise specified we will use STDERR as our output stream
1206             $LOGS{DEFAULT} = $LOGS{$default_fh};
1207             #use Carp qw( cluck confess );
1208             #local $SIG{__WARN__} = \&cluck;
1209             #local $SIG{__DIE__} = \&confess;
1210            
1211             sub object {
1212             # there should probably be a better way of specifying which existing
1213             # logging object should be used rather than REALLOG
1214 3     3 0 8 my $self = shift;
1215 3   33     19 my $class = ref $self || $self;
1216             #carp( " -- $self->object() CALLER -- " );
1217 3 50       25 $self = $class->new( @_ ) unless ref $self;
1218            
1219 3         9 my @args = @_;
1220 3         4 my $args;
1221            
1222 3 50       12 if ( my $init = shift @args ) {
1223 3 50       13 ref $init eq 'HASH' and $args = $init;
1224 3 50       16 ref $init eq 'ARRAY' and 1;
1225             }
1226 3   50     22 my $log = $args->{log} || $class || 'DEFAULT';
1227 3 50 66     19 $log = $LOGS{$log} ||= ($class eq $this_package ? $self : $this_package->new(@_));
1228            
1229 3 50       68 return $log if $log;
1230             # hmmm failed?
1231 0         0 return delete $LOGS{$log};
1232             }
1233             }
1234              
1235              
1236             #print STDERR __FILE__, ":", __LINE__, " :: \n", $log->dump( -n => [ 'FHS_NA', 'FHS_NO'], -d => [ \%FHS_NA, \%FHS_NO]), "\n";
1237             FILEHANDLES : { # a cache of open filehandles for output
1238             # I may want to split this into open_fh, get_fh, close_fh (with perhaps an argument helper of get_fh_file_args or something, to sort out the passed arguments for each of the potential functions mentioned )
1239             sub close_fh { # simply closes the current filehandle and removes if from the list of open handles
1240 0     0 0 0 my $self = shift;
1241 0         0 my $status = 'NA';
1242 0 0       0 if ( my $fh = $self->fh( @_, no_open => 1 ) ) {
1243 0         0 $intlog->write($dll, '$fh: ', $fh );
1244             #; # the problem here, is that if arguments were passed, and no such filehandle was already op, then fh() is going to open a filehandle, give it to us whereupon we are going to immediately close it. That kind of sucks.
1245 0         0 my $file_no = fileno($fh);
1246 0         0 my $file = $FHN_NO{$file_no};
1247 0         0 my $file_clean = $file;
1248 0         0 $file_clean =~ s/^\s*([>]{1,2})\s*//;
1249 0 0       0 if ( $ENV{LOG_DEBUG} ) {
1250 0         0 print STDERR "file_no='$file_no'\n";
1251 0         0 print STDERR "file='$file'\n";
1252 0         0 print STDERR "file_clean='$file_clean'\n";
1253             }
1254 0 0 0     0 if ($fh and $file_no) {
1255 0 0       0 $status = close($fh) or warn "Couldn't close filehandle on '$file': $!";
1256 0         0 delete $FHS_NA{$file_clean};
1257 0         0 delete $FHS_NO{$file_no};
1258 0         0 delete $FHN_NO{$file_no};
1259             }
1260             } else {
1261             #$intlog->write($dl7, '@_: ', \@_ );
1262             #die;
1263             }
1264 0         0 return $status;
1265             }
1266             *get_fh = \&fh;
1267             sub fh {
1268             # this is a bit fucky nutty, I would like to pull all of the file handle-handling stuff into another package, I would like to add hooks for on-the-fly (de)compression, preferably all in perl (making it platform independent), but with outside programs if necessary
1269             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1270             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1271 4989     4989 0 6455 my $self = shift;
1272             #return $FHS_NA{STDERR};
1273 4989         15437 my $args = { @_ };
1274             #print STDOUT join(" ", @_), "\n";
1275 4989   50     13901 my $level = $args->{-level} || DEFAULT;
1276 4989         4487 my $file;
1277             my $fh;
1278 0         0 my $file_no;
1279 0         0 my $file_clean;
1280             #_WRITE( "SHITBALLS", " \$level = '$level'\n" );
1281 4989 50       17704 if ( $level =~ /^(STDERR|STDOUT)$/i ) {
1282 0         0 $fh = $FHS_NA{"\U$level"};
1283 0         0 $file_no = fileno($fh);
1284 0         0 $file = $level;
1285 0         0 $file_clean = $file;
1286             } else {
1287 4989         8180 $file = $args->{"log_file_$level"};
1288 4989   33     15492 $file ||= $args->{log_file};
1289             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1290             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1291 4989   33     8555 $file ||= $self->{"log_file_$level"};
1292             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1293             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1294 4989   33     7486 $file ||= $self->{log_file};
1295             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1296             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1297 4989   33     7987 $file ||= $LEVEL_FHS{$level};
1298             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1299             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1300 4989   33     6958 $file ||= $default_fh;
1301             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1302             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1303 4989         6564 $fh = $args->{fh};# || $FHS_NA{$file_clean};
1304             # $file_clean = $file;
1305             # $file_clean =~ s/^\s*([>]{1,2})\s*//;
1306             # $fh = $args->{fh} || $FHS_NA{$file_clean};
1307             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1308             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1309             }
1310             #fileno($fh);
1311             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1312             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1313             #print STDERR "FH: [$level] :: ", $fh, ":", fileno($fh), " ::: $file $args->{log_file}\n";
1314             #print STDOUT "FH: [$level] :: ", $fh, ":", fileno($fh), " ::: $file $args->{log_file}\n";
1315             #print STDERR __PACKAGE__, ":", __LINE__, "FH: [$level] :: ", ($fh||'undef'), ":", " ::: $file_clean $args->{log_file}\n";
1316             #print STDOUT __PACKAGE__, ":", __LINE__, "FH: [$level] :: ", ($fh||'undef'), ":", " ::: $file_clean $args->{log_file}\n";
1317 4989         4377 my @fhs;
1318             my $reffh;
1319 4989 50       8070 if ( ref $fh eq 'ARRAY' ) {
1320 0         0 $reffh = 1;
1321 0         0 @fhs = @$fh;
1322             } else {
1323 4989         6889 $reffh = 0;
1324 4989         7154 @fhs = $fh;
1325             }
1326 4989         4586 my @return;
1327 4989 50       9726 if ( $fh ) {
1328 0         0 foreach my $_fh ( @fhs ) {
1329 0         0 $file_no = fileno($_fh);
1330             #print STDERR __PACKAGE__, ":", __LINE__, "file_no: $file_no\n";
1331             #print STDOUT __PACKAGE__, ":", __LINE__, "file_no: $file_no\n";
1332 0 0       0 if ( defined $file_no ) {
1333             # I don't know if I should cache this here, because we may not have been responsible for opening it
1334             #::# $FHS_NA{$file_clean} = $fh;
1335             #::# $FHN_NO{$file_no} = $file;
1336             #::# $FHS_NO{$file_no} = $fh;
1337 0         0 push @return, $_fh;
1338             } else {
1339 0         0 warn "$!: $file";
1340             }
1341             }
1342 0 0       0 return $reffh ? \@return : $return[0];
1343             }
1344            
1345 4989         5064 my @files;
1346             my $reffile;
1347 4989 50       7811 if ( ref $file eq 'ARRAY' ) {
1348 0         0 $reffile = 1;
1349 0         0 @files = @$file;
1350             } else {
1351 4989         5155 $reffile = 0;
1352 4989         8009 @files = $file;
1353             }
1354             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'FHS_NA', 'FHS_NO', 'FHN_NO'], -d => [ \%FHS_NA, \%FHS_NO, \%FHN_NO]), "\n";
1355             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'files'], -d => [ \@files ]), "\n";
1356 4989         8032 foreach my $_file ( @files ) {
1357             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file'], -d => [ $_file ]), "\n";
1358 4989         4741 my $_file_clean;
1359 4989         4898 $_file_clean = $_file;
1360 4989         15140 $_file_clean =~ s/^\s*(\||[>]{1,2})\s*//;
1361             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file_clean'], -d => [ $_file_clean ]), "\n";
1362 4989         7324 my $_fh = $FHS_NA{$_file_clean};
1363 4989 50       8012 if ( $args->{no_open} ) {
1364 0         0 push @return, $_fh;
1365             } else {
1366 4989 100       9849 unless ( $_fh ) {
1367 1 50       9 if ( fileno($_file) ) {
1368 0         0 $_fh = $_file;
1369             } else {
1370 1         1 my $mode;
1371 1 50       5 if ( $_file =~ /^\s*(\||[>]{1,2})/ ) {
1372 0         0 $mode = $1;
1373             } else {
1374 1 50       37 $mode = -f $_file_clean ? '>>' : '>';
1375             }
1376 1 50       9 $_fh = new IO::File or die $!;
1377 1 50       56 print STDERR "Opening new filehandle for '$_file' on '$mode' '$_file_clean'\n" if $ENV{LOG_DEBUG};
1378 1         5 my $opened = $_fh->open( "$mode$_file_clean" );
1379 1 50       41 unless ( $opened ) {
1380 0         0 my $error_level = FATAL;
1381 0 0       0 if ( not $log->handle_fatals() ) {
1382 0         0 $error_level = ERROR;
1383             }
1384 0         0 $intlog->write($error_level, "$mode $_file_clean : $!");
1385 0         0 return undef;
1386             }
1387             #print STDERR "Opened new filehandle '$opened' for '$file' on '$mode' '$file_clean'\n";
1388             #print STDOUT "Opened new filehandle '$opened' for '$file' on '$mode' '$file_clean'\n";
1389             }
1390             }
1391 4989         9058 my $_file_no = fileno($_fh);
1392 4989 50       8659 defined $_file_no or die $!;
1393             #print STDERR "Got fileno on new filehandle '$file_no' for '$file' on '$mode' '$file_clean'\n";
1394             #print STDOUT "Got fileno on new filehandle '$file_no' for '$file' on '$mode' '$file_clean'\n";
1395            
1396             ################################################################################
1397             # this locking screwed me all up once when I was running under mod_perl
1398             # I think it was the exclusive lock collision between different httpd child processes
1399             # I should make this a per-file option I guess
1400             # in any case this wouldn't really work in an NFS environment, because there advisory locks are IPC based
1401             #my $flocked = flock $fh, LOCK_EX or die $!;
1402             #print STDERR "Got lock on new filehandle '$flocked' for '$file' on '$mode' '$file_clean'\n";
1403             #print STDOUT "Got lock on new filehandle '$flocked' for '$file' on '$mode' '$file_clean'\n";
1404             ################################################################################
1405            
1406 4989         7268 $FHS_NA{$_file_clean} = $_fh;
1407 4989         7001 $FHS_NO{$_file_no} = $_fh;
1408 4989         7255 $FHN_NO{$_file_no} = $_file;
1409             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1410             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1411 4989 50 33     16538 ( $self->{unbuffer} or $args->{unbuffer} ) and _unbuffer( $_fh );
1412             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1413             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1414 4989         14260 push @return, $_fh;
1415             }
1416             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'FHS_NA', 'FHS_NO', 'FHN_NO'], -d => [ \%FHS_NA, \%FHS_NO, \%FHN_NO]), "\n";
1417             }
1418 4989 50       21864 return $reffile ? \@return : $return[0];
1419             }
1420            
1421             sub _unbuffer {
1422 4989     4989   5758 my $fh = shift;
1423 4989         12957 my $selected = select;
1424             # disable buffering on this filehandle
1425 4989         8525 select $fh; $| = 1;
  4989         9053  
1426             # restore previously selected filehandle
1427 4989         11689 select $selected;
1428 4989         7274 return $fh;
1429             }
1430            
1431             sub _WRITE {
1432 4989     4989   5561 my $self = shift;
1433             #print STDERR __FILE__, ":", __LINE__, " :: ", $self->dump([ \@_ ]), "\n";
1434 4989         5198 my $message;
1435             my $fh;
1436 4989         7296 my $args = {};
1437 4989 50       19504 if ( $_[0] =~ /^-/ ) {
1438 4989         16936 $args = { @_ };
1439 4989 50       14292 $message = $args->{-message} or return undef;
1440 4989 50       10977 ref $message eq 'ARRAY' or $message = [ $message ] ;
1441 4989         7089 $fh = $args->{-FH};
1442             } else {
1443 0 0       0 shift @_ if ( $fh = $FHS_NA{$_[0]} );
1444 0         0 local $STACK_TRACE = 1;
1445 0         0 print STDERR __FILE__, ":", __LINE__, " :: ", $self->dump([ \@_ ]), "\n";
1446 0 0       0 $message = [ join ' ', __PACKAGE__->_caller(), map { defined $_ ? $_ : 'undef'; } @_ ] ;
  0         0  
1447 0         0 exit 1;
1448             }
1449            
1450 4989   50     10886 my $level = $args->{-level} || CLEAN;
1451            
1452 4989 50       8378 my $return = join '', map { defined $_ ? $_ : 'undef'; } @$message;
  14966         32717  
1453 4989 50       13288 if ( $args->{-terse} ) {
1454 0         0 $return =~ s/\s+/ /mg;
1455             }
1456            
1457 4989   33     9295 $fh ||= $FHS_NA{$default_fh};
1458 4989         4251 my @fhs;
1459             my $reffh;
1460 4989 50       8968 if ( ref $fh eq 'ARRAY' ) {
1461 0         0 $reffh = 1;
1462 0         0 @fhs = @$fh;
1463             } else {
1464 4989         4650 $reffh = 0;
1465 4989         8232 @fhs = $fh;
1466             }
1467            
1468 4989         7380 foreach my $_fh ( @fhs ) {
1469             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'fh', 'FHS_NA', 'FHS_NO'], -d => [ $_fh, \%FHS_NA, \%FHS_NO]), "\n";
1470 4989 50 33     12125 fileno($_fh) or $_fh = $FHS_NA{$_fh} or die "Invalid filehandle: " . $self->dump( -n => [ 'fh' ], -d => [ $_fh ] );
1471             #_lock( $_fh );
1472 4989 50       31184 print $_fh $return, $n or die ( "$!: arguments to _WRITE were => " . $self->dump( -n => [ 'args' ], -d => [ $args ] ));
1473             #_unlock( $_fh );
1474             }
1475            
1476             #print STDERR "level=`", ($level || 'undef'), "'\n";
1477 4989 50 66     18536 if ( $level =~ /^(CRIT|FATAL)$/ and ( defined $args->{handle_fatals} ? $args->{handle_fatals} : $self->{handle_fatals} ) ) {
    50          
1478 0         0 local $STACK_TRACE = 1;
1479 0         0 die $self->_caller( ) . "\n$return";
1480             #die "$level\n";
1481 0         0 die "FATAL error! $return\n";
1482             }
1483              
1484 4989 50       12408 if ( $BIG_WARN_ON{$level} ) {
1485             #print STDERR "\n\n\nDOING BIG WARN ON '$level' '$ENV{BIG_WARN_ON_FATAL}'\n\n\n";
1486             #local $STACK_TRACE = 1;
1487 0         0 warn $self->_caller( ) . "\n$return";
1488             #die;
1489             }
1490            
1491 4989 100       9227 if ( $level eq QUIT ) {
1492 56 50 0     255 exit ($args->{QUIT} || $args->{EXIT} || $LOG_CODE{QUIT} ) unless $self->{DEBUG}{NO_QUIT};
1493             }
1494            
1495 4989         20104 return $return;
1496             }
1497             }
1498             sub _lock {
1499 0     0     my $fh = shift;
1500             #flock($fh,LOCK_EX);
1501             # and, in case someone appended
1502             # while we were waiting...
1503 0           seek($fh, 0, 2);
1504             }
1505              
1506             sub _unlock {
1507 0     0     my $fh = shift;
1508             #flock($fh,LOCK_UN);
1509             }
1510 1     1   1034 END {
1511             # delete $FHS_NA{STDERR};
1512             # delete $FHS_NA{STDOUT};
1513             # foreach my $fh ( values %FHS_NA ) {
1514             # $fh->close();
1515             # }
1516             }
1517              
1518             1;
1519             __END__