File Coverage

blib/lib/Easy/Log.pm
Criterion Covered Total %
statement 616 977 63.0
branch 154 500 30.8
condition 51 242 21.0
subroutine 120 137 87.5
pod 12 29 41.3
total 953 1885 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   39414 use Easy::Log::Filter;
  1         3  
  1         7  
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   563 $filter_file = __PACKAGE__ eq 'Easy::Log' ? __FILE__ : ( $INC{'Easy/Log.pm'} or die "Couldn't find location of Easy/Log.pm package" );
13 1         7 $filter_file =~ s|Log.pm|Log/Filter.pm|;
14 1 50       8 print STDERR "filter_file=$filter_file\n" if $ENV{LOG_FILTER_DEBUG};
15 1         2 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       95 open(FILTER, "<$filter_file") or die $!;
18 1         177 $eval .= '#' . join("", ); #`cat $filter_file`; # the '#' here comments out the first line of the filter package 'package Easy::Log::Filter;'
19 1         50 close FILTER;
20 1         4 $eval =~ /(.*)/ms; # for untainting in case taint mode is on
21 1         12 $eval = $1;
22 1 50       5 print STDERR "EVAL:#########################\n$eval\n########################\n" if $ENV{LOG_FILTER_DEBUG};
23 1 50 50 1 0 182 eval "{ $eval }";
  1 50 50 1 0 9  
  1 50 50 1 0 2  
  1 0 33 1   3  
  11 50 33 4630   156  
  1 0 0 4630   5  
  1 0   0   2  
  1 0       4  
  28 0       1766  
  11 0       21  
  1 0       2  
  1 0       17  
  1 0       4  
  1 50       4  
  1 50       4  
  1 50       30  
  1 50       6  
  1 50       6  
  1 50       3  
  1 50       2  
  1 50       9  
  0 50       0  
  0 50       0  
  0 50       0  
  1 50       4  
  1 50       4  
  1 50       3  
  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         3  
  1         6  
  1         3  
  1         9  
  1         4  
  1         5  
  1         3  
  1         5  
  1         5  
  1         5  
  1         4  
  1         6  
  1         9  
  1         28  
  1         6  
  1         2  
  1         10  
  4630         7949  
  4630         6046  
  4630         5666  
  4630         9802  
  4630         5545  
  4630         14644  
  4630         7824  
  4630         9839  
  4630         7898  
  4630         9124  
  4630         8149  
  4630         28872  
  4630         5632  
  4630         8035  
  4630         9726  
  4630         14379  
  4630         5544  
  4630         5421  
  4630         5232  
  4630         9323  
  4630         5695  
  4630         11706  
  4630         6774  
  4630         8210  
  4630         11499  
  4630         8118  
  4630         6647  
  4630         9756  
  4630         6312  
  4630         7622  
  4630         10721  
  4630         32946  
  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       11 (print STDERR '$this_package: ', $this_package, '(', __PACKAGE__, ')', "\n") if $ENV{LOG_FILTER_DEBUG};
25 1 50       51 $@ and die $@;
26             #die;
27             }
28              
29             #
30 1     1   13 use strict;
  1         3  
  1         57  
31 1     1   3346 use Data::Dumper;
  1         9837  
  1         95  
32 1     1   1099 use IO::File;
  1         2515  
  1         161  
33 1     1   7 use Fcntl qw(:flock);
  1         3  
  1         148  
34 1     1   6 use Carp qw( cluck confess );
  1         2  
  1         57  
35 1     1   6 use File::Spec;
  1         2  
  1         81  
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   5 use Exporter;
  1         2  
  1         304  
44             our ( %EXPORT_TAGS, @ISA, @EXPORT_OK, @EXPORT, $VERSION );
45             @ISA = qw( Exporter );
46              
47             $VERSION = '0.02_01';
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   6 use constant MESSAGE => 'MESSAGE'; # this will send an email to the appointed person
  1         2  
  1         85  
75 1     1   6 use constant DEFAULT => 'DEFAULT';
  1         2  
  1         46  
76 1     1   4 use constant LOUD => 'LOUD';
  1         1  
  1         42  
77 1     1   4 use constant CLEAN => 'CLEAN';
  1         2  
  1         41  
78 1     1   5 use constant EMERG => 'EMERG';
  1         1  
  1         43  
79 1     1   5 use constant ALERT => 'ALERT';
  1         1  
  1         45  
80 1     1   5 use constant QUIT => 'QUIT';
  1         2  
  1         41  
81 1     1   4 use constant EXIT => 'QUIT'; # synonym for QUIT
  1         2  
  1         46  
82 1     1   4 use constant CRIT => 'CRIT';
  1         2  
  1         43  
83 1     1   5 use constant FATAL => 'FATAL'; # synonym for CRIT
  1         1  
  1         44  
84 1     1   4 use constant FAIL => 'FAIL'; # synonym for CRIT
  1         3  
  1         49  
85 1     1   4 use constant ERROR => 'ERROR';
  1         3  
  1         39  
86 1     1   7 use constant WARN => 'WARN';
  1         2  
  1         50  
87 1     1   5 use constant NOTICE => 'NOTICE';
  1         2  
  1         42  
88 1     1   5 use constant INFO => 'INFO';
  1         1  
  1         37  
89 1     1   5 use constant DEBUG99 => 'DEBUG99';
  1         2  
  1         42  
90 1     1   4 use constant DEBUG9 => 'DEBUG9';
  1         2  
  1         45  
91 1     1   5 use constant DEBUG8 => 'DEBUG8';
  1         2  
  1         42  
92 1     1   5 use constant DEBUG7 => 'DEBUG7';
  1         2  
  1         42  
93 1     1   5 use constant DEBUG6 => 'DEBUG6';
  1         1  
  1         51  
94 1     1   4 use constant DEBUG5 => 'DEBUG5';
  1         2  
  1         47  
95 1     1   4 use constant DEBUG4 => 'DEBUG4';
  1         2  
  1         36  
96 1     1   4 use constant DEBUG3 => 'DEBUG3';
  1         1  
  1         56  
97 1     1   6 use constant DEBUG2 => 'DEBUG2';
  1         2  
  1         65  
98 1     1   6 use constant DEBUG1 => 'DEBUG1';
  1         42  
  1         47  
99 1     1   13 use constant DEBUG0 => 'DEBUG0';
  1         2  
  1         44  
100 1     1   7 use constant DEBUG => 'DEBUG';
  1         3  
  1         209  
101 1     1   6 use constant TRACE => 'TRACE';
  1         2  
  1         55  
102 1     1   4 use constant SPEW => 'SPEW';
  1         2  
  1         48  
103              
104 1     1   14 use constant D_MESSAGE => 'D_MESSAGE'; # this will send an email to the appointed person
  1         2  
  1         45  
105 1     1   4 use constant D_DEFAULT => 'D_DEFAULT';
  1         2  
  1         64  
106 1     1   6 use constant D_LOUD => 'D_LOUD';
  1         2  
  1         57  
107 1     1   5 use constant D_CLEAN => 'D_CLEAN';
  1         1  
  1         52  
108 1     1   6 use constant D_EMERG => 'D_EMERG';
  1         1  
  1         58  
109 1     1   5 use constant D_ALERT => 'D_ALERT';
  1         2  
  1         54  
110 1     1   6 use constant D_CRIT => 'D_CRIT';
  1         1  
  1         68  
111 1     1   5 use constant D_FATAL => 'D_FATAL';
  1         1  
  1         64  
112 1     1   6 use constant D_FAIL => 'D_FAIL';
  1         2  
  1         85  
113 1     1   5 use constant D_QUIT => 'D_QUIT';
  1         2  
  1         64  
114 1     1   5 use constant D_EXIT => 'D_EXIT';
  1         2  
  1         48  
115 1     1   5 use constant D_ERROR => 'D_ERROR';
  1         2  
  1         51  
116 1     1   5 use constant D_WARN => 'D_WARN';
  1         1  
  1         61  
117 1     1   5 use constant D_NOTICE => 'D_NOTICE';
  1         2  
  1         53  
118 1     1   5 use constant D_INFO => 'D_INFO';
  1         2  
  1         799  
119 1     1   27 use constant D_DEBUG99 => 'D_DEBUG99';
  1         12  
  1         191  
120 1     1   7 use constant D_DEBUG9 => 'D_DEBUG9';
  1         4  
  1         61  
121 1     1   7 use constant D_DEBUG8 => 'D_DEBUG8';
  1         3  
  1         54  
122 1     1   6 use constant D_DEBUG7 => 'D_DEBUG7';
  1         2  
  1         39  
123 1     1   5 use constant D_DEBUG6 => 'D_DEBUG6';
  1         2  
  1         54  
124 1     1   5 use constant D_DEBUG5 => 'D_DEBUG5';
  1         1  
  1         43  
125 1     1   5 use constant D_DEBUG4 => 'D_DEBUG4';
  1         3  
  1         62  
126 1     1   4 use constant D_DEBUG3 => 'D_DEBUG3';
  1         2  
  1         43  
127 1     1   4 use constant D_DEBUG2 => 'D_DEBUG2';
  1         2  
  1         36  
128 1     1   5 use constant D_DEBUG1 => 'D_DEBUG1';
  1         2  
  1         40  
129 1     1   5 use constant D_DEBUG0 => 'D_DEBUG0';
  1         1  
  1         46  
130 1     1   9 use constant D_DEBUG => 'D_DEBUG';
  1         1621  
  1         63  
131 1     1   7 use constant D_TRACE => 'D_TRACE';
  1         1  
  1         41  
132 1     1   5 use constant D_SPEW => 'D_SPEW';
  1         1  
  1         59  
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   5 use constant ll => D_DEFAULT;
  1         2  
  1         46  
141 1     1   4 use constant mll => D_MESSAGE;
  1         2  
  1         42  
142 1     1   4 use constant lll => D_LOUD;
  1         2  
  1         42  
143 1     1   4 use constant cll => D_CLEAN;
  1         2  
  1         50  
144 1     1   4 use constant qll => D_QUIT;
  1         2  
  1         107  
145 1     1   5 use constant ell => D_ERROR;
  1         2  
  1         54  
146 1     1   84 use constant all => D_ALERT;
  1         6  
  1         66  
147 1     1   6 use constant wll => D_WARN;
  1         2  
  1         67  
148 1     1   6 use constant nll => D_NOTICE;
  1         2  
  1         65  
149 1     1   6 use constant ill => D_INFO;
  1         2  
  1         69  
150 1     1   7 use constant dl99 => D_DEBUG99;
  1         1  
  1         54  
151 1     1   5 use constant dl9 => D_DEBUG9;
  1         3  
  1         73  
152 1     1   7 use constant dl8 => D_DEBUG8;
  1         2  
  1         53  
153 1     1   4 use constant dl7 => D_DEBUG7;
  1         2  
  1         42  
154 1     1   4 use constant dl6 => D_DEBUG6;
  1         1  
  1         47  
155 1     1   4 use constant dl5 => D_DEBUG5;
  1         2  
  1         45  
156 1     1   5 use constant dl4 => D_DEBUG4;
  1         2  
  1         52  
157 1     1   5 use constant dl3 => D_DEBUG3;
  1         1  
  1         39  
158 1     1   4 use constant dl2 => D_DEBUG2;
  1         2  
  1         44  
159 1     1   4 use constant dl1 => D_DEBUG1;
  1         1  
  1         38  
160 1     1   4 use constant dl0 => D_DEBUG0;
  1         7  
  1         42  
161 1     1   5 use constant dll => D_DEBUG;
  1         2  
  1         134  
162 1     1   4 use constant tll => D_TRACE;
  1         2  
  1         46  
163 1     1   4 use constant sll => D_SPEW;
  1         2  
  1         15090  
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 = get_userinfo();
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 9 my $self = shift;
312 1         2 my $log_level = shift;
313 1 50       68 $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 13 my $self = shift;
341 1         3 my $log_level = shift;
342 1 50       43 $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 36536 sub log_level { exists $_[1] ? $_[0]->{ log_level } = $_[1] : $_[0]->{ log_level }; }
357 6 50   6 1 47 sub dump_refs { exists $_[1] ? $_[0]->{ dump_refs } = $_[1] : $_[0]->{ dump_refs }; }
358 7 50   7 1 48 sub handle_fatals { exists $_[1] ? $_[0]->{ handle_fatals } = $_[1] : $_[0]->{ handle_fatals }; }
359 6 50   6 1 33 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 16 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 109 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 938 my $self = shift;
370 56   50     104 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     105 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       157 my $valid_level = scalar map { $_ eq $level ? 1 : (); } LOG_LEVELS() if $level;
  3136 50       5599  
379 56 100 66     333 if ( $level and not $valid_level ) {
    50 33        
380 8 50       16 if ( $dest ) {
381             #houston we have a problem
382             } else {
383 8         13 $dest = $level;
384             }
385             } elsif ( $level and $valid_level ) {
386 48         66 $key .= "_$level";
387             }
388            
389 56 50       113 if ( $dest ) {
390 56         321 $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         248 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 18 my $self = shift;
555 6   33     36 my $class = ref $self || $self || $this_package;
556 6         19 $self = bless {}, $class;
557 6         51 $self->init( @_ );
558 6         14 return $self;
559             }
560              
561             sub init {
562 6     6 0 9 my $self = shift;
563 6         19 my $init = shift;
564 6 100       16 if ( defined $init ) {
565 4 50       13 unless ( ref $init eq 'HASH' ) {
566 0         0 unshift @_, $init;
567 0         0 $init = { @_ };
568             }
569             } else {
570 2         4 $init = {};
571             }
572 6         66 $init = { %init , %$init }; # override defaults with init args passed in
573 6         33 while ( my ( $key, $value ) = each %$init ) {
574 37 50       63 next unless $key;
575             #$self->{$key} = $value;
576 37         125 $self->$key( $value );
577             }
578 6         25 while ( my ( $level, $fh ) = each %LEVEL_FHS ) {
579 48         96 $self->log_file( $level => $fh );
580             }
581             #print STDERR "$self: ", &dump( $self, -d => $self );
582 6         20 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   49262 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       3147 join('',$lt[5]+1900, map { length $_ < 2 ? "0$_" : $_; } (($lt[4]+1),($lt[3])) ) . ' ' . join('', map { length $_ < 2 ? "0$_" : $_;} @lt[2,1,0]),
  1852 50       8257  
  2778         10820  
742             }
743              
744             sub _prefix_prod {
745 926 50   926   3999 print STDERR __LINE__, " 'prefix_prod'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
746 926         1217 my $level = shift;
747 926         4514 return '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  2778         78530  
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   2791 print STDERR __LINE__, " 'prefix_dev_long'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
767 926         1652 my $level = shift;
768 926         1217 my $args = shift;
769 926   50     3511 my $backstack = $args->{backstack} || 0;
770             #"$username\@$hostname:$$:$path_abbrev:$path_base",
771 926         3787 my $return = '--['.join("]\n--[",map { space(pad($_, $p_pad), $p_space), }
  1852         68212  
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         3211 $return .= _prefix_prod( $level, $args, @_ );
779 926 100       4167 $return .= "\n" if ( $level =~ /CLEAN/ );
780 926         2094 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 2365495 my $self = shift;
821 12545 50       32761 ref $self or $self = $log;
822 12545 50       40901 (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         37950 my @msg = @_;
824             #my ($level, $_level, $log_level, $_log_level, $args) = $self->_check_level( \@msg );
825 12545         19554 my ($level, $_level, $log_level, $_log_level, $args);
826 0         0 my $use_level;
827 0         0 my $map_level;
828 12545         17824 CHECK_LEVEL:
829             #sub _check_level {
830             {
831             #my $self = shift;
832             #my $msg = shift;
833 12545         13595 my $msg = \@msg;
834             #my $args = {};
835 12545         22827 $args = {};
836             #my $level = shift @$msg;
837 12545         19152 $level = shift @$msg;
838 12545 100 66     67993 ref $level eq 'HASH'
839             and ($args=$level)
840             and $level=shift @$msg;
841              
842 12545   33     62432 $use_level = $args->{level} || $level;
843 12545         16634 $map_level = $use_level;
844 12545         35251 $map_level =~ s/^D_//;
845             #print "LEVEL : '$level'\n";
846             #print "MAP_LEVEL: '$map_level'\n";
847 12545   33     71675 $args->{log_file} ||= $self->{"log_file_$level"} || $self->{"log_file"};
      66        
848 12545   50     77999 $log_level = $args->{log_level} || $self->{log_level} || $ENV{LOG_LEVEL} || 'DEFAULT';
849 12545         15037 my $map_log_level = $log_level;
850 12545         26705 $map_log_level =~ s/^D_//;
851             #my ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
852 12545         37672 ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
853 12545 50       35981 print STDERR "\nLEVELS: $log_level:$map_log_level:$_log_level ... $level:$map_level:$_level\n" if $ENV{LOG_LEVEL_DEBUG};
854            
855 12545 50       34880 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     68245 my $backstack = $args->{backstack} || 0;
877 12545         16910 my $return = \@msg;
878 12545         15107 my $status = 1;
879 12545 50       30255 (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       33578 if( not $ALWAYS_LOG{$map_level} ) {
881 8400 50       25387 if ( my $e = $self->{exclusive} ) {
882 0 0       0 $level =~ /$e/
883             or $status = 0;# or return join( '', @$return );
884             } else {
885 8400 100       20369 $_level >= $_log_level
886             or $status = 0;
887             #or return join( '', map { defined $_ ? $_ : 'undef' } @$return );
888             }
889             }
890 12545 50       33485 (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     53173 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       27810 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       25017 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         11080 my @inmsg = @msg;
  4989         11442  
947 4989 50       19985 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         6880 my @outmsg = ();
951 4989         5295 my $tmp;
952            
953 4989 0       26587 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         5636 my @prefix;
965             my @prefix_out;
966 0         0 my $add_dev_prefix;
967 4989   33     17351 my $log_file = $args->{log_file} || $self->log_file( $level ) || $self->log_file();
968 4989 0 33     21186 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       9267 push @prefix, \&_prefix_dev if $add_dev_prefix;
975 4989 50       12020 push @prefix, $prefix if defined $prefix;
976 4989         7382 my $code_resolve_cnt = 0;
977 4989         5245 my $code_resolve_cnt_max = 10;
978             # really we should have somethings that checks the %args for ALL of the possible settings
979 4989         14162 my $st = $STACK_TRACE;
980 4989 50       29451 $STACK_TRACE = exists $args->{stack_trace} ? $args->{stack_trace}
    50          
981             : defined $self->{stack_trace} ? $self->{stack_trace}
982             : $STACK_TRACE;
983            
984 4989         8207 foreach my $p ( @prefix ) {
985             CODE_PREFIX:
986 4989         13424 while ( ref $p eq 'CODE' ) {
987 926         2245 $p = &$p( $level, $args );
988 926 50       3747 last CODE_PREFIX if ( $code_resolve_cnt++ > $code_resolve_cnt_max );
989             }
990 4989         16436 unshift @inmsg, $p;
991             #unshift @prefix_out, $p;
992             }
993 4989         8983 $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         14588 my ($msg, $d);
999 4989         11019 INMSG: while ( scalar @inmsg ) {
1000 14966         27455 $tmp = undef;
1001 14966         26881 $msg = shift @inmsg;
1002 14966 50       35635 defined $msg or $msg = 'undef';#'(UNDEFINED ELEMENT IN LOG MESSAGE ARGUMENTS)';
1003 14966         16116 my $code_resolve_cnt = 0;
1004             CHECK_REF:
1005 14966 50 33     39319 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         39007 push @outmsg, $msg;
1024             }
1025 4989 0 33     15850 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         25400 @msg = @outmsg;
1033             }
1034              
1035 4989 100 50     18398 $n = exists $args->{n} ? $args->{n} : ($self->{n} || "\n");
1036 4989 50       14216 (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       11428 unless ( $args->{dont_actually_log} ) {
1038             #$return = $self->_actually_log( %$args, -level => $use_level, -message => $return );
1039 4989         40900 %$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     11443 $args->{-terse} ||= $self->{terse};
  4989         24621  
1048 4989   50     14683 $args->{-level} ||= INFO;
1049 4989   50     13210 $args->{-message} ||= ' - -- NO MESSAGE -- - ';
1050 4989         19415 my $fh = $self->fh( %$args );
1051 4989 50       16344 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         23090 $return = $self->_WRITE( -FH => $fh, %$args );
1067             }
1068             };
1069              
1070 4989 50       14297 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         9237 $n = undef;
1081             }
1082 12545 50       54529 ref $return eq 'ARRAY' and $return = join('', map { defined $_ ? $_ : 'undef' } @$return);
  33928 100       97632  
1083             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $intlog->dump([ \@_ ]);
1084 12545 100       68620 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   4440 my $self = shift;
1126 2778   50     12356 my $f = shift || ( ref $self ? 0 : $self ) || 0;
1127 2778         3425 my $nf = $f + 1;
1128 2778         4895 my $log_called_package = '';
1129 2778         3306 my $log_called_file = '';
1130 2778         3955 my @caller = ();
1131 2778         12915 my @f = caller($f);
1132 2778         5607 my ( $package, $filename, $line, $subroutine ) = @f;
1133             #print '( $package, $filename, $line, $subroutine ) = ', "( $package, $filename, $line, $subroutine ) [$f]\n";
1134 2778         7878 my @nf = caller($nf);
1135 2778         5582 my ( $npackage, $nfilename, $nline, $nsubroutine ) = @nf;
1136             #print '( $npackage, $nfilename, $nline, $nsubroutine ) = ', "( $npackage, $nfilename, $nline, $nsubroutine ) [$nf]\n";
1137 2778 100       6582 if ( $nsubroutine ) {
    100          
1138 926         2524 $log_called_package = "$nsubroutine:$line";
1139 926         2045 $log_called_file = "$filename:$line";
1140             } elsif ( $package ) {
1141 926         1994 $log_called_package = "$package:$line";
1142 926         1661 $log_called_file = "$filename:$line";
1143             }
1144 2778         11747 return [ $log_called_package, $log_called_file, \@f, \@nf ];
1145             }
1146              
1147             sub _caller {
1148 926     926   1229 my $self = shift;
1149 926   50     3679 my $f = shift || 0;
1150 926         1350 my @caller = ();
1151 926 50       2167 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         1898 my $log_called_f = _log_called_package( $f );
1177 926 50       3180 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1178 926         2206 my $log_called_at = _log_called_package( $f + 1 );
1179 926 50       3009 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1180 926 50       2343 if ( not $log_called_at->[0] ) {
1181 0         0 $log_called_at = $log_called_f;
1182             }
1183 926         2455 my $called_called_from = _log_called_package( $f + 2 );
1184 926 50       2456 if ( not $called_called_from->[0] ) {
1185 926         1365 $called_called_from = $log_called_at;
1186             }
1187 926 50       3301 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1188 926 50       2812 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1189 926 50       2666 print STDERR 'called_called_from: ', $self->dump( [ $called_called_from ] ), "\n" if $ENV{LOG_DEBUG};
1190 926         2488 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         1901 push @caller, "called from $called_called_from->[0] in file $called_called_from->[1]";
1193 926 50       6960 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     20 my $class = ref $self || $self;
1216             #carp( " -- $self->object() CALLER -- " );
1217 3 50       19 $self = $class->new( @_ ) unless ref $self;
1218            
1219 3         8 my @args = @_;
1220 3         4 my $args;
1221            
1222 3 50       8 if ( my $init = shift @args ) {
1223 3 50       27 ref $init eq 'HASH' and $args = $init;
1224 3 50       9 ref $init eq 'ARRAY' and 1;
1225             }
1226 3   50     29 my $log = $args->{log} || $class || 'DEFAULT';
1227 3 50 66     177 $log = $LOGS{$log} ||= ($class eq $this_package ? $self : $this_package->new(@_));
1228            
1229 3 50       83 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 8744 my $self = shift;
1272             #return $FHS_NA{STDERR};
1273 4989         25127 my $args = { @_ };
1274             #print STDOUT join(" ", @_), "\n";
1275 4989   50     18405 my $level = $args->{-level} || DEFAULT;
1276 4989         5283 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       23549 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         10311 $file = $args->{"log_file_$level"};
1288 4989   33     22247 $file ||= $args->{log_file};
1289             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1290             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1291 4989   33     10338 $file ||= $self->{"log_file_$level"};
1292             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1293             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1294 4989   33     10664 $file ||= $self->{log_file};
1295             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1296             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1297 4989   33     9933 $file ||= $LEVEL_FHS{$level};
1298             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1299             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1300 4989   33     12803 $file ||= $default_fh;
1301             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1302             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1303 4989         8331 $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         4848 my @fhs;
1318             my $reffh;
1319 4989 50       12147 if ( ref $fh eq 'ARRAY' ) {
1320 0         0 $reffh = 1;
1321 0         0 @fhs = @$fh;
1322             } else {
1323 4989         5978 $reffh = 0;
1324 4989         8125 @fhs = $fh;
1325             }
1326 4989         8234 my @return;
1327 4989 50       10325 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         5322 my @files;
1346             my $reffile;
1347 4989 50       9243 if ( ref $file eq 'ARRAY' ) {
1348 0         0 $reffile = 1;
1349 0         0 @files = @$file;
1350             } else {
1351 4989         6064 $reffile = 0;
1352 4989         13111 @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         8083 foreach my $_file ( @files ) {
1357             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file'], -d => [ $_file ]), "\n";
1358 4989         5204 my $_file_clean;
1359 4989         6483 $_file_clean = $_file;
1360 4989         14154 $_file_clean =~ s/^\s*(\||[>]{1,2})\s*//;
1361             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file_clean'], -d => [ $_file_clean ]), "\n";
1362 4989         8105 my $_fh = $FHS_NA{$_file_clean};
1363 4989 50       10685 if ( $args->{no_open} ) {
1364 0         0 push @return, $_fh;
1365             } else {
1366 4989 100       13192 unless ( $_fh ) {
1367 1 50       10 if ( fileno($_file) ) {
1368 0         0 $_fh = $_file;
1369             } else {
1370 1         2 my $mode;
1371 1 50       5 if ( $_file =~ /^\s*(\||[>]{1,2})/ ) {
1372 0         0 $mode = $1;
1373             } else {
1374 1 50       44 $mode = -f $_file_clean ? '>>' : '>';
1375             }
1376 1 50       11 $_fh = new IO::File or die $!;
1377 1 50       75 print STDERR "Opening new filehandle for '$_file' on '$mode' '$_file_clean'\n" if $ENV{LOG_DEBUG};
1378 1         8 my $opened = $_fh->open( "$mode$_file_clean" );
1379 1 50       64 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         8356 my $_file_no = fileno($_fh);
1392 4989 50       13405 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         8361 $FHS_NA{$_file_clean} = $_fh;
1407 4989         17094 $FHS_NO{$_file_no} = $_fh;
1408 4989         20870 $FHN_NO{$_file_no} = $_file;
1409             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1410             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1411 4989 50 33     23514 ( $self->{unbuffer} or $args->{unbuffer} ) and _unbuffer( $_fh );
1412             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1413             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1414 4989         17076 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       25500 return $reffile ? \@return : $return[0];
1419             }
1420            
1421             sub _unbuffer {
1422 4989     4989   10073 my $fh = shift;
1423 4989         13937 my $selected = select;
1424             # disable buffering on this filehandle
1425 4989         13348 select $fh; $| = 1;
  4989         8737  
1426             # restore previously selected filehandle
1427 4989         16218 select $selected;
1428 4989         9186 return $fh;
1429             }
1430            
1431             sub _WRITE {
1432 4989     4989   9735 my $self = shift;
1433             #print STDERR __FILE__, ":", __LINE__, " :: ", $self->dump([ \@_ ]), "\n";
1434 4989         5574 my $message;
1435             my $fh;
1436 4989         7302 my $args = {};
1437 4989 50       22181 if ( $_[0] =~ /^-/ ) {
1438 4989         19246 $args = { @_ };
1439 4989 50       19237 $message = $args->{-message} or return undef;
1440 4989 50       12972 ref $message eq 'ARRAY' or $message = [ $message ] ;
1441 4989         9461 $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     13784 my $level = $args->{-level} || CLEAN;
1451            
1452 4989 50       9929 my $return = join '', map { defined $_ ? $_ : 'undef'; } @$message;
  14966         43814  
1453 4989 50       14860 if ( $args->{-terse} ) {
1454 0         0 $return =~ s/\s+/ /mg;
1455             }
1456            
1457 4989   33     10886 $fh ||= $FHS_NA{$default_fh};
1458 4989         5202 my @fhs;
1459             my $reffh;
1460 4989 50       10059 if ( ref $fh eq 'ARRAY' ) {
1461 0         0 $reffh = 1;
1462 0         0 @fhs = @$fh;
1463             } else {
1464 4989         7935 $reffh = 0;
1465 4989         8529 @fhs = $fh;
1466             }
1467            
1468 4989         7146 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     14457 fileno($_fh) or $_fh = $FHS_NA{$_fh} or die "Invalid filehandle: " . $self->dump( -n => [ 'fh' ], -d => [ $_fh ] );
1471             #_lock( $_fh );
1472 4989 50       43716 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     19952 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       14943 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       10305 if ( $level eq QUIT ) {
1492 56 50 0     214 exit ($args->{QUIT} || $args->{EXIT} || $LOG_CODE{QUIT} ) unless $self->{DEBUG}{NO_QUIT};
1493             }
1494            
1495 4989         22429 return $return;
1496             }
1497             }
1498             sub _lock {
1499 0     0   0 my $fh = shift;
1500             #flock($fh,LOCK_EX);
1501             # and, in case someone appended
1502             # while we were waiting...
1503 0         0 seek($fh, 0, 2);
1504             }
1505              
1506             sub _unlock {
1507 0     0   0 my $fh = shift;
1508             #flock($fh,LOCK_UN);
1509             }
1510              
1511             sub get_userinfo {
1512 1 50   1 0 32 if ( $^O =~ /mswin/i ) {
1513 0         0 return ( $ENV{USERNAME} );
1514             }
1515             else {
1516 1         1434 return getpwuid $<;
1517             }
1518             }
1519              
1520 1     1   500 END {
1521             # delete $FHS_NA{STDERR};
1522             # delete $FHS_NA{STDOUT};
1523             # foreach my $fh ( values %FHS_NA ) {
1524             # $fh->close();
1525             # }
1526             }
1527              
1528             1;
1529             __END__