File Coverage

blib/lib/Log/Easy.pm
Criterion Covered Total %
statement 619 1176 52.6
branch 154 630 24.4
condition 50 310 16.1
subroutine 121 147 82.3
pod 12 32 37.5
total 956 2295 41.6


line stmt bran cond sub pod time code
1             package Log::Easy;
2             # -t STDOUT -t STDERR ???
3             my $prefix_dev_backstack = 2;
4 1     1   22438 use Log::Easy::Filter;
  1         4  
  1         6  
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 Log::Easy::Filter;
11             #do Log::Easy::Filter;
12 1     1   562 $filter_file = __PACKAGE__ eq 'Log::Easy' ? __FILE__ : ( $INC{'Log/Easy.pm'} or die "Couldn't find location of Log/Easy.pm package" );
13 1         9 $filter_file =~ s|Easy.pm|Easy/Filter.pm|;
14 1 50       5 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       80 open(FILTER, "<$filter_file") or die $!;
18 1         143 $eval .= '#' . join("", ); #`cat $filter_file`; # the '#' here comments out the first line of the filter package 'package Log::Easy::Filter;'
19 1         25 close FILTER;
20 1         4 $eval =~ /(.*)/ms; # for untainting in case taint mode is on
21 1         13 $eval = $1;
22 1 50       4 print STDERR "EVAL:#########################\n$eval\n########################\n" if $ENV{LOG_FILTER_DEBUG};
23 1 50 50 1 0 159 eval "{ $eval }";
  1 50 50 1 0 11  
  1 50 50 1 0 2  
  1 0 33 1   3  
  11 50 33 4630   142  
  1 0 0 4630   5  
  1 0   0   1  
  1 0       3  
  28 0       1756  
  11 0       20  
  1 0       4  
  1 0       20  
  1 0       5  
  1 50       5  
  1 50       5  
  1 50       31  
  1 50       6  
  1 50       7  
  1 50       4  
  1 50       2  
  1 50       10  
  0 50       0  
  0 50       0  
  0 50       0  
  1 50       3  
  1 50       6  
  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         6  
  1         5  
  1         3  
  1         3  
  1         6  
  1         4  
  1         5  
  1         4  
  1         20  
  1         4  
  1         9  
  1         8  
  1         33  
  1         8  
  1         2  
  1         10  
  4630         7063  
  4630         6021  
  4630         5104  
  4630         9968  
  4630         5035  
  4630         13764  
  4630         11357  
  4630         8116  
  4630         5021  
  4630         12180  
  4630         6899  
  4630         10151  
  4630         6327  
  4630         9122  
  4630         8787  
  4630         21743  
  4630         6143  
  4630         11043  
  4630         5273  
  4630         18065  
  4630         5268  
  4630         22463  
  4630         5961  
  4630         8411  
  4630         5288  
  4630         9770  
  4630         6588  
  4630         10448  
  4630         6404  
  4630         7631  
  4630         9106  
  4630         23751  
  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       5 (print STDERR '$this_package: ', $this_package, '(', __PACKAGE__, ')', "\n") if $ENV{LOG_FILTER_DEBUG};
25 1 50       28 $@ and die $@;
26             #die;
27             }
28              
29             #
30 1     1   6 use strict;
  1         2  
  1         38  
31 1     1   3746 use Data::Dumper;
  1         15167  
  1         93  
32 1     1   979 use IO::File;
  1         2891  
  1         183  
33 1     1   7 use Fcntl qw(:flock);
  1         3  
  1         139  
34 1     1   6 use Carp qw( cluck confess );
  1         1  
  1         53  
35 1     1   7 use File::Spec;
  1         1  
  1         70  
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   1461 use Getopt::Long;
  1         14286  
  1         8  
44              
45 1     1   195 use Exporter;
  1         2  
  1         305  
46             our ( %EXPORT_TAGS, @ISA, @EXPORT_OK, @EXPORT, $VERSION );
47             @ISA = qw( Exporter );
48              
49             $VERSION = '0.01_11';
50              
51             %EXPORT_TAGS = (
52             # available constants for log level text names, these will never be filtered nor will warnings about them ever be made
53             # basically, these are for production level logging (as opposed to the 'shorthand' log levels below in "log_level_[not_]filtered"
54             # as such they can still be used to put the program in DEBUG mode (etc), but for more formalized debugging
55             #log_level => [ Log::Easy::Filter->LOG_LEVELS() ],
56             log_level => [ LOG_LEVELS() ],
57             # global logging object
58             log => [ qw( $log log ) ],
59             # convenient log level aliases that WILL BE FILTERED if appropriate (MUST begin with a $ [eg regular SCALAR variable]
60             #log_level_filtered => [ map { "\$$_" } Log::Easy::Filter->DEFAULT_FILTER() ],
61             ll_filtered => [ map { "\$$_" } DEFAULT_FILTER() ],
62             # 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
63             # this is useful for debugging when you may want a particular message to be displayed (simply delete the '$')
64             #log_level_not_filtered => [ Log::Easy::Filter->DEFAULT_FILTER() ],
65             ll_not_filtered => [ DEFAULT_FILTER() ],
66             # these are utility methods for output formatting
67             misc => [ qw(space pad dump _caller $hostname ) ],
68             usage => [ qw( get_options optargs_missing usage) ],
69             );
70              
71             $EXPORT_TAGS{all} = [ map {@{$_}} values %EXPORT_TAGS ];
72             $EXPORT_TAGS{initialize} = [ @{$EXPORT_TAGS{log_level}} ];
73             $EXPORT_TAGS{basic} = [ map { @{$EXPORT_TAGS{$_}} } qw( log_level log ll_filtered ll_not_filtered) ];
74             @EXPORT_OK = @{$EXPORT_TAGS{'all'}};
75             @EXPORT = ();
76              
77 1     1   6 use constant MESSAGE => 'MESSAGE'; # this will send an email to the appointed person
  1         2  
  1         81  
78 1     1   6 use constant DEFAULT => 'DEFAULT';
  1         3  
  1         43  
79 1     1   5 use constant LOUD => 'LOUD';
  1         2  
  1         45  
80 1     1   5 use constant CLEAN => 'CLEAN';
  1         2  
  1         46  
81 1     1   6 use constant EMERG => 'EMERG';
  1         2  
  1         50  
82 1     1   7 use constant ALERT => 'ALERT';
  1         3  
  1         44  
83 1     1   6 use constant QUIT => 'QUIT';
  1         3  
  1         50  
84 1     1   5 use constant EXIT => 'QUIT'; # synonym for QUIT
  1         3  
  1         46  
85 1     1   6 use constant CRIT => 'CRIT';
  1         1  
  1         49  
86 1     1   6 use constant FATAL => 'FATAL'; # synonym for CRIT
  1         2  
  1         46  
87 1     1   8 use constant FAIL => 'FAIL'; # synonym for CRIT
  1         3  
  1         56  
88 1     1   6 use constant ERROR => 'ERROR';
  1         3  
  1         47  
89 1     1   7 use constant WARN => 'WARN';
  1         2  
  1         49  
90 1     1   6 use constant NOTICE => 'NOTICE';
  1         2  
  1         51  
91 1     1   6 use constant INFO => 'INFO';
  1         1  
  1         50  
92 1     1   7 use constant DEBUG99 => 'DEBUG99';
  1         2  
  1         44  
93 1     1   5 use constant DEBUG9 => 'DEBUG9';
  1         3  
  1         48  
94 1     1   6 use constant DEBUG8 => 'DEBUG8';
  1         2  
  1         53  
95 1     1   6 use constant DEBUG7 => 'DEBUG7';
  1         2  
  1         988  
96 1     1   8 use constant DEBUG6 => 'DEBUG6';
  1         3  
  1         56  
97 1     1   6 use constant DEBUG5 => 'DEBUG5';
  1         2  
  1         49  
98 1     1   5 use constant DEBUG4 => 'DEBUG4';
  1         2  
  1         46  
99 1     1   5 use constant DEBUG3 => 'DEBUG3';
  1         2  
  1         44  
100 1     1   6 use constant DEBUG2 => 'DEBUG2';
  1         41  
  1         49  
101 1     1   5 use constant DEBUG1 => 'DEBUG1';
  1         2  
  1         37  
102 1     1   5 use constant DEBUG0 => 'DEBUG0';
  1         1  
  1         45  
103 1     1   5 use constant DEBUG => 'DEBUG';
  1         2  
  1         42  
104 1     1   5 use constant TRACE => 'TRACE';
  1         1  
  1         45  
105 1     1   5 use constant SPEW => 'SPEW';
  1         1  
  1         36  
106              
107 1     1   5 use constant D_MESSAGE => 'D_MESSAGE'; # this will send an email to the appointed person
  1         3  
  1         42  
108 1     1   4 use constant D_DEFAULT => 'D_DEFAULT';
  1         1  
  1         36  
109 1     1   5 use constant D_LOUD => 'D_LOUD';
  1         2  
  1         43  
110 1     1   5 use constant D_CLEAN => 'D_CLEAN';
  1         1  
  1         43  
111 1     1   5 use constant D_EMERG => 'D_EMERG';
  1         9  
  1         39  
112 1     1   6 use constant D_ALERT => 'D_ALERT';
  1         2  
  1         44  
113 1     1   5 use constant D_CRIT => 'D_CRIT';
  1         1  
  1         47  
114 1     1   5 use constant D_FATAL => 'D_FATAL';
  1         3  
  1         39  
115 1     1   5 use constant D_FAIL => 'D_FAIL';
  1         2  
  1         51  
116 1     1   4 use constant D_QUIT => 'D_QUIT';
  1         2  
  1         44  
117 1     1   5 use constant D_EXIT => 'D_EXIT';
  1         2  
  1         38  
118 1     1   5 use constant D_ERROR => 'D_ERROR';
  1         1  
  1         1408  
119 1     1   6 use constant D_WARN => 'D_WARN';
  1         2  
  1         37  
120 1     1   5 use constant D_NOTICE => 'D_NOTICE';
  1         3  
  1         36  
121 1     1   5 use constant D_INFO => 'D_INFO';
  1         1  
  1         37  
122 1     1   5 use constant D_DEBUG99 => 'D_DEBUG99';
  1         2  
  1         36  
123 1     1   4 use constant D_DEBUG9 => 'D_DEBUG9';
  1         1  
  1         36  
124 1     1   4 use constant D_DEBUG8 => 'D_DEBUG8';
  1         2  
  1         34  
125 1     1   5 use constant D_DEBUG7 => 'D_DEBUG7';
  1         1  
  1         1634  
126 1     1   8 use constant D_DEBUG6 => 'D_DEBUG6';
  1         2  
  1         62  
127 1     1   6 use constant D_DEBUG5 => 'D_DEBUG5';
  1         2  
  1         52  
128 1     1   4 use constant D_DEBUG4 => 'D_DEBUG4';
  1         2  
  1         44  
129 1     1   5 use constant D_DEBUG3 => 'D_DEBUG3';
  1         2  
  1         38  
130 1     1   4 use constant D_DEBUG2 => 'D_DEBUG2';
  1         6  
  1         47  
131 1     1   5 use constant D_DEBUG1 => 'D_DEBUG1';
  1         2  
  1         45  
132 1     1   5 use constant D_DEBUG0 => 'D_DEBUG0';
  1         1  
  1         40  
133 1     1   4 use constant D_DEBUG => 'D_DEBUG';
  1         2  
  1         44  
134 1     1   5 use constant D_TRACE => 'D_TRACE';
  1         8  
  1         39  
135 1     1   5 use constant D_SPEW => 'D_SPEW';
  1         2  
  1         66  
136              
137              
138              
139             # the following, when used as log levels in code calling this package with qw(:all)
140             # these may not be worth the clutter
141             # I have also made identically named scalars which if used will cause the log messages to be filtered out
142             # WARNING: without the `$' the log message WILL NOT be filtered out!
143 1     1   5 use constant ll => D_DEFAULT;
  1         1  
  1         55  
144 1     1   5 use constant mll => D_MESSAGE;
  1         2  
  1         44  
145 1     1   5 use constant lll => D_LOUD;
  1         2  
  1         51  
146 1     1   6 use constant cll => D_CLEAN;
  1         8  
  1         46  
147 1     1   5 use constant qll => D_QUIT;
  1         2  
  1         52  
148 1     1   6 use constant ell => D_ERROR;
  1         2  
  1         60  
149 1     1   6 use constant all => D_ALERT;
  1         10  
  1         45  
150 1     1   6 use constant wll => D_WARN;
  1         2  
  1         51  
151 1     1   6 use constant nll => D_NOTICE;
  1         1  
  1         44  
152 1     1   5 use constant ill => D_INFO;
  1         2  
  1         49  
153 1     1   5 use constant dl99 => D_DEBUG99;
  1         2  
  1         44  
154 1     1   5 use constant dl9 => D_DEBUG9;
  1         6  
  1         43  
155 1     1   5 use constant dl8 => D_DEBUG8;
  1         2  
  1         50  
156 1     1   5 use constant dl7 => D_DEBUG7;
  1         1  
  1         43  
157 1     1   4 use constant dl6 => D_DEBUG6;
  1         2  
  1         95  
158 1     1   6 use constant dl5 => D_DEBUG5;
  1         3  
  1         49  
159 1     1   5 use constant dl4 => D_DEBUG4;
  1         2  
  1         56  
160 1     1   4 use constant dl3 => D_DEBUG3;
  1         2  
  1         46  
161 1     1   5 use constant dl2 => D_DEBUG2;
  1         2  
  1         44  
162 1     1   5 use constant dl1 => D_DEBUG1;
  1         2  
  1         51  
163 1     1   5 use constant dl0 => D_DEBUG0;
  1         2  
  1         45  
164 1     1   10 use constant dll => D_DEBUG;
  1         2  
  1         44  
165 1     1   12 use constant tll => D_TRACE;
  1         2  
  1         57  
166 1     1   5 use constant sll => D_SPEW;
  1         1  
  1         9156  
167              
168              
169             our ( $p_space, $p_pad ) = ( 8, 8 );
170             our $STACK_TRACE = $ENV{LOG_STACK_TRACE} || 0;
171              
172             our ( $DUMPER, $log_level, $log, $intlog );
173              
174             # if we have big warngings set to true for any particular log level then we'll issue a perl 'warn'ing
175             our %BIG_WARN_DEFAULTS = ( ( map { ("DEBUG$_" => 0); } ( 0 .. 9 ) ),
176             ( map { ($_ => 0);} qw( MESSAGE LOUD CLEAN QUIT EXIT EMERG ALERT CRIT FATAL FAIL ERROR WARN NOTICE INFO DEBUG TRACE SPEW ) ),
177             ( qw( WARN 0 ERROR 0 CRIT 1 FATAL 1 FAIL 0 ) )
178             );
179             #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;
180             our %BIG_WARN_ON = map { ( $_ => ( defined $ENV{"BIG_WARN_ON_$_"} ? $ENV{"BIG_WARN_ON_$_"} : ( $BIG_WARN_DEFAULTS{$_} || 0 ) )); } keys %BIG_WARN_DEFAULTS;
181             # these were(are?) actually apache constants for logging levels I think anything that gets in that
182             # is preceded with a '_' gets [0] (numerical value) these return the uppercase(?) version of
183             # themselves
184             our %LOG_CODE = ( STDERR => 0x00E0,
185             STDOUT => 0x00E0,
186             CLEAN => 0x00E0,
187             MESSAGE => 0x00E0,
188             LOUD => 0x00E0,
189             CRIT => 0x00E0,
190             FATAL => 0x00E0,
191             FAIL => 0x00E0,
192             QUIT => 0x00E0,
193             EXIT => 0x00E0,# synonym for QUIT
194             EMERG => 0x00E0,
195             ALERT => 0x0080,
196             ERROR => 0x0070,
197             WARN => 0x0060,
198             NOTICE => 0x0050,
199             INFO => 0x0040,
200             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.*'
201             (map { ("DEBUG$_" => ( 0x0030 + $_ )); } ( 0 .. 9 )),
202             DEBUG => 0x0030,
203             TRACE => 0x0020,
204             SPEW => 0x0010,
205             DEFAULT => 0x0030,# set equal to DEBUG
206             );
207             # translate between our more expanded selection of logging levels to what apache understands
208             our %APACHE_LEVELS = ( DEFAULT => INFO,
209             TRACE => DEBUG,
210             SPEW => DEBUG,
211             DEBUG => DEBUG,
212             (map { ("DEBUG$_" => 'DEBUG'); } ( 0 .. 9, 99 )),
213             INFO => INFO,
214             WARN => WARN,
215             NOTICE => NOTICE,
216             CRIT => CRIT,
217             FATAL => CRIT,
218             FAIL => CRIT,
219             QUIT => CRIT,
220             EXIT => CRIT,
221             ERROR => ERROR,
222             ALERT => ALERT,
223             EMERG => EMERG,
224             LOUD => ERROR,
225             CLEAN => ERROR,
226             );
227              
228             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 )
229             = ( ll, lll, qll, cll, ell, all, wll, nll, ill, dll, tll, sll, mll, dl0, dl1, dl2, dl3, dl4, dl5, dl6, dl7, dl8, dl9, dl99 );
230             our $n;
231             our %LEVEL_FHS = map { ($_ => 'STDERR'); } qw(EMERG ALERT CRIT FATAL FAIL ERROR WARN QUIT);
232              
233             #%ALWAYS_LOG is for log levels that should never be dropped, even if the package is blocked from logging
234             our %ALWAYS_LOG = qw(
235             CLEAN 1
236             CRIT 1
237             FATAL 1
238             FAIL 1
239             QUIT 1
240             ERROR 1
241             ALERT 1
242             EMERG 1
243             MESSAGE 1
244             );
245             our $default_log_level = 'INFO';
246             $log_level = $ENV{LOG_LEVEL} ||= ( [ map {$ENV{$_}?$_:()}(@{$EXPORT_TAGS{log_level}}) ]->[0] || $default_log_level );
247             # message terminator (sometimes we DON'T want newlines!)
248              
249             our $default_handle_fatals = 1;
250             our $default_unbuffer = 1;
251             our $default_fh = $ENV{LOG_FILE_DEFAULT} || $ENV{DEFAULT_LOG_FILE} || 'STDOUT';
252             our %init = ( log_file => $ENV{LOG_FILE} || $default_fh ,
253             log_level => $log_level,
254             dump_refs => (exists $ENV{LOG_DUMP_REFS} ) ? $ENV{LOG_DUMP_REFS} : 1 ,
255             handle_fatals => (exists $ENV{LOG_HANDLE_FATALS}) ? $ENV{LOG_HANDLE_FATALS} : $default_handle_fatals,
256             exclusive => $ENV{LOG_EXCLUSIVE} || '',
257             unbuffer => (exists $ENV{LOG_UNBUFFER} ? $ENV{LOG_UNBUFFER} : $default_unbuffer),
258             #prefix => \&_prefix_default,
259             );
260              
261             our %FHS_NO = (); # store list of filehandles indexed by fileno()
262             our %FHS_NA = (); # store list of filehandles indexed by file name
263             our %FHN_NO = (); # corresponding list of filenames for our filehandles indexed by fileno()
264             # OK .. I'm not sure, but trying to use STDIN may be totally retarded
265             #@LEVEL_FHS{qw( STDIN STDOUT STDERR )} = ( \*STDIN , \*STDOUT, \*STDERR );
266             @FHS_NA{qw( STDIN STDOUT STDERR )} = ( \*STDIN , \*STDOUT, \*STDERR );
267             @FHN_NO{(map { fileno($_); } @FHS_NA{qw( STDIN STDOUT STDERR )})} = qw( STDIN STDOUT STDERR );
268             @FHS_NO{keys %FHN_NO} = values %FHN_NO;
269             foreach my $fh ( @FHS_NA{qw( STDOUT STDERR )} ) { $log->{unbuffer} ? _unbuffer( $fh ) : (); }
270              
271              
272             $log = $this_package->new();
273             $intlog = $this_package->new( { prefix => \&_prefix_dev } );
274              
275             our $hostname = `hostname`;
276             #print STDERR '$hostname: ', $hostname;
277             chomp $hostname;
278             $intlog->write($dll, '$hostname: ', $hostname );
279              
280             our @userinfo = getpwuid $<;
281             our $username = $userinfo[0];
282              
283             my @pathinfo = (File::Spec->splitpath( File::Spec->rel2abs( $0 )));
284             $intlog->write({prefix=>undef},$sll, '@pathinfo: ', \@pathinfo );
285              
286             my $path_base = $0;
287             my @o = split( m|/|, $path_base );
288             $intlog->write($dll, '@o: ', \@o );
289             my $max_path_seg = 3;
290             my $num_path_seg = scalar @o;
291             #my $path_abbrev = ( $num_path_seg > $max_path_seg ) ? join('/', map {''} ( 1 .. ( $num_path_seg - $max_path_seg ))), '...', @o[$#o - 1 .. $#o ] ) : $path_base;
292             #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;
293             my $path_abbrev = ( $num_path_seg > $max_path_seg ) ? join('/', @o[0 .. 2], '...', @o[$#o - 1 .. $#o ] ) : $path_base;
294              
295             #my $xxx = $intlog;
296             #$xxx->write('STDERR', '%ENV{BIG_WARN_ON_XXX}: ', { map { $_ => ( $ENV{"BIG_WARN_ON_$_"} || 0 ) } keys%BIG_WARN_DEFAULTS } );
297             #$xxx->write('STDERR', '%BIG_WARN_DEFAULTS: ', \%BIG_WARN_DEFAULTS );
298             #$xxx->write('STDERR', '%BIG_WARN_ON: ', \%BIG_WARN_ON );
299              
300             # we don't normally want a stack trace on every log call
301             # enable on any particular call with: $intlog->write({st=>1},$lll, ':');
302             # enable on all calls with: $log->stack_trace( 1 );
303              
304              
305             *always_log = \*ALWAYS_LOG;
306             sub ALWAYS_LOG {
307 1     1 0 9 my $self = shift;
308 1         2 my $log_level = shift;
309 1 50       13 $log_level or return %ALWAYS_LOG;
310 0         0 $log_level =~ s/^D_//;
311 0         0 return $ALWAYS_LOG{$log_level};
312             }
313              
314              
315             #$intlog->write($lll, '%LOG_CODE: ', "\n", map { (space($_->[0]), ' => ', pad( $_->[1]), "\n") } sort { $a->[1] <=> $b->[1]; } map { [ $_ => $LOG_CODE{$_} ]; } keys %LOG_CODE );
316             #$intlog->packages('!' . $this_package); # uncomment this to disable all internal logging
317              
318             $ENV{LOG_PACKAGES} ||= '';
319             if ( $ENV{LOG_PACKAGES} ) {
320             $log->packages($ENV{LOG_PACKAGES});
321             $intlog->packages($ENV{LOG_PACKAGES});
322             }
323              
324              
325             # the following two sets of exported variables/subs are for development debugging purposes and are
326             # filtered out at compile time, unless $ENV{LOG_FILTER} is appropriately set. I'm thinking that since
327             # these are for development debugging that they should maybe have some different significance when
328             # it comes to descriptive output. Currently all log messages output the &{$log->{prefix}}(). Perhaps
329             # we should use a bitmask to determine whether or not a log should be output and additionally what
330             # kind of prefix it has. This would allow these to mimic the "production" log levels (in value)
331             # while also allowing us to have more descriptive prefix (caller, etc...) when they are used for
332             # development debugging
333              
334             *log_code = \*LOG_CODE;
335             sub LOG_CODE {
336 1     1 0 13 my $self = shift;
337 1         3 my $log_level = shift;
338 1 50       36 $log_level or return %LOG_CODE;
339 0         0 $log_level =~ s/^D_//;
340 0         0 return $LOG_CODE{$log_level};
341             }
342              
343 0 0   0 1 0 sub n { exists $_[1] ? $_[0]->{ n } = $_[1] : $_[0]->{ n }; }
344 0 0   0 1 0 sub log { exists $_[1] ? $_[0]->{ log } = $_[1] : $_[0]->{ log }; }
345             #sub log {
346             # if ( $_[0] and UNIVERSAL::isa( $_[0], __PACKAGE__ ) ) {
347             # return exists $_[1] ? $_[0]->{ log } = $_[1] : $_[0]->{ log };
348             # } else {
349             # return $log;
350             # }
351             #}
352 62 50   62 1 32107 sub log_level { exists $_[1] ? $_[0]->{ log_level } = $_[1] : $_[0]->{ log_level }; }
353 6 50   6 1 32 sub dump_refs { exists $_[1] ? $_[0]->{ dump_refs } = $_[1] : $_[0]->{ dump_refs }; }
354 7 50   7 1 55 sub handle_fatals { exists $_[1] ? $_[0]->{ handle_fatals } = $_[1] : $_[0]->{ handle_fatals }; }
355 6 50   6 1 133 sub exclusive { exists $_[1] ? $_[0]->{ exclusive } = $_[1] : $_[0]->{ exclusive }; }
356 0 0   0 1 0 sub stack_trace { exists $_[1] ? $_[0]->{ stack_trace } = $_[1] : $_[0]->{ stack_trace }; }
357 0 0   0 1 0 sub email { exists $_[1] ? $_[0]->{ email } = $_[1] : $_[0]->{ email }; }
358 2 50   2 1 19 sub prefix { exists $_[1] ? $_[0]->{ prefix } = $_[1] : $_[0]->{ prefix }; }
359 0 0   0 0 0 sub terse { exists $_[1] ? $_[0]->{ terse } = $_[1] : $_[0]->{ terse }; }
360 6 50   6 0 34 sub unbuffer { exists $_[1] ? $_[0]->{ unbuffer } = $_[1] : $_[0]->{ unbuffer }; }
361             *autoflush = \&unbuffer;
362             sub log_file {
363             # this needs to be able to take a file handle as well as a filename or symbolic filehandle name (eg 'STDOUT')
364             # 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
365 56     56 1 877 my $self = shift;
366 56   50     137 my $level = shift || '';
367             #my @caller = _caller();
368             # print STDERR __LINE__, "-" x 80, "\n", @caller, "\n";# if $ENV{LOG_PACKAGES_DEBUG};
369             # print STDERR __LINE__, " LEVEL=$level\n";# if $ENV{LOG_PACKAGES_DEBUG};
370 56   100     151 my $dest = shift || '';
371             # print STDERR __LINE__, " DEST=$dest\n";# if $ENV{LOG_PACKAGES_DEBUG};
372 56         135 my $key = 'log_file';
373             # print STDERR __LINE__, " KEY=$key\n";# if $ENV{LOG_PACKAGES_DEBUG};
374 56 100       172 my $valid_level = scalar map { $_ eq $level ? 1 : (); } LOG_LEVELS() if $level;
  3136 50       6353  
375 56 100 66     361 if ( $level and not $valid_level ) {
    50 33        
376 8 50       16 if ( $dest ) {
377             #houston we have a problem
378             } else {
379 8         20 $dest = $level;
380             }
381             } elsif ( $level and $valid_level ) {
382 48         80 $key .= "_$level";
383             }
384            
385 56 50       107 if ( $dest ) {
386 56         153 $self->{$key} = $dest;
387             }
388             # print STDERR __LINE__, " VALID_LEVEL=$valid_level\n";# if $ENV{LOG_PACKAGES_DEBUG};
389             # print STDERR __LINE__, " LEVEL=$level\n";# if $ENV{LOG_PACKAGES_DEBUG};
390             # print STDERR __LINE__, " DEST=$dest\n";# if $ENV{LOG_PACKAGES_DEBUG};
391             # print STDERR __LINE__, " KEY=$key\n";# if $ENV{LOG_PACKAGES_DEBUG};
392             # print STDERR __LINE__, " RETURN=$self->{$key}\n";# if $ENV{LOG_PACKAGES_DEBUG};
393             # print STDERR __LINE__, "-" x 80, "\n";# if $ENV{LOG_PACKAGES_DEBUG};
394 56         246 return $self->{$key};
395             }
396             sub log_file_multiplex {
397 0     0 0 0 my $self = shift;
398             # I should change this to accept filehandles as well
399 0 0       0 if ( scalar @_ > 2 ) {
400 0         0 die "
401             Called with too many arguments
402             the several ways this could be called, maximum of 2 arguments allowed
403             0: () ===> with no arguments, return the log_file unadorned with a specific log_level
404             1: ===> set the log_file for any LEVEL not otherwise spoken for to the specified FILE (or 'STDERR', 'STDOUT')
405             2: ===> return the log_file for the LEVEL specified
406             3: [ , ] ===> set the log_file for any LEVEL not otherwise spoken for to be multiplexed across the specified files in list [ FILE1, FILE2, ..., FILEn]
407             4: [ , , ..., ] ===> return the log_file for the list of LEVELs specified
408             5: => ===> set the log_file for the LEVEL specified to FILE
409             6: => [ , , ..., ] ===> set the log_file for the LEVEL specified to multiplex across files in list [ FILE1, FILE2, ..., FILEn]
410             7: [ , ] => ===> set the log_file for the LEVELS specified to the same file FILE
411             8: [ , ] => [ , , ..., ] ===> set the log_file for the LEVELS specified to multiplex across files in list [ FILE1, FILE2, ..., FILEn]
412             ";
413             }
414 0         0 my $key = 'log_file';
415             #$key = 'log_file_multiplex';
416            
417 0   0     0 my $level = shift || '';
418 0   0     0 my $dest = shift || '';
419 0 0 0     0 if ( not $level and not $dest ) {
420             ######
421 0         0 return $self->{$key};
422             ######
423             ######################################
424             }
425            
426 0         0 my $reflevel;
427             my $refdest;
428 0 0       0 unless ( ref $level eq 'ARRAY' ) {
429 0         0 $reflevel = 0;
430 0         0 $level = [ $level ];
431             } else {
432 0         0 $reflevel = 1;
433             }
434            
435 0 0 0     0 if ( $level and not $dest ) {
436             # check to see if this is specifying just a level, or just a dest
437 0 0       0 my $valid_level = scalar map { $_ eq $level->[0] ? 1 : (); } LOG_LEVELS() if $level->[0];
  0 0       0  
438 0 0       0 if ( $valid_level ) {
439 0         0 my @return;
440 0         0 foreach my $l ( @$level ) {
441 0 0       0 my $vl = scalar map { $_ eq $l ? 1 : (); } LOG_LEVELS();
  0         0  
442 0 0       0 unless ( $vl ) {
443 0         0 die "
444             Something is awry with the arguments you passed:
445             " . join(', ', @$level ) . "
446             ";
447             } else {
448 0         0 push @return, $self->{$key}{$l};
449             }
450             }
451             ######
452 0 0       0 return $reflevel ? \@return : $return[0];
453             ######
454             ######################################
455             } else {
456             # if the arg is not a valid log level then it must be a destination file or filehandle
457 0         0 $refdest = $reflevel;
458 0         0 $dest = $level;
459 0         0 undef $level;
460             }
461             }
462            
463 0 0       0 unless ( ref $dest eq 'ARRAY' ) {
464 0         0 $refdest = 0;
465 0         0 $dest = [ $dest ];
466             } else {
467 0 0       0 $refdest = defined $refdest ? $refdest : 0;
468             }
469            
470 0 0 0     0 if ( $dest and not $level ) {
471             # we got only one argument and it was a destination without the level specified
472             # this means by default we want to multiplex across the files given
473 0         0 $self->{$key} = $dest;
474             ######
475 0         0 return $self->{$key};
476             ######
477             ######################################
478             }
479            
480             # here we have both level and dest, which should each now be array refs
481 0         0 foreach my $l ( @$level ) {
482 0         0 my $k = "${key}_$l";
483 0         0 my $pd = $self->{$k};
484             # check to see where $pd and $dest do not agree, close all filehandles in$pd which are not also in $dest
485 0         0 $self->{$k} = $dest;
486             }
487 0         0 return $self->{$key};
488             }
489              
490             sub packages {
491             # this sets up lists of DO and DONT log for packages specified at runtime
492             # 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
493             # 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
494 0     0 0 0 my $self = shift;
495 0 0       0 if ( exists $_[0] ) {
496 0         0 my @new_packages = @_;
497 0   0     0 my $packages = $self->{packages_array} ||= [];
498 0   0     0 my $do_log = $packages->[0] ||= [];
499 0   0     0 my $dont_log = $packages->[1] ||= [];
500 0         0 foreach my $package_set ( @new_packages ) {
501 0         0 my @package_set = split(/\#/, $package_set );
502 0         0 foreach my $package ( @package_set ) {
503 0 0 0     0 next unless ($package and $package !~ /^\s+$/);
504 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$package: ' , $package, "\n" if $ENV{LOG_PACKAGES_DEBUG};
505 0 0       0 if ( $package =~ s/^\!// ) {
506             #it's a dont
507 0 0       0 unless( grep { /^$package$/ } @$dont_log ) {
  0         0  
508 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", 'DONT ::: $package: \'' , $package, "'\n" if $ENV{LOG_PACKAGES_DEBUG};
509 0         0 push @$dont_log, $package;
510             }
511             } else {
512 0 0       0 unless( grep { /^$package$/ } @$do_log ) {
  0         0  
513 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", 'DO ::: $package: \'' , $package, "'\n" if $ENV{LOG_PACKAGES_DEBUG};
514 0         0 push @$do_log, $package;
515             }
516             }
517             }
518             }
519 0 0       0 if ( my $packages = $self->{packages_array} ) {
520 0         0 my $do_log = $packages->[0];
521 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$do_log: ' , scalar @$do_log , " :: '", join('|', @$do_log) , "'\n" if $ENV{LOG_PACKAGES_DEBUG};
522 0         0 my $dont_log = $packages->[1];
523 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$dont_log: ', scalar @$dont_log, " :: '", join('|', @$dont_log), "'\n" if $ENV{LOG_PACKAGES_DEBUG};
524 0   0     0 my $packages_rx = $self->{packages} ||= [];
525 0 0       0 my $do_log_rx = scalar @$do_log ? [ map { qr/$_/; } @$do_log ] : []; #scalar @$do_log ? join('|', @$do_log ) : undef;
  0         0  
526 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$do_log_rx: ' , scalar @$do_log_rx , " :: '", join('|', @$do_log_rx) , "'\n" if $ENV{LOG_PACKAGES_DEBUG};
527 0 0       0 my $dont_log_rx = scalar @$dont_log ? [ map { qr/$_/; } @$dont_log ] : []; #scalar @$dont_log ? join('|', @$dont_log ) : undef;
  0         0  
528 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", '$dont_log_rx: ', scalar @$dont_log_rx, " :: '", join('|', @$dont_log_rx), "'\n" if $ENV{LOG_PACKAGES_DEBUG};
529 0         0 $packages_rx->[0] = $do_log_rx;
530 0         0 $packages_rx->[1] = $dont_log_rx;
531             }
532             }
533 0         0 return $self->{packages};
534             }
535              
536             sub clone {
537 0     0 1 0 my $self = shift;
538 0         0 my $VAR1 = $self->dump( @_ );
539 0         0 my $clone = eval $VAR1;
540 0 0 0     0 $clone->{prefix} = $self->{prefix} if ( UNIVERSAL::isa( $clone, $this_package ) and ref $self->{prefix} eq 'CODE' );
541 0         0 return $clone;
542             }
543              
544              
545              
546             #print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY! ... ", $log->dump([ \@_ ]);
547             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $log->dump([ \@_ ]);
548             sub new {
549             #print STDERR _caller();
550 6     6 0 18 my $self = shift;
551 6   33     34 my $class = ref $self || $self || $this_package;
552 6         20 $self = bless {}, $class;
553 6         35 $self->init( @_ );
554 6         15 return $self;
555             }
556              
557             sub init {
558 6     6 0 11 my $self = shift;
559 6         12 my $init = shift;
560 6 100       14 if ( defined $init ) {
561 4 50       14 unless ( ref $init eq 'HASH' ) {
562 0         0 unshift @_, $init;
563 0         0 $init = { @_ };
564             }
565             } else {
566 2         4 $init = {};
567             }
568 6         73 $init = { %init , %$init }; # override defaults with init args passed in
569 6         34 while ( my ( $key, $value ) = each %$init ) {
570 37 50       85 next unless $key;
571             #$self->{$key} = $value;
572 37         103 $self->$key( $value );
573             }
574 6         31 while ( my ( $level, $fh ) = each %LEVEL_FHS ) {
575 48         104 $self->log_file( $level => $fh );
576             }
577             #print STDERR "$self: ", &dump( $self, -d => $self );
578 6         21 return $self;
579             };
580              
581             sub dump {
582 0     0 0 0 my $DUMP = '';
583 0         0 my $self = shift;
584 0 0       0 (print STDERR $this_package, " STDERR ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), Dumper(\@_), "\n") if $ENV{LOG_INTERNAL_DUMP_DEBUG};
585 0   0     0 my $class = ref $self || $self;
586 0         0 my ( $dumps, $names );
587 0         0 my ( $pure, $deep, $indent, $id, $terse, $pad );
588 0 0 0     0 if ( $_[0] and $_[0] =~ /^-/ ) {
589 0         0 my $args = { @_ };
590 0   0     0 $dumps = $args->{-d} || $args->{-dump} || $self;
591 0   0     0 $names = $args->{-n} || $args->{-names} || undef;
592 0 0       0 $dumps = [ $dumps ] unless ( ref $names eq 'ARRAY' );
593 0   0     0 $pure = $args->{-pure} || 0 ;
594 0   0     0 $deep = $args->{-deep} || 0 ;
595 0 0       0 $indent = ((defined $args->{-i})? ($args->{-i}) : (defined $args->{-indent} ? $args->{-indent} : undef ));
    0          
596 0   0     0 $id = $args->{-id} || 0;
597 0   0     0 $terse = $args->{-terse} || 0 ;
598 0   0     0 $pad = $args->{-p} || $args->{-pad} || '';
599 0 0 0     0 if ( $terse and not defined $indent ) {
600 0         0 $indent = 0;
601             }
602 0 0       0 if ( not defined $indent ) {
603 0         0 $indent = 2;
604             }
605             } else {
606 0   0     0 $dumps = shift || $self;
607 0   0     0 $names = shift || undef;
608 0   0     0 $pure = shift || 0;
609 0   0     0 $deep = shift || 0;
610 0   0     0 $indent = shift || 2;
611 0   0     0 $id = shift || 0;
612 0   0     0 $terse = shift || 0;
613 0   0     0 $pad = shift || '';
614             }
615 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};
616            
617 0 0 0     0 ( defined $dumps ) and ( ref $dumps eq 'ARRAY' ) or ( $dumps = [ $dumps ] );
618 0 0 0     0 ( defined $names ) and ( ref $names eq 'ARRAY' ) or ( $names = [ $names ] );
619 0 0       0 if ( $id ) {
620 0         0 for( my $i = 0; $i <= $#$dumps; $i++ ) {
621 0         0 my $d = $dumps->[$i];
622 0 0       0 my $n = ref $d ? $d : \$d;
623 0         0 $names->[$i] = $n;
624             }
625             }
626 0         0 my $dumper = Data::Dumper->new( $dumps , $names );
627            
628 0 0       0 $dumper->Pad ( $pad ) if $pad;
629 0 0       0 $dumper->Purity ( $pure ) if $pure;
630 0 0       0 $dumper->Deepcopy( $deep ) if $deep;
631 0 0       0 $dumper->Terse ( $terse ) if $terse;
632 0 0       0 $dumper->Indent ( $indent ) if defined $indent;
633 0         0 $DUMP = $dumper->Dump();
634 0         0 return $DUMP
635             }
636              
637             sub get_options {
638 0     0 0 0 my $optargs_orig = shift;
639 0         0 my $optargs = { %$optargs_orig };
640 0         0 $intlog->write($dll, '$optargs: ', $optargs );
641 0         0 $intlog->write($dll, '@_: ', \@_ );
642 0 0       0 my $optconfig = ref $_[0] eq 'HASH' ? (shift) : {};
643 0         0 $intlog->write($dll, '$optconfig: ', $optconfig );
644 0         0 $intlog->write($dll, '@_: ', \@_ );
645 0 0       0 my $config = ref $_[0] eq 'HASH' ? (shift) : {};
646 0         0 $intlog->write($dll, '$config: ', $config );
647              
648 0         0 my %options;
649 0   0     0 my $target = $config->{target} || \%options;
650 0   0     0 my $default = $config->{default} || $target;
651              
652             # give some easy usage/help options
653 0 0 0     0 if ( not $config->{nohelp} or exists $config->{help} and $config->{help} ) {
      0        
654 0   0 0   0 $optargs->{help} ||= $optargs->{usage} ||= ['' , sub { usage( $optargs, \%options, $optconfig, $config ) }, 'print help message and exit'];
  0   0     0  
655 0   0 0   0 $optargs->{usage} ||= $optargs->{help} ||= ['' , sub { usage( $optargs, \%options, $optconfig, $config ) }, 'print help message and exit'];
  0   0     0  
656             }
657 0 0 0     0 my $no_usage = $config->{no_usage} || scalar (grep { /no_usage/ } @_) ? 1 : 0;
658 0         0 $intlog->write($sll, '$no_usage: ', $no_usage );
659 0 0 0     0 my $no_missing = $config->{no_missing} || scalar (grep { /no_missing/ } @_) ? 1 : 0;
660 0         0 $intlog->write($sll, '$no_missing: ', $no_missing );
661 0 0       0 my $p = new Getopt::Long::Parser config => [ map { ($optconfig->{$_} ? $_ : ($_ =~ /^no_/ ? $_ : "no_$_")); } keys %$optconfig ];
  0 0       0  
662 0         0 my %GetOptions = map { my $optname = $_;
  0         0  
663 0         0 $intlog->write($dll, '$optname: ', $optname );
664 0         0 my $progopt = $optargs->{$_}[0];
665 0         0 $intlog->write($dll, '$progopt: ', $progopt );
666 0         0 my $argspec = '';
667 0         0 my $optspec = '';
668 0         0 my $type;
669 0 0       0 if ( $progopt =~ /^([:=]+)([ifs@%])$/ ) {
670 0         0 my $spec = $1;
671 0         0 $type = $2;
672 0         0 $argspec = substr($spec, 0 , 1);
673 0   0     0 $optspec = substr($spec, 1 , 1) || $argspec;
674 0         0 $argspec .= $type;
675 0         0 $optspec .= $type;
676             } else {
677 0         0 $argspec = $progopt;
678 0         0 $optspec = $progopt;
679             }
680             #("$_$optargs->{$_}[0]" => ref $optargs->{$_}[1] ? $optargs->{$_}[1] : \$optargs->{$_}[1])
681 0         0 $intlog->write($dll, '$optspec: ', $optspec );
682 0         0 $intlog->write($dll, '$argspec: ', $argspec );
683 0 0       0 my @opt = ( "$optname$optspec" => ref $optargs->{$_}[1] ? $optargs->{$_}[1] : \$optargs->{$_}[1] );
684 0         0 $intlog->write($dll, '@opt: ', \@opt );
685 0         0 @opt;
686             } keys %$optargs;
687            
688 0         0 $intlog->write($dll, '%GetOptions: ', \%GetOptions);
689 0     0   0 local $SIG{__WARN__} = sub { &failed_options(@_) };# may want to add some additional arguments to pass to failed_options
  0         0  
690 0         0 $log->write($dll, '@ARGV: ', \@ARGV );
691 0         0 my $opt = $p->getoptions( %GetOptions );
692 0         0 $intlog->write($dll, '%GetOptions: ', \%GetOptions);
693 0         0 $log->write($dll, '@ARGV: ', \@ARGV );
694 0         0 $log->write($dll, '$opt: ', $opt );
695 0         0 $intlog->write($dl7, '$optargs: ', $optargs );
696 0         0 $intlog->write($dl7, '$opt: ', $opt);
697             # check that all required options have been provided
698 0 0       0 my @missing = $no_missing ? () : optargs_missing( $optargs );
699 0         0 $intlog->write($sll, "\@missing: ($no_missing)", \@missing );
700             #return () if (scalar @missing and $no_usage);
701              
702             # when this routine is separated into its own package (Getargs::Long ???), the %options should
703             # probably be a tied hash with a canonical set of key names and a 'hidden' set of aliases as
704             # specified by the $key of %optargs (eg my %o = ( 'foo|bar|baz' => [ '!', undef, 'some flag'] );
705             # would have a canonical name 'foo' (returned by keys %o) and aliases 'bar' and 'baz'
706              
707 0         0 foreach my $key ( keys %$optargs ) {
708 0         0 $intlog->write($dll, '$key: ', $key );
709 0 0       0 my $value = defined $optargs->{$key}[1] ? $optargs->{$key}[1] : $default->{$key};
710 0         0 $intlog->write($dll, '$value: ', $value );
711 0         0 my @aliases = ();# = ( $key );
712 0 0       0 if ( $key =~ /\|/ ) {
713 0         0 push @aliases, split /\|/, $key;
714             } else {
715 0         0 push @aliases, $key;
716             }
717 0         0 $intlog->write($dll, '@aliases: ', \@aliases );
718 0         0 foreach my $alias ( @aliases ) {
719 0 0       0 if ( ref $value eq 'SCALAR' ) {
    0          
    0          
720 0         0 $options{$alias} = $$value;
721             } elsif ( ref $value eq 'CODE' ) {
722             #$options{$alias} = $value;
723             } elsif ( ref $value eq 'ARRAY' ) {
724 0         0 my $final_value = [];
725 0         0 foreach my $item ( @$value ) {
726 0 0       0 if ( ref $item eq 'ARRAY' ) {
727 0         0 push @$final_value, @$item;
728             }
729             else {
730 0         0 push @$final_value, $item;
731             }
732             }
733 0         0 $options{$alias} = $final_value;
734             } else {
735 0         0 $options{$alias} = $value;
736             }
737 0         0 $target->{$alias} = $options{$alias};
738             }
739             }
740 0 0 0     0 return usage( $optargs, \%options, $optconfig, $config ) if (scalar @missing and not $no_usage);
741 0         0 $intlog->write($dl7, '%options: ', \%options);
742 0         0 return %options;
743             }
744              
745             sub failed_options {
746 0     0 0 0 $intlog->write({EXIT => 1, prefix => ''}, EXIT, @_);
747             }
748              
749             sub optargs_missing {
750 0     0 0 0 my $optargs = shift;
751 0         0 $intlog->write($dl7, '$optargs: ', $optargs );
752 0   0     0 my $options = shift || {};
753 0         0 $intlog->write($dl7, '$options: ', $options );
754 0         0 my @missing;
755             my %options;
756 0         0 my @aliases = ();
757 0         0 my %aliases = ();
758 0         0 foreach my $key ( keys %$optargs ) {
759 0 0       0 next if $key =~ /^(usage|help)$/;
760 0         0 $intlog->write($dl7, '$key: ', $key );
761 0         0 my @a;
762 0         0 my $value = $optargs->{$key}[1];
763 0 0       0 ref $value eq 'SCALAR' and $value = $$value;
764 0         0 $intlog->write($dl7, '$value: ', $value );
765 0 0       0 if ( $key =~ /\|/ ) {
766 0         0 push @a, split /\|/, $key;
767             } else {
768 0         0 push @a, $key;
769             }
770 0         0 push @aliases, @a;
771 0         0 $aliases{$key} = \@a;
772 0         0 foreach my $alias ( @a ) {
773 0         0 $intlog->write($dl7, '$alias: ', $alias );
774 0 0       0 $options{$alias} = defined $options->{$alias} ? $options->{$alias} : $value;
775 0         0 $intlog->write($dl7, qq'\$options{$alias}: ', $options{$alias} );
776             }
777             }
778 0         0 $intlog->write($dl7, '%options: ', \%options );
779 0         0 foreach my $opt (keys %$optargs ) {
780 0         0 $intlog->write($dl7, '$opt: ', $opt );
781 0         0 my $optspec = $optargs->{$opt}[0];
782 0         0 $intlog->write($dl7, '$optspec: ', $optspec );
783 0 0       0 next if not $optspec;
784 0         0 my $a = $aliases{$opt};
785 0         0 $intlog->write($dl7, '$a: ', $a );
786 0         0 my $alias = $a->[0];
787 0         0 $intlog->write($dl7, '$alias: ', $alias );
788 0         0 my $value = $options{$alias};
789 0         0 $intlog->write($dl7, '$value: ', $value );
790 0 0       0 my $optval = (ref $value eq 'ARRAY' ? join("", @$value) : $value );
791 0         0 $intlog->write($dl7, '$optval: ', $optval );
792 0 0       0 if ( $optspec =~ /^\=/ ) {
793 0         0 $intlog->write(D_SPEW, 'REQUIRED: ', $opt );
794 0 0 0     0 if ( not defined $optval or ($optval ne '0' and not $optval) ) {
      0        
795 0         0 $intlog->write(D_SPEW, 'REQUIRED AND MISSING: ', $opt );
796 0         0 push @missing, $opt;
797             }
798             }
799             }
800 0         0 $intlog->write($dl7, '%options: ', \%options );
801 0         0 $intlog->write($dll, '@missing: ', \@missing );
802 0         0 return @missing;
803             }
804 1     1   16239 use Text::Wrap;
  1         4246  
  1         18152  
805             $Text::Wrap::columns = 70;
806             $Text::Wrap::huge = 'overflow';
807             my %already_decoded;
808             sub usage {
809             # I really need to clean up how this gets its arguments, prubably aught to have the @_ be HASHable { optargs => \%optargs, ... } instead of trying to rely on this ordering crap
810 0     0 0 0 my $optargs_orig = shift;
811 0         0 my $optargs = { %$optargs_orig };
812 0         0 $intlog->write($dll, '$optargs: ', $optargs );
813            
814 0 0       0 my $options = ref $_[0] eq 'HASH' ? (shift) : {};
815 0         0 $intlog->write($dll, '$options: ', $options );
816 0 0       0 my $optconfig = ref $_[0] eq 'HASH' ? (shift) : {};
817 0         0 $intlog->write($dll, '$optconfig: ', $optconfig );
818 0 0       0 my $config = ref $_[0] eq 'HASH' ? (shift) : {};
819 0         0 $intlog->write($dll, '$config: ', $config );
820             # give some easy usage/help options
821 0 0 0     0 if ( not $config->{nohelp} or exists $config->{help} and $config->{help} ) {
      0        
822 0   0 0   0 $optargs->{help} ||= $optargs->{usage} ||= ['' , sub { usage( $optargs, $options, $optconfig, $config ) }, 'print help message and exit'];
  0   0     0  
823 0   0 0   0 $optargs->{usage} ||= $optargs->{help} ||= ['' , sub { usage( $optargs, $options, $optconfig, $config ) }, 'print help message and exit'];
  0   0     0  
824             }
825             # if ( not $config->{nohelp} or exists $config->{help} and $config->{help} ) {
826             # $optargs->{help} ||= $optargs->{usage} ||= ['' , sub { usage( $optargs ) }, 'print help message and exit'];
827             # $optargs->{usage} ||= $optargs->{help} ||= ['' , sub { usage( $optargs ) }, 'print help message and exit'];
828             # }
829 0 0       0 my $no_missing = scalar (grep { /no_missing/ } map { defined $_ ? $_ : (); } @_) ? 1 : 0;
  0 0       0  
  0         0  
830 0 0       0 my $usage_args = ref $_[0] eq 'HASH' ? (shift) : $_[0] ? $_[0] : {};
    0          
831 0         0 $intlog->write($dll, '$usage_args: ', $usage_args );
832 0 0       0 ref $usage_args eq 'HASH' or $usage_args = { $usage_args => (scalar @_ ? @_ : 1 )};
    0          
833 0 0       0 my %options = $options ? %$options : map { ($_ => $optargs->{$_}[1]) } keys %$optargs;
  0         0  
834 0         0 $intlog->write($dll, '$optargs: ', $optargs );
835 0         0 my @missing = optargs_missing( $optargs, $options );
836 0         0 $intlog->write($dll, '@missing: ', \@missing);
837 0         0 my @required = map { my $a = $optargs->{$_}[0];
  0         0  
838 0 0       0 $a =~ /^\=/ ? $_ : ();
839 0         0 } sort { $a cmp $b } keys %$optargs;
840            
841 0         0 my @optional = map { my $a = $optargs->{$_}[0];
  0         0  
842 0 0       0 $a =~ /^\=/ ? () : $_;
843 0         0 } sort { $a cmp $b } keys %$optargs;
844            
845 0 0       0 my $missing = scalar @missing ? "MISSING REQUIRED ARGUMENT(S): ( " . join(', ', map { ($optargs->{$_} ? "--$_" : $_); } sort @missing ) . " ) ... \n" : '';
  0 0       0  
846 0         0 my $base_name = $pathinfo[2];
847 0         0 $intlog->write($dll, '$base_name: ', $base_name );
848 0         0 my %type_spec = qw( f FLOAT
849             i INTEGER
850             s STRING
851             );
852 0         0 my $indent = ' | ';
853 0         0 my $sep = ( ' ' x ((length $indent) - 4) ) . ('-' x ( $Text::Wrap::columns - ((length $indent) + 2)));
854 0         0 $sep = ' ';
855 0   0     0 $usage_args->{brief_info} ||= $config->{brief_info} || '';
      0        
856 0 0       0 $intlog->write(CLEAN,(#'_' x ($Text::Wrap::columns + 3),
857             "\n",
858             ($config->{usage_message} ? $config->{usage_message} : () ),
859             "\n",
860             $no_missing ? () : ($missing,"\n"),
861             space("usage: $base_name $usage_args->{brief_info}", ), "\n",
862             $sep,#"\n ",
863             join("\n" . ' ', #(' ' x (length "usage: $base_name")),
864             map {
865 0 0       0 my $val = ( defined $options{$_}
    0          
866             ? $options{$_}
867             : $optargs->{$_}[1]
868             );
869 0 0       0 ref $val eq 'SCALAR' and $val = $$val;
870 0 0       0 ref $val eq 'ARRAY' and $val = join(', ', @$val);
871 0 0       0 ref $val eq 'HASH' and $val = join(', ', map { "$_ => $val->{$_}" } keys %$val);
  0         0  
872            
873 0         0 my $label = $_;
874 0 0       0 $label =~ /\|/ and $label = '(' . $label . ')';
875 0 0       0 my $required = $optargs->{$_}[0] =~ /^\=/ ? 1 : 0;
876             #my $boolean = $optargs->{$_}[0] =~ /(^$)|(\+)/ ? 1 : 0;
877 0         0 $optargs->{$_}[0] =~ /([fis])/;
878 0         0 my $type = $1;
879 0 0       0 my $boolean = $type ? 0 : 1;
880 0 0       0 $type = $boolean ? 'BOOLEAN' : $type_spec{$type};
881 0   0     0 my $desc = $optargs->{$_}[2] || $_; #'NO DESCRIPTION PROVIDED';
882 0         0 my @desc = split ('\s+', $desc );
883 0 0       0 my $show_req = ($required ? "REQUIRED($type)" : "OPTIONAL($type)");# . "\n";
884 0         0 my @wrap = wrap( $indent, $indent, @desc);
885 0 0       0 if( scalar @wrap == 1 ) {
886 0         0 @wrap = split("\n", $wrap[0]);
887             }
888 0         0 $intlog->write($dll, '@wrap: ', \@wrap );
889 0         0 $desc = "\n" . join( "\n", map { space($_, $Text::Wrap::columns ) . ' |'; } @wrap ) . "\n" . (' ' x length $indent ) . ('-' x ($Text::Wrap::columns - length $indent)) . $sep;
  0         0  
890 0 0 0     0 if ( 'CODE' eq ref $val
      0        
891             and $_ !~ /(usage|help)/
892             and not $already_decoded{$val}++
893             ) {
894 0         0 $val = &$val( $_, $options{$_} );
895             }
896 0 0 0     0 if ( defined $val and ( $val or $val eq '0' ) ) {
      0        
897 0 0       0 $val = $boolean ? $val : "'$val'";
898             }
899 0 0 0     0 my $onoff = ($boolean and $val) ? '#ON#' : '#OFF#';
900 0 0       0 my @opt = ( $required
    0          
    0          
    0          
    0          
    0          
    0          
    0          
901             ? ( space($show_req, 25), ' ', ( '--', space($_, 25),($val ? ' ': '***'), space($val ? ($boolean ? $onoff : $val) : ($boolean ? $onoff : uc "<$_>***"), 15)) , ' ', $desc )
902             : ( space($show_req, 25), ' [ ', ( '--', space($_, 25), space($val ? ($boolean ? $onoff : $val) : ($boolean ? $onoff : uc "<$_>"), 15)) , ' ] ', $desc )
903             );
904 0         0 join('', @opt);
905             } #( sort
906             ( # sort here to make required options come first, and sort alphabetically in each sub-category: (required, not-required)
907             ( sort @required ),
908             ( sort @optional ),
909             )
910             #)
911             ),
912             "\n",
913             #'_' x ($Text::Wrap::columns + 3),
914             )
915             );
916 0         0 %already_decoded = ();
917 0 0       0 exists $config->{exit} or exit -1;
918 0 0       0 $config->{exit} and exit -1;
919             }
920              
921             #sub _prepare_message {
922             # my $self = shift;
923             # my $level = shift;
924             # my $args = shift;
925             # my @inmsg = @_;
926             # my $dump_refs = exists $args->{dump_refs} ? $args->{dump_refs}
927             # : exists $self->{dump_refs} ? $self->{dump_refs}
928             # : $level eq 'SPEW';
929             # my @outmsg = ();
930             # my $tmp;
931             #
932             # $level = $args->{level} || $level;
933             # my $log_level = $args->{log_level} || $self->{log_level} || $ENV{LOG_LEVEL};
934             # print STDERR __LINE__, " LOG_LEVEL='$log_level', LEVEL='$level', \$args->{prefix}='$args->{prefix}'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
935             # my $prefix = exists $args->{prefix} ? $args->{prefix}
936             # : $log_level =~ /^D_/ ? \&_prefix_dev
937             # : $level =~ /CLEAN/ ? ''
938             # : defined $self->{prefix} ? $self->{prefix}
939             # : $level =~ /^D/ ? \&_prefix_dev
940             # : $log_level =~ /(SPEW)/ ? \&_prefix_dev
941             # #: $level =~ /QUIT/ ? \&_prefix_dev
942             # : $level =~ /CRIT/ ? \&_prefix_dev
943             # : $level =~ /FATAL/ ? \&_prefix_dev
944             # : $level =~ /FAIL/ ? \&_prefix_dev
945             # : \&_prefix_default;
946             # my @prefix;
947             # my @prefix_out;
948             # my $add_dev_prefix;
949             # my $log_file = $args->{log_file} || $self->log_file( $level ) || $self->log_file();
950             # if ( exists $args->{prefix}
951             # and $log_level =~ /^D_/
952             # and $log_file =~ /^(STDOUT|STDERR)$/
953             # ) {
954             # $add_dev_prefix = 1;
955             # }
956             # push @prefix, \&_prefix_dev if $add_dev_prefix;
957             # push @prefix, $prefix if defined $prefix;
958             # # really we should have somethings that checks the %args for ALL of the possible settings
959             # my $st = $STACK_TRACE;
960             # $STACK_TRACE = exists $args->{stack_trace} ? $args->{stack_trace}
961             # : defined $self->{stack_trace} ? $self->{stack_trace}
962             # : $STACK_TRACE;
963             #
964             # my $code_resolve_cnt_max = 10;
965             # foreach my $p ( @prefix ) {
966             # my $code_resolve_cnt = 0;
967             # CORE_PREFIX:
968             # while ( ref $p eq 'CODE' ) {
969             # $p = &$p( $level, $args );
970             # last CODE_PREFIX if ( $code_resolve_cnt++ > $code_resolve_cnt_max );
971             # }
972             # unshift @inmsg, $p;
973             # #unshift @prefix_out, $p;
974             # }
975             # $STACK_TRACE = $st;# restore the previous setting
976             #
977             # # my $prefix_length = [ split("\n", join( '', @prefix_out)) ];
978             # # $prefix_length = $prefix_length->[-1];
979             # # $prefix_length = length $prefix_length;
980             # my ($msg, $d);
981             # INMSG: while ( scalar @inmsg ) {
982             # $tmp = undef;
983             # $msg = shift @inmsg;
984             # defined $msg or $msg = 'undef';#'(UNDEFINED ELEMENT IN LOG MESSAGE ARGUMENTS)';
985             # my $code_resolve_cnt = 0;
986             # CHECK_REF:
987             # if (( my $ref = ref $msg ) and $dump_refs ) {
988             # # this next line of cruft is here so you can pass arguments to ->dump() without having to prepend with a minus sign
989             # my @extra_args = map { $_ =~ /^(terse|deep|pure|id|indent)$/ ? ( "-$_" => $args->{$_} ) : ( $_ => $args->{$_} ) } keys %$args;
990             # (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 );
991             # if ( $ref eq 'CODE' ) {
992             # $d = &$msg();
993             # $msg = $d;
994             # goto CHECK_REF unless ( ref $msg eq 'CODE' and $code_resolve_cnt++ > $code_resolve_cnt_max );
995             # } else {
996             # #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length + length $msg) ));
997             # #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length) ));
998             # #$d =~ s/^\s+//;
999             # #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x $prefix_length ) );
1000             # #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
1001             # $d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
1002             # }
1003             # $msg = $d;
1004             # }
1005             # push @outmsg, $msg;
1006             # }
1007             # if ( $add_dev_prefix
1008             # and $outmsg[-1] !~ /\n$/ms
1009             # ) {
1010             # push @outmsg, "\n";
1011             # };
1012             # return @outmsg;
1013             #}
1014              
1015             *_prefix_default = \&_prefix_prod;
1016              
1017             sub _time {
1018 926     926   42012 my @lt = localtime();
1019             #( 0, 1, 2, 3, 4, 5, 6, 7, 8)
1020             #($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
1021 926 50       3053 join('',$lt[5]+1900, map { length $_ < 2 ? "0$_" : $_; } (($lt[4]+1),($lt[3])) ) . ' ' . join('', map { length $_ < 2 ? "0$_" : $_;} @lt[2,1,0]),
  1852 100       8744  
  2778         15218  
1022             }
1023              
1024             sub _prefix_prod {
1025 926 50   926   2586 print STDERR __LINE__, " 'prefix_prod'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
1026 926         1469 my $level = shift;
1027 926         4340 return '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  2778         72202  
1028             "$username\@$hostname:$$",
1029             _time(),
1030             uc $level
1031             )."] "
1032             ;
1033             }
1034              
1035             sub _prefix_brief {
1036 0 0   0   0 print STDERR __LINE__, " 'prefix_brief'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
1037 0         0 my $level = shift;
1038 0         0 return '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  0         0  
1039             "$username\@$hostname:$$",
1040             _time(),
1041             )."] "
1042             ;
1043             }
1044              
1045             sub _prefix_dev {
1046 926 50   926   2537 print STDERR __LINE__, " 'prefix_dev_long'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
1047 926         1348 my $level = shift;
1048 926         1060 my $args = shift;
1049 926   50     3419 my $backstack = $args->{backstack} || 0;
1050             #"$username\@$hostname:$$:$path_abbrev:$path_base",
1051 926         3264 my $return = '['.join('][',map { space(pad($_, $p_pad), $p_space), }
  1852         55545  
1052             #__PACKAGE__->_caller($backstack + 3), # we need a 3 here to ignore (skip over) the subroutine calls within the logging module itself
1053             # was 3 before we inlined something
1054             __PACKAGE__->_caller($backstack + $prefix_dev_backstack), # we need a 2 here to ignore (skip over) the subroutine calls within the logging module itself
1055             )."] "
1056             . "\n"
1057             ;
1058 926         3334 $return .= _prefix_prod( $level, $args, @_ );
1059 926 100       4016 $return .= "\n" if ( $level =~ /CLEAN/ );
1060 926         2261 return $return;
1061             }
1062              
1063             my %level_cache = ();
1064             sub _check_level {
1065 0     0   0 my $self = shift;
1066 0         0 my $msg = shift;
1067 0         0 my $args = {};
1068 0         0 my $level = shift @$msg;
1069 0 0 0     0 ref $level eq 'HASH'
1070             and ($args=$level)
1071             and $level=shift @$msg;
1072 0         0 my $map_level = $level;
1073 0         0 $map_level =~ s/^D_//;
1074             #print "LEVEL : '$level'\n";
1075             #print "MAP_LEVEL: '$map_level'\n";
1076 0   0     0 $args->{log_file} ||= $self->{"log_file_$level"} || $self->{"log_file"};
      0        
1077 0   0     0 my $log_level = $args->{log_level} ||= $self->{log_level} || DEFAULT;
      0        
1078 0         0 my $map_log_level = $log_level;
1079 0         0 $map_log_level =~ s/^D_//;
1080 0         0 my ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
1081 0 0       0 print STDERR "\nLEVELS: $log_level:$map_log_level:$_log_level ... $level:$map_level:$_level\n" if $ENV{LOG_LEVEL_DEBUG};
1082            
1083 0 0       0 if ( not defined $_level ) {
1084 0         0 $intlog->write({stack_trace => 1 }, ERROR, "Illegal log level '$level' setting it to 'DEFAULT'");
1085 0         0 unshift @$msg, ( $level = 'DEFAULT' );
1086 0 0       0 return $self->_check_level( $msg ) unless exists $level_cache{$level};
1087 0         0 $intlog->write( ERROR, "Illegal log level '$level' trouble setting it to $level");
1088 0         0 return undef;
1089             }
1090            
1091 0         0 my @return = ($level, $_level, $log_level, $_log_level, $args);
1092             #_actually_log( $self, -level => LOUD, -FH => \*STDOUT, -message => \@return );
1093 0         0 return @return;
1094             }
1095              
1096             sub write {
1097             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $intlog->dump([ \@_ ]);
1098            
1099             # print STDERR $this_package," :: ", join(', ', caller()), "\n";
1100 6273     6273 1 2232683 my $self = shift;
1101 6273 50       16626 ref $self or $self = $log;
1102 6273 50       18977 (print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [$_[0]], -n =>['_args']), "\n") if ( $ENV{LOG_INTERNAL_DEBUG} > 4 );
1103 6273         17977 my @msg = @_;
1104             #my ($level, $_level, $log_level, $_log_level, $args) = $self->_check_level( \@msg );
1105 6273         7933 my ($level, $_level, $log_level, $_log_level, $args);
1106 0         0 my $use_level;
1107 0         0 my $map_level;
1108 6273         9114 CHECK_LEVEL:
1109             #sub _check_level {
1110             {
1111             #my $self = shift;
1112             #my $msg = shift;
1113 6273         7242 my $msg = \@msg;
1114             #my $args = {};
1115 6273         10080 $args = {};
1116             #my $level = shift @$msg;
1117 6273         14247 $level = shift @$msg;
1118 6273 100 66     39108 ref $level eq 'HASH'
1119             and ($args=$level)
1120             and $level=shift @$msg;
1121              
1122 6273   33     26326 $use_level = $args->{level} || $level;
1123 6273         12038 $map_level = $use_level;
1124 6273         14612 $map_level =~ s/^D_//;
1125             #print "LEVEL : '$level'\n";
1126             #print "MAP_LEVEL: '$map_level'\n";
1127 6273   33     27462 $args->{log_file} ||= $self->{"log_file_$level"} || $self->{"log_file"};
      66        
1128 6273   50     36287 $log_level = $args->{log_level} || $self->{log_level} || $ENV{LOG_LEVEL} || 'DEFAULT';
1129 6273         9080 my $map_log_level = $log_level;
1130 6273         11480 $map_log_level =~ s/^D_//;
1131             #my ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
1132 6273         16782 ( $_level, $_log_level ) = @LOG_CODE{$map_level, $map_log_level};
1133 6273 50       15336 print STDERR "\nLEVELS: $log_level:$map_log_level:$_log_level ... $level:$map_level:$_level\n" if $ENV{LOG_LEVEL_DEBUG};
1134            
1135 6273 50       22193 if ( not defined $_level ) {
1136 0         0 $intlog->write({stack_trace => 1 }, ERROR, "Illegal log level '$level' setting it to 'DEFAULT'");
1137 0         0 unshift @$msg, ( $level = 'DEFAULT' );
1138             #return $self->_check_level( $msg ) unless exists $level_cache{$level};
1139 0 0       0 if ( not exists $level_cache{$level} ) {
1140 0         0 goto CHECK_LEVEL;
1141             #($level, $_level, $log_level, $_log_level, $args) = $self->_check_level( $msg );
1142             } else {
1143 0         0 $intlog->write( ERROR, "Illegal log level '$level' trouble setting it to $level");
1144 0         0 return undef;
1145             }
1146             }
1147            
1148             # my @return = ($level, $_level, $log_level, $_log_level, $args);
1149             # #_actually_log( $self, -level => LOUD, -FH => \*STDOUT, -message => \@return );
1150             # return @return;
1151             }
1152             # this needs to be set up to log at any of severa levels which may be set simultaneously
1153             # eg log at WARN and TRACE
1154             # log levels should be a list
1155             # ie @_log_levels rather than $_log_level
1156 6273   50     23918 my $backstack = $args->{backstack} || 0;
1157 6273         8349 my $return = \@msg;
1158 6273         10220 my $status = 1;
1159 6273 50       16506 (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 );
1160 6273 100       15934 if( not $ALWAYS_LOG{$map_level} ) {
1161 2128 50       5189 if ( my $e = $self->{exclusive} ) {
1162 0 0       0 $level =~ /$e/
1163             or $status = 0;# or return join( '', @$return );
1164             } else {
1165 2128 100       5348 $_level >= $_log_level
1166             or $status = 0;
1167             #or return join( '', map { defined $_ ? $_ : 'undef' } @$return );
1168             }
1169             }
1170 6273 50       15333 (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 );
1171 6273 50 66     27527 if ( #not $ALWAYS_LOG{$map_level} and
1172             $status
1173             and my $packages = $self->{packages}
1174             ) {
1175 0         0 my $do_match;
1176             my $dont_match;
1177 0         0 my $do_log_rx = $packages->[0];
1178 0         0 my $dont_log_rx = $packages->[1];
1179              
1180 0         0 my $log_called_package = _log_called_package(1)->[0];
1181             #print STDERR __PACKAGE__, ":", __LINE__, ": ", "LOG CALLED PACKAGE: '$log_called_package'\n";
1182 0 0       0 if ( scalar @$do_log_rx ) {
1183 0         0 foreach my $do_rx ( @$do_log_rx ) {
1184 0 0       0 if ( $log_called_package =~ /^($do_rx)$/ ) {
1185             #print STDERR "DO LOG: $do_log_rx\n";
1186             #$do_match = ( $do_match and length $do_match > length $do_rx ) ? $do_match : $do_rx;
1187 0         0 $do_match = $do_rx;
1188             }
1189             }
1190 0 0       0 $do_match or $status = 0;
1191             }
1192            
1193 0 0 0     0 if ( $status and scalar @$dont_log_rx ) {
1194 0         0 foreach my $dont_rx ( @$dont_log_rx ) {
1195 0 0 0     0 if ( $status
1196             #and not $do_match
1197             #and ( not $do_match or ( $dont_log_rx =~ /$do_log_rx/ ))
1198             and $log_called_package =~ /^($dont_rx)$/
1199             ) {
1200             #$dont_match = ( $dont_match and length $dont_match > length $dont_rx ) ? $dont_match : $dont_rx;
1201 0         0 $dont_match = $dont_rx;
1202 0         0 $status = 0;
1203             }
1204             }
1205             }
1206            
1207 0 0 0     0 if ( $do_match and $dont_match ) {
1208             # 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
1209 0 0       0 $status = ( length $do_match > length $dont_match ) ? 1 : 0 ;
1210 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", "DO status=$status ($do_match): $do_log_rx\n" if $ENV{LOG_PACKAGES_DEBUG};
1211 0 0       0 print STDERR __PACKAGE__, ":", __LINE__, ": ", "DONT status=$status ($dont_match): $dont_log_rx\n" if $ENV{LOG_PACKAGES_DEBUG};
1212             }
1213             }
1214            
1215 6273 50       14234 print STDERR __LINE__, " LOG_LEVEL='$log_level', LEVEL='$level', MAP_LEVEL='$map_level', \$args->{prefix}='$args->{prefix}'\n" if ($ENV{LOG_INTERNAL_DEBUG} > 2);
1216 6273 100       11697 if ( $status ) {
1217             #warn "STATUS: $status ::: $level:$_level ... $log_level:$_log_level";
1218             # this is an effort at in-lining some subroutines
1219             #@msg = $self->_prepare_message( $level, $args, @msg );
1220             #sub _prepare_message {
1221             {
1222             # my $self = shift;
1223             # my $level = shift;
1224             # my $args = shift;
1225             # my @inmsg = @_;
1226 4989         5263 my @inmsg = @msg;
  4989         10238  
1227 4989 50       17594 my $dump_refs = exists $args->{dump_refs} ? $args->{dump_refs}
    50          
1228             : exists $self->{dump_refs} ? $self->{dump_refs}
1229             : $level eq 'SPEW';
1230 4989         14140 my @outmsg = ();
1231 4989         5365 my $tmp;
1232            
1233 4989 0       22711 my $prefix = exists $args->{prefix} ? $args->{prefix}
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    50          
1234             : $log_level =~ /^D_/ ? \&_prefix_dev
1235             : $use_level =~ /CLEAN/ ? ''
1236             : defined $self->{prefix} ? $self->{prefix}
1237             : $use_level =~ /^D/ ? \&_prefix_dev
1238             : $log_level =~ /(SPEW)/ ? \&_prefix_dev
1239             #: $use_level =~ /QUIT/ ? \&_prefix_dev
1240             : $use_level =~ /CRIT/ ? \&_prefix_dev
1241             : $use_level =~ /FATAL/ ? \&_prefix_dev
1242             : $use_level =~ /FAIL/ ? \&_prefix_dev
1243             : \&_prefix_default;
1244 4989         5538 my @prefix;
1245             my @prefix_out;
1246 0         0 my $add_dev_prefix;
1247 4989   33     29913 my $log_file = $args->{log_file} || $self->log_file( $level ) || $self->log_file();
1248 4989 0 33     13664 if ( exists $args->{prefix}
      33        
1249             and $log_level =~ /^D_/
1250             and $log_file =~ /^(STDOUT|STDERR)$/
1251             ) {
1252 0         0 $add_dev_prefix = 1;
1253             }
1254 4989 50       10646 push @prefix, \&_prefix_dev if $add_dev_prefix;
1255 4989 50       12709 push @prefix, $prefix if defined $prefix;
1256 4989         5947 my $code_resolve_cnt = 0;
1257 4989         6257 my $code_resolve_cnt_max = 10;
1258             # really we should have somethings that checks the %args for ALL of the possible settings
1259 4989         5962 my $st = $STACK_TRACE;
1260 4989 50       15255 $STACK_TRACE = exists $args->{stack_trace} ? $args->{stack_trace}
    50          
1261             : defined $self->{stack_trace} ? $self->{stack_trace}
1262             : $STACK_TRACE;
1263            
1264 4989         9430 foreach my $p ( @prefix ) {
1265             CODE_PREFIX:
1266 4989         11877 while ( ref $p eq 'CODE' ) {
1267 926         2458 $p = &$p( $level, $args );
1268 926 50       7840 last CODE_PREFIX if ( $code_resolve_cnt++ > $code_resolve_cnt_max );
1269             }
1270 4989         16532 unshift @inmsg, $p;
1271             #unshift @prefix_out, $p;
1272             }
1273 4989         8377 $STACK_TRACE = $st;# restore the previous setting
1274              
1275             # my $prefix_length = [ split("\n", join( '', @prefix_out)) ];
1276             # $prefix_length = $prefix_length->[-1];
1277             # $prefix_length = length $prefix_length;
1278 4989         5477 my ($msg, $d);
1279 4989         10588 INMSG: while ( scalar @inmsg ) {
1280 14966         27376 $tmp = undef;
1281 14966         20453 $msg = shift @inmsg;
1282 14966 50       28114 defined $msg or $msg = 'undef';#'(UNDEFINED ELEMENT IN LOG MESSAGE ARGUMENTS)';
1283 14966         17581 my $code_resolve_cnt = 0;
1284             CHECK_REF:
1285 14966 50 33     42887 if (( my $ref = ref $msg ) and $dump_refs ) {
1286             # this next line of cruft is here so you can pass arguments to ->dump() without having to prepend with a minus sign
1287 0 0       0 my @extra_args = map { $_ =~ /^(terse|deep|pure|id|indent)$/ ? ( "-$_" => $args->{$_} ) : ( $_ => $args->{$_} ) } keys %$args;
  0         0  
1288 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 );
1289 0 0       0 if ( $ref eq 'CODE' ) {
1290 0         0 $d = &$msg();
1291 0         0 $msg = $d;
1292 0 0 0     0 goto CHECK_REF unless ( ref $msg eq 'CODE' and $code_resolve_cnt++ > $code_resolve_cnt_max );
1293             } else {
1294             #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length + length $msg) ));
1295             #$d = $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x ( $prefix_length) ));
1296             #$d =~ s/^\s+//;
1297             #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, @extra_args, -pad => (' ' x $prefix_length ) );
1298             #$d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
1299 0         0 $d = "\n" . $self->dump(-d=>[$msg],-n=>["$msg"], -deep => 0, -indent => 1, @extra_args );
1300             }
1301 0         0 $msg = $d;
1302             }
1303 14966         46869 push @outmsg, $msg;
1304             }
1305 4989 50 33     11487 if ( $add_dev_prefix
1306             and $outmsg[-1] !~ /\n$/ms
1307             ) {
1308 0         0 push @outmsg, "\n";
1309             };
1310             #return @outmsg;
1311 4989         40241 @msg = @outmsg;
1312             }
1313              
1314 4989 100 50     17754 $n = exists $args->{n} ? $args->{n} : ($self->{n} || "\n");
1315 4989 50       13600 (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 );
1316 4989 50       10717 unless ( $args->{dont_actually_log} ) {
1317             #$return = $self->_actually_log( %$args, -level => $use_level, -message => $return );
1318 4989         40085 %$args = ( %$args, -level => $level, -message => $return );
1319             #sub _actually_log {
1320             {
1321            
1322             #print STDERR $this_package, " ", __LINE__, " ::: OH MY! ... ", $_[0]->dump([ \@_ ]);
1323             #my $self = shift;
1324             #(warn $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@_], -n =>['_']), "\n") if $ENV{LOG_INTERNAL_DEBUG};
1325             #my $args = { @_ };
1326 4989   33     10701 $args->{-terse} ||= $self->{terse};
  4989         36148  
1327 4989   50     12055 $args->{-level} ||= INFO;
1328 4989   50     11513 $args->{-message} ||= ' - -- NO MESSAGE -- - ';
1329 4989         17929 my $fh = $self->fh( %$args );
1330 4989 50       20562 if ( not $fh ) {
1331 0         0 my $log_file = $self->log_file($args->{-level});
1332              
1333 0         0 my $error_level = FATAL;
1334 0 0       0 if ( not $log->handle_fatals() ) {
1335 0         0 $error_level = ERROR;
1336             }
1337 0         0 $intlog->write($error_level, "No filehandle for `", $args->{-level}, "' on `", $log_file, "'", \%FHS_NA);
1338 0 0       0 exit 1 if $log->handle_fatals();
1339             #return undef;
1340 0         0 $return = undef;
1341             }
1342             else {
1343             #print "MESSAGE: $message\n";
1344             #return $self->_WRITE( %$args, -FH => $fh );
1345 4989         22935 $return = $self->_WRITE( -FH => $fh, %$args );
1346             }
1347             };
1348              
1349 4989 50       18979 defined $return or $status = undef;
1350             }
1351             # if ( $use_level eq MESSAGE ) {
1352             # if ( my $email = $args->{email} ? $args->{email} : $self->{email} ) {
1353             # # we should send a message to the bloke?
1354             # } else {
1355             # #$intlog->write(ERROR, "No email address specified to send MESSAGE: $return");
1356             # $self->write(ALERT, "No email address specified to send MESSAGE: $return") unless $self->{DEBUG}{NO_ALERT};
1357             # }
1358             # }
1359 4989         8854 $n = undef;
1360             }
1361 6273 50       13789 ref $return eq 'ARRAY' and $return = join('', map { defined $_ ? $_ : 'undef' } @$return);
  2568 100       8819  
1362             #print STDOUT $this_package, " STDOUT ", __LINE__, " ::: OH MY! ... ", $intlog->dump([ \@_ ]);
1363 6273 100       35874 return wantarray ? ( $status, $return ) : $status ;
1364             }
1365              
1366             sub _actually_log {
1367             #print STDERR $this_package, " ", __LINE__, " ::: OH MY! ... ", $_[0]->dump([ \@_ ]);
1368 0     0   0 my $self = shift;
1369             #(warn $this_package, " STDOUT ", __LINE__, " ::: OH MY!:: ", __PACKAGE__->_caller(), $self->dump(-d=> [\@_], -n =>['_']), "\n") if $ENV{LOG_INTERNAL_DEBUG};
1370 0         0 my $args = { @_ };
1371 0   0     0 $args->{-terse} ||= $self->{terse};
1372 0   0     0 $args->{-level} ||= INFO;
1373 0   0     0 $args->{-message} ||= ' - -- NO MESSAGE -- - ';
1374 0         0 my $fh = $self->fh( %$args );
1375 0 0       0 unless ( $fh ) {
1376 0         0 my $log_file = $self->log_file($args->{-level});
1377              
1378 0         0 my $error_level = FATAL;
1379 0 0       0 if ( not $log->handle_fatals() ) {
1380 0         0 $error_level = ERROR;
1381             }
1382 0         0 $intlog->write($error_level, "No filehandle for `$args->{-level}' on $log_file");
1383             #exit 1;
1384 0         0 return undef;
1385             }
1386             #print "MESSAGE: $message\n";
1387 0         0 return $self->_WRITE( %$args, -FH => $fh );
1388             };
1389              
1390             #@f{qw(package filename line subroutine hasargs wantarray evaltext is_require hints bitmask )}=caller();
1391             my @showf = qw(package filename line subroutine hasargs wantarray evaltext is_require );
1392             sub called_from {
1393 0     0 0 0 my $self = shift;
1394 0 0 0     0 my $f = exists $_[0] ? (shift) : (( ref $self ? 2 : $self ) || 2);
1395 0         0 $intlog->write($dll, '$f: ', $f );
1396 0         0 my $lcpa = $self->_log_called_package( $f );
1397 0         0 $intlog->write($dll, '$lcpa: ', $lcpa );
1398 0         0 my $lcp = $lcpa->[0];
1399 0         0 $intlog->write($dll, '$lcp: ', $lcp );
1400 0         0 return $lcp;
1401             }
1402              
1403             sub _log_called_package {
1404 2778     2778   15368 my $self = shift;
1405 2778   50     10206 my $f = shift || ( ref $self ? 0 : $self ) || 0;
1406 2778         3742 my $nf = $f + 1;
1407 2778         3607 my $log_called_package = '';
1408 2778         2985 my $log_called_file = '';
1409 2778         4070 my @caller = ();
1410 2778         14984 my @f = caller($f);
1411 2778         5438 my ( $package, $filename, $line, $subroutine ) = @f;
1412             #print '( $package, $filename, $line, $subroutine ) = ', "( $package, $filename, $line, $subroutine ) [$f]\n";
1413 2778         7424 my @nf = caller($nf);
1414 2778         4324 my ( $npackage, $nfilename, $nline, $nsubroutine ) = @nf;
1415             #print '( $npackage, $nfilename, $nline, $nsubroutine ) = ', "( $npackage, $nfilename, $nline, $nsubroutine ) [$nf]\n";
1416 2778 100       6556 if ( $nsubroutine ) {
    100          
1417 926         2264 $log_called_package = "$nsubroutine:$line";
1418 926         1774 $log_called_file = "$filename:$line";
1419             } elsif ( $package ) {
1420 926         2159 $log_called_package = "$package:$line";
1421 926         1737 $log_called_file = "$filename:$line";
1422             }
1423 2778         12296 return [ $log_called_package, $log_called_file, \@f, \@nf ];
1424             }
1425              
1426             sub _caller {
1427 926     926   1383 my $self = shift;
1428 926   50     2018 my $f = shift || 0;
1429 926         1426 my @caller = ();
1430 926 50       1973 if ( $STACK_TRACE ) {
1431             # 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?
1432             # did I just do my own for some easier to read formatting?
1433 0         0 my $s = 0;
1434 0         0 my %mes;
1435 0 0       0 my @mes = ({map{$mes{$_}=!$mes{$_}?length$_:($mes{$_}$_);}@showf});
  0 0       0  
  0         0  
1436 0         0 my $width = 0;
1437 0         0 my $depth = 0;
1438 0         0 while (1) {
1439 0         0 my %f;
1440 0         0 $depth = $f + ++$s;
1441 0         0 @f{ @showf, qw( hints bitmask )}= caller($depth);
1442             # 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
1443 0 0       0 last unless join('',map{$f{$_}?$f{$_}:''}(@showf));
  0 0       0  
1444 0         0 $width=0;
1445 0         0 my $x = 0;
1446             #push @mes, "$s => \n\t", join("\n\t",map{(space( $_ . "(" . $x++ . ")") . " => " . ($f{$_}?$f{$_}:'undef')) }@showf), "\n";
1447 0 0 0     0 foreach (@showf) {$f{$_} ||= 'undef';$mes{$_}=!$mes{$_}?length$f{$_}:($mes{$_}
  0 0       0  
  0         0  
  0         0  
1448 0         0 $mes[$depth] = \%f;
1449             }
1450 0         0 my ($c, @c);
1451 0         0 my $sep = '';
1452 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  
1453 0         0 push @caller, @m;
1454             }
1455 926         1971 my $log_called_f = _log_called_package( $f );
1456 926 50       3119 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1457 926         1903 my $log_called_at = _log_called_package( $f + 1 );
1458 926 50       3505 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1459 926 50       1969 if ( not $log_called_at->[0] ) {
1460 0         0 $log_called_at = $log_called_f;
1461             }
1462 926         2342 my $called_called_from = _log_called_package( $f + 2 );
1463 926 50       2181 if ( not $called_called_from->[0] ) {
1464 926         1496 $called_called_from = $log_called_at;
1465             }
1466 926 50       3704 print STDERR 'log_called_f: ', $self->dump( [ $log_called_f ] ), "\n" if $ENV{LOG_DEBUG};
1467 926 50       2153 print STDERR 'log_called_at: ', $self->dump( [ $log_called_at ] ), "\n" if $ENV{LOG_DEBUG};
1468 926 50       1786 print STDERR 'called_called_from: ', $self->dump( [ $called_called_from ] ), "\n" if $ENV{LOG_DEBUG};
1469 926         3442 push @caller, "log call at $log_called_at->[0] in file $log_called_at->[1]";
1470 926         2228 push @caller, "$log_called_at->[0] called from $called_called_from->[0] in file $called_called_from->[1]";
1471 926 50       14351 return wantarray ? @caller : join('', @caller );
1472             }
1473              
1474             LOGS: { # a cache of open log objects for output
1475             # this may not be too desirable in the end because
1476             # you lose individual control of the log level, file ... and such
1477             # although I may be able to fix that
1478             my %LOGS = ( STDOUT => $this_package->object( { log_file => 'STDOUT', log_level => $log_level } ),
1479             STDIN => $this_package->object( { log_file => 'STDIN' , log_level => $log_level } ),
1480             STDERR => $this_package->object( { log_file => 'STDERR', log_level => $log_level } ),
1481             );
1482            
1483             # unless otherwise specified we will use STDERR as our output stream
1484             $LOGS{DEFAULT} = $LOGS{$default_fh};
1485             #use Carp qw( cluck confess );
1486             #local $SIG{__WARN__} = \&cluck;
1487             #local $SIG{__DIE__} = \&confess;
1488            
1489             sub object {
1490             # there should probably be a better way of specifying which existing
1491             # logging object should be used rather than REALLOG
1492 3     3 0 12 my $self = shift;
1493 3   33     19 my $class = ref $self || $self;
1494             #carp( " -- $self->object() CALLER -- " );
1495 3 50       20 $self = $class->new( @_ ) unless ref $self;
1496            
1497 3         11 my @args = @_;
1498 3         7 my $args;
1499            
1500 3 50       11 if ( my $init = shift @args ) {
1501 3 50       12 ref $init eq 'HASH' and $args = $init;
1502 3 50       8 ref $init eq 'ARRAY' and 1;
1503             }
1504 3   50     26 my $log = $args->{log} || $class || 'DEFAULT';
1505 3 50 66     17 $log = $LOGS{$log} ||= ($class eq $this_package ? $self : $this_package->new(@_));
1506            
1507 3 50       67 return $log if $log;
1508             # hmmm failed?
1509 0         0 return delete $LOGS{$log};
1510             }
1511             }
1512              
1513              
1514             #print STDERR __FILE__, ":", __LINE__, " :: \n", $log->dump( -n => [ 'FHS_NA', 'FHS_NO'], -d => [ \%FHS_NA, \%FHS_NO]), "\n";
1515             FILEHANDLES : { # a cache of open filehandles for output
1516             # 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 )
1517             sub close_fh { # simply closes the current filehandle and removes if from the list of open handles
1518 0     0 0 0 my $self = shift;
1519 0         0 my $status = 'NA';
1520 0 0       0 if ( my $fh = $self->fh( @_, no_open => 1 ) ) {
1521 0         0 $intlog->write($dll, '$fh: ', $fh );
1522             #; # 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.
1523 0         0 my $file_no = fileno($fh);
1524 0         0 my $file = $FHN_NO{$file_no};
1525 0         0 my $file_clean = $file;
1526 0         0 $file_clean =~ s/^\s*([>]{1,2})\s*//;
1527 0 0       0 if ( $ENV{LOG_DEBUG} ) {
1528 0         0 print STDERR "file_no='$file_no'\n";
1529 0         0 print STDERR "file='$file'\n";
1530 0         0 print STDERR "file_clean='$file_clean'\n";
1531             }
1532 0 0 0     0 if ($fh and $file_no) {
1533 0 0       0 $status = close($fh) or warn "Couldn't close filehandle on '$file': $!";
1534 0         0 delete $FHS_NA{$file_clean};
1535 0         0 delete $FHS_NO{$file_no};
1536 0         0 delete $FHN_NO{$file_no};
1537             }
1538             } else {
1539             #$intlog->write($dl7, '@_: ', \@_ );
1540             #die;
1541             }
1542 0         0 return $status;
1543             }
1544             *get_fh = \&fh;
1545             sub fh {
1546             # 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
1547             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1548             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1549 4989     4989 0 12799 my $self = shift;
1550             #return $FHS_NA{STDERR};
1551 4989         17791 my $args = { @_ };
1552             #print STDOUT join(" ", @_), "\n";
1553 4989   50     14453 my $level = $args->{-level} || DEFAULT;
1554 4989         5319 my $file;
1555             my $fh;
1556 0         0 my $file_no;
1557 0         0 my $file_clean;
1558             #_WRITE( "SHITBALLS", " \$level = '$level'\n" );
1559 4989 50       16578 if ( $level =~ /^(STDERR|STDOUT)$/i ) {
1560 0         0 $fh = $FHS_NA{"\U$level"};
1561 0         0 $file_no = fileno($fh);
1562 0         0 $file = $level;
1563 0         0 $file_clean = $file;
1564             } else {
1565 4989         16756 $file = $args->{"log_file_$level"};
1566 4989   33     19573 $file ||= $args->{log_file};
1567             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1568             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1569 4989   33     9265 $file ||= $self->{"log_file_$level"};
1570             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1571             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1572 4989   33     8546 $file ||= $self->{log_file};
1573             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1574             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1575 4989   33     8512 $file ||= $LEVEL_FHS{$level};
1576             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1577             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1578 4989   33     8246 $file ||= $default_fh;
1579             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1580             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1581 4989         7278 $fh = $args->{fh};# || $FHS_NA{$file_clean};
1582             # $file_clean = $file;
1583             # $file_clean =~ s/^\s*([>]{1,2})\s*//;
1584             # $fh = $args->{fh} || $FHS_NA{$file_clean};
1585             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1586             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1587             }
1588             #fileno($fh);
1589             #print STDERR __PACKAGE__, ":", __LINE__, "\n";
1590             #print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1591             #print STDERR "FH: [$level] :: ", $fh, ":", fileno($fh), " ::: $file $args->{log_file}\n";
1592             #print STDOUT "FH: [$level] :: ", $fh, ":", fileno($fh), " ::: $file $args->{log_file}\n";
1593             #print STDERR __PACKAGE__, ":", __LINE__, "FH: [$level] :: ", ($fh||'undef'), ":", " ::: $file_clean $args->{log_file}\n";
1594             #print STDOUT __PACKAGE__, ":", __LINE__, "FH: [$level] :: ", ($fh||'undef'), ":", " ::: $file_clean $args->{log_file}\n";
1595 4989         18240 my @fhs;
1596             my $reffh;
1597 4989 50       9187 if ( ref $fh eq 'ARRAY' ) {
1598 0         0 $reffh = 1;
1599 0         0 @fhs = @$fh;
1600             } else {
1601 4989         6275 $reffh = 0;
1602 4989         8438 @fhs = $fh;
1603             }
1604 4989         15635 my @return;
1605 4989 50       11461 if ( $fh ) {
1606 0         0 foreach my $_fh ( @fhs ) {
1607 0         0 $file_no = fileno($_fh);
1608             #print STDERR __PACKAGE__, ":", __LINE__, "file_no: $file_no\n";
1609             #print STDOUT __PACKAGE__, ":", __LINE__, "file_no: $file_no\n";
1610 0 0       0 if ( defined $file_no ) {
1611             # I don't know if I should cache this here, because we may not have been responsible for opening it
1612             #::# $FHS_NA{$file_clean} = $fh;
1613             #::# $FHN_NO{$file_no} = $file;
1614             #::# $FHS_NO{$file_no} = $fh;
1615 0         0 push @return, $_fh;
1616             } else {
1617 0         0 warn "$!: $file";
1618             }
1619             }
1620 0 0       0 return $reffh ? \@return : $return[0];
1621             }
1622            
1623 4989         5243 my @files;
1624             my $reffile;
1625 4989 50       12005 if ( ref $file eq 'ARRAY' ) {
1626 0         0 $reffile = 1;
1627 0         0 @files = @$file;
1628             } else {
1629 4989         5580 $reffile = 0;
1630 4989         8916 @files = $file;
1631             }
1632             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'FHS_NA', 'FHS_NO', 'FHN_NO'], -d => [ \%FHS_NA, \%FHS_NO, \%FHN_NO]), "\n";
1633             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'files'], -d => [ \@files ]), "\n";
1634 4989         7832 foreach my $_file ( @files ) {
1635             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file'], -d => [ $_file ]), "\n";
1636 4989         5425 my $_file_clean;
1637 4989         6057 $_file_clean = $_file;
1638 4989         15369 $_file_clean =~ s/^\s*(\||[>]{1,2})\s*//;
1639             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ '_file_clean'], -d => [ $_file_clean ]), "\n";
1640 4989         9213 my $_fh = $FHS_NA{$_file_clean};
1641 4989 50       12329 if ( $args->{no_open} ) {
1642 0         0 push @return, $_fh;
1643             } else {
1644 4989 100       11680 unless ( $_fh ) {
1645 1 50       9 if ( fileno($_file) ) {
1646 0         0 $_fh = $_file;
1647             } else {
1648 1         3 my $mode;
1649 1 50       6 if ( $_file =~ /^\s*(\||[>]{1,2})/ ) {
1650 0         0 $mode = $1;
1651             } else {
1652 1 50       37 $mode = -f $_file_clean ? '>>' : '>';
1653             }
1654 1 50       11 $_fh = new IO::File or die $!;
1655 1 50       75 print STDERR "Opening new filehandle for '$_file' on '$mode' '$_file_clean'\n" if $ENV{LOG_DEBUG};
1656 1         8 my $opened = $_fh->open( "$mode$_file_clean" );
1657 1 50       60 unless ( $opened ) {
1658 0         0 my $error_level = FATAL;
1659 0 0       0 if ( not $log->handle_fatals() ) {
1660 0         0 $error_level = ERROR;
1661             }
1662 0         0 $intlog->write($error_level, "$mode $_file_clean : $!");
1663 0         0 return undef;
1664             }
1665             #print STDERR "Opened new filehandle '$opened' for '$file' on '$mode' '$file_clean'\n";
1666             #print STDOUT "Opened new filehandle '$opened' for '$file' on '$mode' '$file_clean'\n";
1667             }
1668             }
1669 4989         9172 my $_file_no = fileno($_fh);
1670 4989 50       9009 defined $_file_no or die $!;
1671             #print STDERR "Got fileno on new filehandle '$file_no' for '$file' on '$mode' '$file_clean'\n";
1672             #print STDOUT "Got fileno on new filehandle '$file_no' for '$file' on '$mode' '$file_clean'\n";
1673            
1674             ################################################################################
1675             # this locking screwed me all up once when I was running under mod_perl
1676             # I think it was the exclusive lock collision between different httpd child processes
1677             # I should make this a per-file option I guess
1678             # in any case this wouldn't really work in an NFS environment, because there advisory locks are IPC based
1679             #my $flocked = flock $fh, LOCK_EX or die $!;
1680             #print STDERR "Got lock on new filehandle '$flocked' for '$file' on '$mode' '$file_clean'\n";
1681             #print STDOUT "Got lock on new filehandle '$flocked' for '$file' on '$mode' '$file_clean'\n";
1682             ################################################################################
1683            
1684 4989         8408 $FHS_NA{$_file_clean} = $_fh;
1685 4989         11728 $FHS_NO{$_file_no} = $_fh;
1686 4989         8435 $FHN_NO{$_file_no} = $_file;
1687             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1688             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1689 4989 50 33     22779 ( $self->{unbuffer} or $args->{unbuffer} ) and _unbuffer( $_fh );
1690             # print STDERR __PACKAGE__, ":", __LINE__, "\n";
1691             # print STDOUT __PACKAGE__, ":", __LINE__, "\n";
1692 4989         22290 push @return, $_fh;
1693             }
1694             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'FHS_NA', 'FHS_NO', 'FHN_NO'], -d => [ \%FHS_NA, \%FHS_NO, \%FHN_NO]), "\n";
1695             }
1696 4989 50       34543 return $reffile ? \@return : $return[0];
1697             }
1698            
1699             sub _unbuffer {
1700 4989     4989   6051 my $fh = shift;
1701 4989         21485 my $selected = select;
1702             # disable buffering on this filehandle
1703 4989         9561 select $fh; $| = 1;
  4989         9203  
1704             # restore previously selected filehandle
1705 4989         12873 select $selected;
1706 4989         10569 return $fh;
1707             }
1708            
1709             sub _WRITE {
1710 4989     4989   6868 my $self = shift;
1711             #print STDERR __FILE__, ":", __LINE__, " :: ", $self->dump([ \@_ ]), "\n";
1712 4989         5264 my $message;
1713             my $fh;
1714 4989         13119 my $args = {};
1715 4989 50       17519 if ( $_[0] =~ /^-/ ) {
1716 4989         22095 $args = { @_ };
1717 4989 50       19897 $message = $args->{-message} or return undef;
1718 4989 50       13126 ref $message eq 'ARRAY' or $message = [ $message ] ;
1719 4989         9607 $fh = $args->{-FH};
1720             } else {
1721 0 0       0 shift @_ if ( $fh = $FHS_NA{$_[0]} );
1722 0         0 local $STACK_TRACE = 1;
1723 0         0 print STDERR __FILE__, ":", __LINE__, " :: ", $self->dump([ \@_ ]), "\n";
1724 0 0       0 $message = [ join ' ', __PACKAGE__->_caller(), map { defined $_ ? $_ : 'undef'; } @_ ] ;
  0         0  
1725 0         0 exit 1;
1726             }
1727            
1728 4989   50     12527 my $level = $args->{-level} || CLEAN;
1729            
1730 4989         13809 my $return = join '', @$message;
1731 4989 50       17308 if ( $args->{-terse} ) {
1732 0         0 $return =~ s/\s+/ /mg;
1733             }
1734            
1735 4989   33     10008 $fh ||= $FHS_NA{$default_fh};
1736 4989         13927 my @fhs;
1737             my $reffh;
1738 4989 50       10622 if ( ref $fh eq 'ARRAY' ) {
1739 0         0 $reffh = 1;
1740 0         0 @fhs = @$fh;
1741             } else {
1742 4989         13772 $reffh = 0;
1743 4989         9331 @fhs = $fh;
1744             }
1745            
1746 4989         8439 foreach my $_fh ( @fhs ) {
1747             #print STDERR __FILE__, ":", __LINE__, " :: \n", $self->dump( -n => [ 'fh', 'FHS_NA', 'FHS_NO'], -d => [ $_fh, \%FHS_NA, \%FHS_NO]), "\n";
1748 4989 50 33     19263 fileno($_fh) or $_fh = $FHS_NA{$_fh} or die "Invalid filehandle: " . $self->dump( -n => [ 'fh' ], -d => [ $_fh ] );
1749             #_lock( $_fh );
1750 4989 50       49174 print $_fh $return, $n or die ( "$!: arguments to _WRITE were => " . $self->dump( -n => [ 'args' ], -d => [ $args ] ));
1751             #_unlock( $_fh );
1752             }
1753            
1754             #print STDERR "level=`", ($level || 'undef'), "'\n";
1755 4989 50 66     18353 if ( $level =~ /^(CRIT|FATAL)$/ and ( defined $args->{handle_fatals} ? $args->{handle_fatals} : $self->{handle_fatals} ) ) {
    50          
1756             #local $STACK_TRACE = 1;
1757             #die $self->_caller( ) . "\n$return";
1758             #die "$level\n";
1759 0         0 die "FATAL error! $return\n";
1760             }
1761              
1762 4989 50       25350 if ( $BIG_WARN_ON{$level} ) {
1763             #print STDERR "\n\n\nDOING BIG WARN ON '$level' '$ENV{BIG_WARN_ON_FATAL}'\n\n\n";
1764             #local $STACK_TRACE = 1;
1765 0         0 warn $self->_caller( ) . "\n$return";
1766             #die;
1767             }
1768            
1769 4989 100       11282 if ( $level eq QUIT ) {
1770 56 50 0     236 exit ($args->{QUIT} || $args->{EXIT} || $LOG_CODE{QUIT} ) unless $self->{DEBUG}{NO_QUIT};
1771             }
1772            
1773 4989         24180 return $return;
1774             }
1775             }
1776             sub _lock {
1777 0     0     my $fh = shift;
1778             #flock($fh,LOCK_EX);
1779             # and, in case someone appended
1780             # while we were waiting...
1781 0           seek($fh, 0, 2);
1782             }
1783              
1784             sub _unlock {
1785 0     0     my $fh = shift;
1786             #flock($fh,LOCK_UN);
1787             }
1788 1     1   908 END {
1789             # delete $FHS_NA{STDERR};
1790             # delete $FHS_NA{STDOUT};
1791             # foreach my $fh ( values %FHS_NA ) {
1792             # $fh->close();
1793             # }
1794             }
1795              
1796             1;
1797             __END__