File Coverage

blib/lib/Log/Any/App.pm
Criterion Covered Total %
statement 487 604 80.6
branch 156 252 61.9
condition 25 47 53.1
subroutine 44 50 88.0
pod 1 1 100.0
total 713 954 74.7


line stmt bran cond sub pod time code
1             package Log::Any::App;
2              
3             our $DATE = '2016-01-19'; # DATE
4             our $VERSION = '0.52'; # VERSION
5              
6             # i need this to run on centos 5.x. otherwise all my other servers are debian
7             # 5.x and 6.x+ (perl 5.010).
8 2     2   47984 use 5.008000;
  2         6  
9 2     2   10 use strict;
  2         3  
  2         41  
10 2     2   9 use warnings;
  2         3  
  2         74  
11              
12 2     2   8 use File::Path qw(make_path);
  2         4  
  2         115  
13 2     2   9 use File::Spec;
  2         3  
  2         47  
14 2     2   2372 use Log::Any::IfLOG;
  2         26  
  2         11  
15 2     2   1444 use Log::Any::Adapter;
  2         31460  
  2         16  
16              
17              
18 2     2   73 use vars qw($dbg_ctx);
  2         5  
  2         17823  
19              
20             our %PATTERN_STYLES = (
21             plain => '%m',
22             plain_nl => '%m%n',
23             script_short => '[%r] %m%n',
24             script_long => '[%d] %m%n',
25             daemon => '[pid %P] [%d] %m%n',
26             syslog => '[pid %p] %m',
27             );
28             for (keys %PATTERN_STYLES) {
29             $PATTERN_STYLES{"cat_$_"} = "[cat %c]$PATTERN_STYLES{$_}";
30             $PATTERN_STYLES{"loc_$_"} = "[loc %l]$PATTERN_STYLES{$_}";
31             }
32              
33             my $init_args;
34             our $init_called;
35             my $is_daemon;
36              
37             # poor man's version of 5.10's //
38             sub _ifdef {
39 3482     3482   4831 my $def = pop @_;
40 3482         5840 for (@_) {
41 3482 100       9349 return $_ if defined($_);
42             }
43 3378         9838 $def;
44             }
45              
46             # j=as json (except the last default)
47             sub _ifdefj {
48 144     144   697 require JSON;
49              
50 144         286 my $def = pop @_;
51 144         274 for (@_) {
52 239 50       789 return JSON::decode_json($_) if defined($_);
53             }
54 144         657 $def;
55             }
56              
57             sub init {
58 49 50   49 1 82357 return if $init_called++;
59              
60 49         91 $is_daemon = undef;
61              
62 49         97 my ($args, $caller) = @_;
63 49   66     264 $caller ||= caller();
64              
65 49         126 my $spec = _parse_opts($args, $caller);
66 49 100 33     206 if ($spec->{log} && $spec->{init}) {
67 1         5 _init_log4perl($spec);
68 1 50       3490 if ($ENV{LOG_ENV}) {
69 0         0 my $log_main = Log::Any->get_logger(category => 'main');
70 0         0 $log_main->tracef("Environment variables: %s", \%ENV);
71             }
72             }
73 49         131 $spec;
74             }
75              
76             sub _gen_appender_config {
77 6     6   11 my ($ospec, $apd_name, $filter) = @_;
78              
79 6         11 my $name = $ospec->{name};
80 6         7 my $class;
81 6         8 my $params = {};
82 6 50       36 if ($name =~ /^dir/i) {
    50          
    0          
    0          
    0          
    0          
83 0         0 $class = "Log::Dispatch::Dir";
84 0         0 $params->{dirname} = $ospec->{path};
85 0         0 $params->{filename_pattern} = $ospec->{filename_pattern};
86 0 0       0 $params->{max_size} = $ospec->{max_size} if $ospec->{max_size};
87 0 0       0 $params->{max_files} = $ospec->{histories}+1 if $ospec->{histories};
88 0 0       0 $params->{max_age} = $ospec->{max_age} if $ospec->{max_age};
89             } elsif ($name =~ /^file/i) {
90 6         7 $class = "Log::Dispatch::FileWriteRotate";
91 6         28 my ($dir, $prefix) = $ospec->{path} =~ m!(.+)/(.+)!;
92 6   50     19 $dir ||= "."; $prefix ||= $ospec->{path};
  6   33     12  
93 6         14 $params->{dir} = $dir;
94 6         8 $params->{prefix} = $prefix;
95 6         10 $params->{suffix} = $ospec->{suffix};
96 6         10 $params->{size} = $ospec->{max_size};
97 6         9 $params->{period} = $ospec->{period};
98 6         9 $params->{histories} = $ospec->{histories};
99 6         17 $params->{buffer_size} = $ospec->{buffer_size};
100             } elsif ($name =~ /^screen/i) {
101             $class = "Log::Log4perl::Appender::" .
102 0 0       0 ($ospec->{color} ? "ScreenColoredLevels" : "Screen");
103 0 0       0 $params->{stderr} = $ospec->{stderr} ? 1:0;
104 0         0 $params->{"color.WARN"} = "bold blue"; # blue on black is so unreadable
105             } elsif ($name =~ /^syslog/i) {
106 0         0 $class = "Log::Dispatch::Syslog";
107 0         0 $params->{mode} = 'append';
108 0         0 $params->{ident} = $ospec->{ident};
109 0         0 $params->{facility} = $ospec->{facility};
110             } elsif ($name =~ /^unixsock/i) {
111 0         0 $class = "Log::Log4perl::Appender::Socket::UNIX";
112 0         0 $params->{Socket} = $ospec->{path};
113             } elsif ($name =~ /^array/i) {
114 0         0 $class = "Log::Dispatch::ArrayWithLimits";
115 0         0 $params->{array} = $ospec->{array};
116 0         0 $params->{max_elems} = $ospec->{max_elems};
117             } else {
118 0         0 die "BUG: Unknown appender type: $name";
119             }
120              
121             join(
122             "",
123             "log4perl.appender.$apd_name = $class\n",
124 12         78 (map { "log4perl.appender.$apd_name.$_ = $params->{$_}\n" }
125 6 50       23 grep {defined $params->{$_}} keys %$params),
  42         74  
126             "log4perl.appender.$apd_name.layout = PatternLayout\n",
127             "log4perl.appender.$apd_name.layout.ConversionPattern = $ospec->{pattern}\n",
128             ($filter ? "log4perl.appender.$apd_name.Filter = $filter\n" : ""),
129             );
130             }
131              
132             sub _lit {
133 0     0   0 require Data::Dump;
134 0         0 Data::Dump::dump(shift);
135             }
136              
137             sub _gen_l4p_config {
138 1     1   2 my ($spec) = @_;
139              
140 1         5 my @otypes = qw(file dir screen syslog unixsock array);
141              
142             # we use a custom perl code to implement filter_* specs.
143 1         3 my @fccode;
144 1         3 push @fccode, 'my %p = @_';
145 1         2 push @fccode, 'my $str';
146 1         3 for my $ospec (map { @{ $spec->{$_} } } @otypes) {
  6         8  
  6         16  
147 2 50       8 if (defined $ospec->{filter_text}) {
148 0         0 push @fccode, '$str = '._lit($ospec->{filter_text});
149 0         0 push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
150             ' && index($_, $str) == -1';
151             }
152 2 50       8 if (defined $ospec->{filter_no_text}) {
153 0         0 push @fccode, '$str = '._lit($ospec->{filter_no_text});
154 0         0 push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
155             ' && index($_, $str) > -1';
156             }
157 2 50       7 if (defined $ospec->{filter_citext}) {
158 0         0 push @fccode, '$str = '._lit($ospec->{filter_citext});
159 0         0 push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
160             ' && !/\Q$str/io';
161             }
162 2 50       7 if (defined $ospec->{filter_no_citext}) {
163 0         0 push @fccode, '$str = '._lit($ospec->{filter_no_citext});
164 0         0 push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
165             ' && /\Q$str/io';
166             }
167 2 50       8 if (defined $ospec->{filter_re}) {
168 0         0 push @fccode, '$str = '._lit($ospec->{filter_re});
169             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
170 0 0       0 ' && $_ !~ ' . (ref($ospec->{filter_re}) eq 'Regexp' ? '$str' : 'qr/$str/o');
171             }
172 2 50       6 if (defined $ospec->{filter_no_re}) {
173 0         0 push @fccode, '$str = '._lit($ospec->{filter_no_re});
174             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
175 0 0       0 ' && $_ =~ ' . (ref($ospec->{filter_re}) eq 'Regexp' ? '$str' : 'qr/$str/o');
176             }
177             }
178 1         3 push @fccode, "1";
179 1         4 my $fccode = join "; ", @fccode;
180              
181             my $filters_str = join(
182             "",
183             "log4perl.filter.FilterCustom = sub { $fccode }\n",
184             "\n",
185             "log4perl.filter.FilterOFF0 = Log::Log4perl::Filter::LevelRange\n",
186             "log4perl.filter.FilterOFF0.LevelMin = TRACE\n",
187             "log4perl.filter.FilterOFF0.LevelMax = FATAL\n",
188             "log4perl.filter.FilterOFF0.AcceptOnMatch = false\n",
189             "\n",
190             "log4perl.filter.FilterOFF = Log::Log4perl::Filter::Boolean\n",
191             "log4perl.filter.FilterOFF.logic = FilterOFF0 && FilterCustom\n",
192 1         5 map {join(
  5         39  
193             "",
194             "log4perl.filter.Filter${_}0 = Log::Log4perl::Filter::LevelRange\n",
195             "log4perl.filter.Filter${_}0.LevelMin = $_\n",
196             "log4perl.filter.Filter${_}0.LevelMax = FATAL\n",
197             "log4perl.filter.Filter${_}0.AcceptOnMatch = true\n",
198             "\n",
199             "log4perl.filter.Filter$_ = Log::Log4perl::Filter::Boolean\n",
200             "log4perl.filter.Filter$_.logic = Filter${_}0 && FilterCustom\n",
201             "\n",
202             )} qw(FATAL ERROR WARN INFO DEBUG), # TRACE
203             );
204              
205 1         3 my %levels; # key = output name; value = { cat => level, ... }
206             my %cats; # list of categories
207 0         0 my %ospecs; # key = oname; this is just a shortcut to get ospec
208              
209             # 1. list all levels for each category and output
210 1         3 for my $ospec (map { @{ $spec->{$_} } } @otypes) {
  6         7  
  6         12  
211 2         6 my $oname = $ospec->{name};
212 2         6 $ospecs{$oname} = $ospec;
213 2         5 $levels{$oname} = {};
214 2         3 my %seen_cats;
215 2 50       7 if ($ospec->{category_level}) {
216 2         3 while (my ($cat0, $level) = each %{ $ospec->{category_level} }) {
  6         27  
217 4         11 my @cat = _extract_category($ospec, $cat0);
218 4         8 for my $cat (@cat) {
219 4 50       12 next if $seen_cats{$cat}++;
220 4         7 $cats{$cat}++;
221 4         17 $levels{$oname}{$cat} = $level;
222             }
223             }
224             }
225 2 50       9 if ($spec->{category_level}) {
226 2         3 while (my ($cat0, $level) = each %{ $spec->{category_level} }) {
  4         16  
227 2         5 my @cat = _extract_category($ospec, $cat0);
228 2         9 for my $cat (@cat) {
229 4 50       14 next if $seen_cats{$cat}++;
230 4         7 $cats{$cat}++;
231 4         14 $levels{$oname}{$cat} = $level;
232             }
233             }
234             }
235 2         5 my @cat = _extract_category($ospec);
236 2         5 for my $cat (@cat) {
237 2 50       6 next if $seen_cats{$cat}++;
238 2         3 $cats{$cat}++;
239 2         9 $levels{$oname}{$cat} = $ospec->{level};
240             }
241             }
242             #print Dumper \%levels; exit;
243              
244             my $find_olevel = sub {
245 40     40   58 my ($oname, $cat) = @_;
246 40         63 my $olevel = $levels{$oname}{''};
247 40         80 my @c = split /\./, $cat;
248 40         106 for (my $i=0; $i<@c; $i++) {
249 64         114 my $c = join(".", @c[0..$i]);
250 64 100       190 if ($levels{$oname}{$c}) {
251 42         128 $olevel = $levels{$oname}{$c};
252             }
253             }
254 40         104 $olevel;
255 1         7 };
256              
257             # 2. determine level for each category (which is the minimum level of all
258             # appenders for that category)
259 1         3 my %cat_configs; # key = cat, value = [catlevel, apdname, ...]
260 1         2 my $add_str = '';
261 1         2 my $apd_str = '';
262 1         8 for my $cat0 (sort {$a cmp $b} keys %cats) {
  13         20  
263 7 100       33 $add_str .= "log4perl.additivity.$cat0 = 0\n" unless $cat0 eq '';
264 7         12 my @cats = ($cat0);
265             # since we don't use additivity, we need to add supercategories ourselves
266 7         30 while ($cat0 =~ s/\.[^.]+$//) { push @cats, $cat0 }
  6         25  
267 7         9 for my $cat (@cats) {
268 13         15 my $cat_level;
269 13         23 for my $oname (keys %levels) {
270 26         48 my $olevel = $find_olevel->($oname, $cat);
271 26 50       56 next unless $olevel;
272 26         45 $cat_level = _ifdef($cat_level, $olevel);
273 26         51 $cat_level = _min_level($cat_level, $olevel);
274             }
275 13         51 $cat_configs{$cat} = [uc($cat_level)];
276             #next if $cat_level eq 'off';
277             }
278             }
279             #print Dumper \%cat_configs; exit;
280              
281             # 3. add appenders for each category
282 1         4 my %generated_appenders; # key = apdname, just a memory hash
283 1         5 for my $cat (keys %cat_configs) {
284 7         12 my $cat_level = $cat_configs{$cat}[0];
285 7         15 for my $oname (keys %levels) {
286 14         21 my $ospec = $ospecs{$oname};
287 14         23 my $olevel = $find_olevel->($oname, $cat);
288             #print "D:oname=$oname, cat=$cat, olevel=$olevel, cat_level=$cat_level\n";
289 14         22 my $apd_name;
290             my $filter;
291 14 100 66     46 if ($olevel ne $cat_level &&
292             _min_level($olevel, $cat_level) eq $cat_level) {
293             # we need to filter the appender, since the category level is
294             # lower than the output level
295 5         9 $apd_name = $oname . "_" . uc($olevel);
296 5         9 $filter = "Filter".uc($olevel);
297             } else {
298 9         14 $apd_name = $oname;
299 9         11 $filter = "FilterCustom";
300             }
301 14 100       43 unless ($generated_appenders{$apd_name}++) {
302 6         13 $apd_str .= _gen_appender_config($ospec, $apd_name, $filter).
303             "\n";
304             }
305 14         20 push @{ $cat_configs{$cat} }, $apd_name;
  14         43  
306             }
307             }
308             #print Dumper \%cat_configs; exit;
309              
310             # 4. write out log4perl category line
311 1         4 my $cat_str = '';
312 1         5 for my $cat (sort {$a cmp $b} keys %cat_configs) {
  13         20  
313 7 100       21 my $l = $cat eq '' ? '' : ".$cat";
314 7         19 $cat_str .= "log4perl.logger$l = ".join(", ", @{ $cat_configs{$cat} })."\n";
  7         31  
315             }
316              
317             join(
318 1         26 "",
319             "# filters\n", $filters_str,
320             "# categories\n", $cat_str, $add_str, "\n",
321             "# appenders\n", $apd_str,
322             );
323             }
324              
325             sub _init_log4perl {
326 1     1   1289 require Log::Log4perl;
327              
328 1         55839 my ($spec) = @_;
329              
330             # create intermediate directories for dir
331 1         2 for (@{ $spec->{dir} }) {
  1         6  
332 0         0 my $dir = _dirname($_->{path});
333 0 0 0     0 make_path($dir) if length($dir) && !(-d $dir);
334             }
335              
336             # create intermediate directories for file
337 1         4 for (@{ $spec->{file} }) {
  1         4  
338 2         10 my $dir = _dirname($_->{path});
339 2 50 33     53 make_path($dir) if length($dir) && !(-d $dir);
340             }
341              
342 1         6 my $config_str = _gen_l4p_config($spec);
343 1 50       6 if ($spec->{dump}) {
344 0         0 require Data::Dump;
345 0         0 print "Log::Any::App configuration:\n",
346             Data::Dump::dump($spec);
347 0         0 print "Log4perl configuration: <
348             }
349              
350 1         6 Log::Log4perl->init(\$config_str);
351 1         123904 Log::Any::Adapter->set('Log4perl');
352             }
353              
354             sub _basename {
355 49     49   95 my $path = shift;
356 49         690 my ($vol, $dir, $file) = File::Spec->splitpath($path);
357 49         169 $file;
358             }
359              
360             sub _dirname {
361 2     2   4 my $path = shift;
362 2         35 my ($vol, $dir, $file) = File::Spec->splitpath($path);
363 2         7 $dir;
364             }
365              
366             # we separate args and opts, because we need to export logger early
367             # (BEGIN), but configure logger in INIT (to be able to detect
368             # existence of other modules).
369              
370             sub _parse_args {
371 2     2   5 my ($args, $caller) = @_;
372 2         8 $args = _ifdef($args, []); # if we don't import(), we never get args
373              
374 2         5 my $i = 0;
375 2         9 while ($i < @$args) {
376 10         15 my $arg = $args->[$i];
377 10 100       45 do { $i+=2; next } if $arg =~ /^-(\w+)$/;
  9         12  
  9         32  
378 1 50       7 if ($arg eq '$log') {
379 1         3 _export_logger($caller);
380             } else {
381 0         0 die "Unknown arg '$arg', valid arg is '\$log' or -OPTS";
382             }
383 1         6 $i++;
384             }
385             }
386              
387             sub _parse_opts {
388 49     49   3699 require File::HomeDir;
389              
390 49         15234 my ($args, $caller) = @_;
391 49         134 $args = _ifdef($args, []); # if we don't import(), we never get args
392 49         306 _debug("parse_opts: args = [".join(", ", @$args)."]");
393              
394 49         95 my $i = 0;
395 49         69 my %opts;
396 49         165 while ($i < @$args) {
397 73         124 my $arg = $args->[$i];
398 73 100       380 do { $i++; next } unless $arg =~ /^-(\w+)$/;
  1         2  
  1         3  
399 72         151 my $opt = $1;
400 72 50       190 die "Missing argument for option $opt" unless $i++ < @$args-1;
401 72         125 $arg = $args->[$i];
402 72         171 $opts{$opt} = $arg;
403 72         192 $i++;
404             }
405              
406 49         85 my $spec = {};
407              
408 49         195 $spec->{log} = _ifdef($ENV{LOG}, 1);
409 49 50       166 if (defined $opts{log}) {
410 0         0 $spec->{log} = $opts{log};
411 0         0 delete $opts{log};
412             }
413             # exit as early as possible if we are not doing any logging
414 49 50       128 goto END_PARSE_OPTS unless $spec->{log};
415              
416 49         115 $spec->{name} = _basename($0);
417 49 100       133 if (defined $opts{name}) {
418 6         14 $spec->{name} = $opts{name};
419 6         12 delete $opts{name};
420             }
421              
422 49         196 $spec->{level_flag_paths} = [File::HomeDir->my_home, "/etc"];
423 49 100       1956 if (defined $opts{level_flag_paths}) {
424 4         8 $spec->{level_flag_paths} = $opts{level_flag_paths};
425 4         10 delete $opts{level_flag_paths};
426             }
427              
428 49         186 $spec->{level} = _set_level("", "", $spec);
429 49 50 66     310 if (!$spec->{level} && defined($opts{level})) {
    100          
430 0         0 $spec->{level} = _check_level($opts{level}, "-level");
431 0         0 _debug("Set general level to $spec->{level} (from -level)");
432             } elsif (!$spec->{level}) {
433 31         59 $spec->{level} = "warn";
434 31         101 _debug("Set general level to $spec->{level} (default)");
435             }
436 49         85 delete $opts{level};
437              
438 49         181 $spec->{category_alias} = _ifdefj($ENV{LOG_CATEGORY_ALIAS}, {});
439 49 100       162 if (defined $opts{category_alias}) {
440             die "category_alias must be a hashref"
441 1 50       6 unless ref($opts{category_alias}) eq 'HASH';
442 1         3 $spec->{category_alias} = $opts{category_alias};
443 1         2 delete $opts{category_alias};
444             }
445              
446 49 100       109 if (defined $opts{category_level}) {
447             die "category_level must be a hashref"
448 1 50       5 unless ref($opts{category_level}) eq 'HASH';
449 1         2 $spec->{category_level} = {};
450 1         2 for (keys %{ $opts{category_level} }) {
  1         5  
451             $spec->{category_level}{$_} =
452 1         7 _check_level($opts{category_level}{$_}, "-category_level{$_}");
453             }
454 1         2 delete $opts{category_level};
455             }
456              
457 49         93 $spec->{init} = 1;
458 49 100       116 if (defined $opts{init}) {
459 48         99 $spec->{init} = $opts{init};
460 48         150 delete $opts{init};
461             }
462              
463 49         89 $spec->{daemon} = 0;
464 49 100       105 if (defined $opts{daemon}) {
465 2         5 $spec->{daemon} = $opts{daemon};
466 2         7 _debug("setting is_daemon=$opts{daemon} (from daemon option)");
467 2         3 $is_daemon = $opts{daemon};
468 2         5 delete $opts{daemon};
469             }
470              
471 49         167 $spec->{dump} = $ENV{LOGANYAPP_DEBUG};
472 49 50       109 if (defined $opts{dump}) {
473 0         0 $spec->{dump} = 1;
474 0         0 delete $opts{dump};
475             }
476              
477 49         96 $spec->{filter_text} = $ENV{LOG_FILTER_TEXT};
478 49 50       115 if (defined $opts{filter_text}) {
479 0         0 $spec->{filter_text} = $opts{filter_text};
480 0         0 delete $opts{filter_text};
481             }
482 49         93 $spec->{filter_no_text} = $ENV{LOG_FILTER_NO_TEXT};
483 49 50       120 if (defined $opts{filter_no_text}) {
484 0         0 $spec->{filter_no_text} = $opts{filter_no_text};
485 0         0 delete $opts{filter_no_text};
486             }
487 49         93 $spec->{filter_citext} = $ENV{LOG_FILTER_CITEXT};
488 49 50       105 if (defined $opts{filter_citext}) {
489 0         0 $spec->{filter_citext} = $opts{filter_citext};
490 0         0 delete $opts{filter_citext};
491             }
492 49         92 $spec->{filter_no_citext} = $ENV{LOG_FILTER_NO_CITEXT};
493 49 50       101 if (defined $opts{filter_no_citext}) {
494 0         0 $spec->{filter_no_citext} = $opts{filter_no_citext};
495 0         0 delete $opts{filter_no_citext};
496             }
497 49         83 $spec->{filter_re} = $ENV{LOG_FILTER_RE};
498 49 50       130 if (defined $opts{filter_re}) {
499 0         0 $spec->{filter_re} = $opts{filter_re};
500 0         0 delete $opts{filter_re};
501             }
502 49         103 $spec->{filter_no_re} = $ENV{LOG_FILTER_NO_RE};
503 49 50       101 if (defined $opts{filter_no_re}) {
504 0         0 $spec->{filter_no_re} = $opts{filter_no_re};
505 0         0 delete $opts{filter_no_re};
506             }
507              
508 49         108 $spec->{file} = [];
509 49 100       227 _parse_opt_file($spec, _ifdef($opts{file}, ($0 ne '-e' ? 1:0)));
510 49         333 delete $opts{file};
511              
512 49         182 $spec->{dir} = [];
513 49         160 _parse_opt_dir($spec, _ifdef($opts{dir}, 0));
514 49         94 delete $opts{dir};
515              
516 49         106 $spec->{screen} = [];
517 49         149 _parse_opt_screen($spec, _ifdef($opts{screen}, !_is_daemon()));
518 49         104 delete $opts{screen};
519              
520 49         103 $spec->{syslog} = [];
521 49         158 _parse_opt_syslog($spec, _ifdef($opts{syslog}, _is_daemon()));
522 49         103 delete $opts{syslog};
523              
524 49         93 $spec->{unixsock} = [];
525 49         145 _parse_opt_unixsock($spec, _ifdef($opts{unixsock}, 0));
526 49         299 delete $opts{unixsock};
527              
528 49         104 $spec->{array} = [];
529 49         152 _parse_opt_array($spec, _ifdef($opts{array}, 0));
530 49         98 delete $opts{array};
531              
532 49 50       122 if (keys %opts) {
533 0         0 die "Unknown option(s) ".join(", ", keys %opts)." Known opts are: ".
534             "log, name, level, category_level, category_alias, dump, init, ".
535             "filter_{,no_}{text,citext,re}, file, dir, screen, syslog, ".
536             "unixsock, array";
537             }
538              
539             END_PARSE_OPTS:
540             #use Data::Dump; dd $spec;
541 49         134 $spec;
542             }
543              
544             sub _is_daemon {
545 98 100   98   236 if (defined $is_daemon) { return $is_daemon }
  51         120  
546 47 100       98 if (defined $main::IS_DAEMON) {
547 1         2 $is_daemon = $main::IS_DAEMON;
548 1         5 _debug("Setting is_daemon=$main::IS_DAEMON (from \$main::IS_DAEMON)");
549 1         3 return $main::IS_DAEMON;
550             }
551              
552 46         116 for (
553             "App/Daemon.pm",
554             "Daemon/Easy.pm",
555             "Daemon/Daemonize.pm",
556             "Daemon/Generic.pm",
557             "Daemonise.pm",
558             "Daemon/Simple.pm",
559             "HTTP/Daemon.pm",
560             "IO/Socket/INET/Daemon.pm",
561             #"Mojo/Server/Daemon.pm", # simply loading Mojo::UserAgent will load this too
562             "MooseX/Daemonize.pm",
563             "Net/Daemon.pm",
564             "Net/Server.pm",
565             "Proc/Daemon.pm",
566             "Proc/PID/File.pm",
567             "Win32/Daemon/Simple.pm") {
568 636 100       1640 if ($INC{$_}) {
569 2         9 _debug("setting is_daemon=1 (from existence of module $_)");
570 2         3 $is_daemon = 1;
571 2         6 return 1;
572             }
573             }
574 44         94 _debug("setting is_daemon=0 (no indication that we are a daemon)");
575 44         62 $is_daemon = 0;
576 44         97 0;
577             }
578              
579             sub _parse_opt_OUTPUT {
580 296     296   1211 my (%args) = @_;
581 296         462 my $kind = $args{kind};
582 296         392 my $default_sub = $args{default_sub};
583 296         389 my $postprocess = $args{postprocess};
584 296         423 my $spec = $args{spec};
585 296         385 my $arg = $args{arg};
586              
587 296 100       899 return unless $arg;
588              
589 96 100 100     322 if (!ref($arg) || ref($arg) eq 'HASH') {
    50          
590 95         133 my $name = uc($kind).(@{ $spec->{$kind} }+0);
  95         284  
591 95         167 local $dbg_ctx = $name;
592 95         102 push @{ $spec->{$kind} }, $default_sub->($spec);
  95         257  
593 95         507 $spec->{$kind}[-1]{name} = $name;
594 95 100       279 if (!ref($arg)) {
595             # leave every output parameter as is
596             } else {
597 6         20 for my $k (keys %$arg) {
598 12         26 for ($spec->{$kind}[-1]) {
599 12 50       29 exists($_->{$k}) or die "Invalid $kind argument: $k, please".
600             " only specify one of: " . join(", ", sort keys %$_);
601             $_->{$k} = $k eq 'level' ?
602 12 100       38 _check_level($arg->{$k}, "-$kind") : $arg->{$k};
603 12 100       73 _debug("Set level of $kind to $_->{$k} (spec)")
604             if $k eq 'level';
605             }
606             }
607             }
608 95         181 $spec->{$kind}[-1]{main_spec} = $spec;
609 95         228 _set_pattern($spec->{$kind}[-1], $kind);
610 95 100       400 $postprocess->(spec => $spec, ospec => $spec->{$kind}[-1])
611             if $postprocess;
612             } elsif (ref($arg) eq 'ARRAY') {
613 1         3 for (@$arg) {
614 2         11 _parse_opt_OUTPUT(%args, arg => $_);
615             }
616             } else {
617 0         0 die "Invalid argument for -$kind, ".
618             "must be a boolean or hashref or arrayref";
619             }
620             }
621              
622             sub _set_pattern_style {
623 95     95   159 my ($x) = @_;
624             ($ENV{LOG_SHOW_LOCATION} ? 'loc_':
625 95 50       568 $ENV{LOG_SHOW_CATEGORY} ? 'cat_':'') . $x;
    50          
626             }
627              
628             sub _default_file {
629 48     48   288 require File::HomeDir;
630              
631 48         75 my ($spec) = @_;
632 48         98 my $level = _set_level("file", "file", $spec);
633 48 100       122 if (!$level) {
634 39         72 $level = $spec->{level};
635 39         106 _debug("Set level of file to $level (general level)");
636             }
637             return {
638             level => $level,
639             category_level => _ifdefj($ENV{FILE_LOG_CATEGORY_LEVEL},
640             $ENV{LOG_CATEGORY_LEVEL},
641             $spec->{category_level}),
642             path => $> ? File::Spec->catfile(File::HomeDir->my_home, "$spec->{name}.log") :
643             "/var/log/$spec->{name}.log", # XXX and on Windows?
644             max_size => undef,
645             histories => undef,
646             period => undef,
647             buffer_size => undef,
648             category => '',
649             pattern_style => _set_pattern_style('daemon'),
650             pattern => undef,
651              
652             filter_text => _ifdef($ENV{FILE_LOG_FILTER_TEXT}, $spec->{filter_text}),
653             filter_no_text => _ifdef($ENV{FILE_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
654             filter_citext => _ifdef($ENV{FILE_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
655             filter_no_citext => _ifdef($ENV{FILE_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
656             filter_re => _ifdef($ENV{FILE_LOG_FILTER_RE}, $spec->{filter_re}),
657 48 50       243 filter_no_re => _ifdef($ENV{FILE_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
658             };
659             }
660              
661             sub _parse_opt_file {
662 49     49   87 my ($spec, $arg) = @_;
663              
664 49 100 100     538 if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
      100        
665 2         6 $arg = {path => $arg};
666             }
667              
668             _parse_opt_OUTPUT(
669             kind => 'file', default_sub => \&_default_file,
670             spec => $spec, arg => $arg,
671             postprocess => sub {
672 48     48   156 my (%args) = @_;
673 48         86 my $spec = $args{spec};
674 48         66 my $ospec = $args{ospec};
675 48 100       312 if ($ospec->{path} =~ m!/$!) {
676 2         5 my $p = $ospec->{path};
677 2         5 $p .= "$spec->{name}.log";
678 2         9 _debug("File path ends with /, assumed to be dir, ".
679             "final path becomes $p");
680 2         10 $ospec->{path} = $p;
681             }
682             },
683 49         356 );
684             }
685              
686             sub _default_dir {
687 0     0   0 require File::HomeDir;
688              
689 0         0 my ($spec) = @_;
690 0         0 my $level = _set_level("dir", "dir", $spec);
691 0 0       0 if (!$level) {
692 0         0 $level = $spec->{level};
693 0         0 _debug("Set level of dir to $level (general level)");
694             }
695             return {
696             level => $level,
697             category_level => _ifdefj($ENV{DIR_LOG_CATEGORY_LEVEL},
698             $ENV{LOG_CATEGORY_LEVEL},
699             $spec->{category_level}),
700             path => $> ? File::Spec->catfile(File::HomeDir->my_home, "log", $spec->{name}) :
701             "/var/log/$spec->{name}", # XXX and on Windows?
702             max_size => undef,
703             max_age => undef,
704             histories => undef,
705             category => '',
706             pattern_style => _set_pattern_style('plain'),
707             pattern => undef,
708             filename_pattern => undef,
709              
710             filter_text => _ifdef($ENV{DIR_LOG_FILTER_TEXT}, $spec->{filter_text}),
711             filter_no_text => _ifdef($ENV{DIR_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
712             filter_citext => _ifdef($ENV{DIR_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
713             filter_no_citext => _ifdef($ENV{DIR_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
714             filter_re => _ifdef($ENV{DIR_LOG_FILTER_RE}, $spec->{filter_re}),
715 0 0       0 filter_no_re => _ifdef($ENV{DIR_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
716             };
717             }
718              
719             sub _parse_opt_dir {
720 49     49   87 my ($spec, $arg) = @_;
721              
722 49 50 33     310 if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
      33        
723 0         0 $arg = {path => $arg};
724             }
725              
726             _parse_opt_OUTPUT(
727 49         126 kind => 'dir', default_sub => \&_default_dir,
728             spec => $spec, arg => $arg,
729             );
730             }
731              
732             sub _default_screen {
733 43     43   64 my ($spec) = @_;
734 43         87 my $level = _set_level("screen", "screen", $spec);
735 43 100       108 if (!$level) {
736 34         66 $level = $spec->{level};
737 34         179 _debug("Set level of screen to $level (general level)");
738             }
739             return {
740             color => _ifdef($ENV{COLOR}, (-t STDOUT)),
741             stderr => 1,
742             level => $level,
743             category_level => _ifdefj($ENV{SCREEN_LOG_CATEGORY_LEVEL},
744             $ENV{LOG_CATEGORY_LEVEL},
745             $spec->{category_level}),
746             category => '',
747             pattern_style => _set_pattern_style(
748             $ENV{LOG_ELAPSED_TIME_IN_SCREEN} ? 'script_short' : 'plain_nl'),
749             pattern => undef,
750              
751             filter_text => _ifdef($ENV{SCREEN_LOG_FILTER_TEXT}, $spec->{filter_text}),
752             filter_no_text => _ifdef($ENV{SCREEN_FILTER_NO_TEXT}, $spec->{filter_no_text}),
753             filter_citext => _ifdef($ENV{SCREEN_FILTER_CITEXT}, $spec->{filter_citext}),
754             filter_no_citext => _ifdef($ENV{SCREEN_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
755             filter_re => _ifdef($ENV{SCREEN_FILTER_RE}, $spec->{filter_re}),
756 43 50       225 filter_no_re => _ifdef($ENV{SCREEN_FILTER_NO_RE}, $spec->{filter_no_re}),
757             };
758             }
759              
760             sub _parse_opt_screen {
761 49     49   86 my ($spec, $arg) = @_;
762 49         127 _parse_opt_OUTPUT(
763             kind => 'screen', default_sub => \&_default_screen,
764             spec => $spec, arg => $arg,
765             );
766             }
767              
768             sub _default_syslog {
769 4     4   6 my ($spec) = @_;
770 4         9 my $level = _set_level("syslog", "syslog", $spec);
771 4 50       13 if (!$level) {
772 4         6 $level = $spec->{level};
773 4         11 _debug("Set level of syslog to $level (general level)");
774             }
775             return {
776             level => $level,
777             category_level => _ifdefj($ENV{SYSLOG_LOG_CATEGORY_LEVEL},
778             $ENV{LOG_CATEGORY_LEVEL},
779             $spec->{category_level}),
780             ident => $spec->{name},
781             facility => 'daemon',
782             pattern_style => _set_pattern_style('syslog'),
783             pattern => undef,
784             category => '',
785              
786             filter_text => _ifdef($ENV{SYSLOG_LOG_FILTER_TEXT}, $spec->{filter_text}),
787             filter_no_text => _ifdef($ENV{SYSLOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
788             filter_citext => _ifdef($ENV{SYSLOG_FILTER_CITEXT}, $spec->{filter_citext}),
789             filter_no_citext => _ifdef($ENV{SYSLOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
790             filter_re => _ifdef($ENV{SYSLOG_FILTER_RE}, $spec->{filter_re}),
791 4         18 filter_no_re => _ifdef($ENV{SYSLOG_FILTER_NO_RE}, $spec->{filter_no_re}),
792             };
793             }
794              
795             sub _parse_opt_syslog {
796 49     49   84 my ($spec, $arg) = @_;
797 49         132 _parse_opt_OUTPUT(
798             kind => 'syslog', default_sub => \&_default_syslog,
799             spec => $spec, arg => $arg,
800             );
801             }
802              
803             sub _default_unixsock {
804 0     0   0 require File::HomeDir;
805              
806 0         0 my ($spec) = @_;
807 0         0 my $level = _set_level("unixsock", "unixsock", $spec);
808 0 0       0 if (!$level) {
809 0         0 $level = $spec->{level};
810 0         0 _debug("Set level of unixsock to $level (general level)");
811             }
812             return {
813             level => $level,
814             category_level => _ifdefj($ENV{UNIXSOCK_LOG_CATEGORY_LEVEL},
815             $ENV{LOG_CATEGORY_LEVEL},
816             $spec->{category_level}),
817             path => $> ? File::Spec->catfile(File::HomeDir->my_home, "$spec->{name}-log.sock") :
818             "/var/run/$spec->{name}-log.sock", # XXX and on Windows?
819             category => '',
820             pattern_style => _set_pattern_style('daemon'),
821             pattern => undef,
822              
823             filter_text => _ifdef($ENV{UNIXSOCK_LOG_FILTER_TEXT}, $spec->{filter_text}),
824             filter_no_text => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
825             filter_citext => _ifdef($ENV{UNIXSOCK_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
826             filter_no_citext => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
827             filter_re => _ifdef($ENV{UNIXSOCK_LOG_FILTER_RE}, $spec->{filter_re}),
828 0 0       0 filter_no_re => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
829             };
830             }
831              
832             sub _parse_opt_unixsock {
833 49     49   81 my ($spec, $arg) = @_;
834              
835 49 50 33     266 if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
      33        
836 0         0 $arg = {path => $arg};
837             }
838              
839             _parse_opt_OUTPUT(
840             kind => 'unixsock', default_sub => \&_default_unixsock,
841             spec => $spec, arg => $arg,
842             postprocess => sub {
843 0     0   0 my (%args) = @_;
844 0         0 my $spec = $args{spec};
845 0         0 my $ospec = $args{ospec};
846 0 0       0 if ($ospec->{path} =~ m!/$!) {
847 0         0 my $p = $ospec->{path};
848 0         0 $p .= "$spec->{name}-log.sock";
849 0         0 _debug("Unix socket path ends with /, assumed to be dir, ".
850             "final path becomes $p");
851 0         0 $ospec->{path} = $p;
852             }
853              
854             # currently Log::Log4perl::Appender::Socket::UNIX *connects to an
855             # existing and listening* Unix socket and prints log to it. we are
856             # *not* creating a listening unix socket where clients can connect
857             # and see logs. to do that, we'll need a separate thread/process
858             # that listens to unix socket and stores (some) log entries and
859             # display it to users when they connect and request them.
860             #
861             #if ($ospec->{create} && !(-e $ospec->{path})) {
862             # _debug("Creating Unix socket $ospec->{path} ...");
863             # require IO::Socket::UNIX::Util;
864             # IO::Socket::UNIX::Util::create_unix_socket(
865             # $ospec->{path});
866             #}
867             },
868 49         280 );
869             }
870              
871             sub _default_array {
872 0     0   0 my ($spec) = @_;
873 0         0 my $level = _set_level("array", "array", $spec);
874 0 0       0 if (!$level) {
875 0         0 $level = $spec->{level};
876 0         0 _debug("Set level of array to $level (general level)");
877             }
878             return {
879             level => $level,
880             category_level => _ifdefj($ENV{ARRAY_LOG_CATEGORY_LEVEL},
881             $ENV{LOG_CATEGORY_LEVEL},
882             $spec->{category_level}),
883             array => [],
884             max_elems => undef,
885             category => '',
886             pattern_style => _set_pattern_style('script_long'),
887             pattern => undef,
888              
889             filter_text => _ifdef($ENV{ARRAY_LOG_FILTER_TEXT}, $spec->{filter_text}),
890             filter_no_text => _ifdef($ENV{ARRAY_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
891             filter_citext => _ifdef($ENV{ARRAY_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
892             filter_no_citext => _ifdef($ENV{ARRAY_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
893             filter_re => _ifdef($ENV{ARRAY_LOG_FILTER_RE}, $spec->{filter_re}),
894 0         0 filter_no_re => _ifdef($ENV{ARRAY_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
895             };
896             }
897              
898             sub _parse_opt_array {
899 49     49   87 my ($spec, $arg) = @_;
900              
901 49         121 _parse_opt_OUTPUT(
902             kind => 'array', default_sub => \&_default_array,
903             spec => $spec, arg => $arg,
904             );
905             }
906              
907             sub _set_pattern {
908 95     95   155 my ($s, $name) = @_;
909 95         240 _debug("Setting $name pattern ...");
910 95 50       281 unless (defined($s->{pattern})) {
911             die "BUG: neither pattern nor pattern_style is defined ($name)"
912 95 50       231 unless defined($s->{pattern_style});
913             die "Unknown pattern style for $name `$s->{pattern_style}`, ".
914             "use one of: ".join(", ", keys %PATTERN_STYLES)
915 95 50       276 unless defined($PATTERN_STYLES{ $s->{pattern_style} });
916 95         187 $s->{pattern} = $PATTERN_STYLES{ $s->{pattern_style} };
917 95         350 _debug("Set $name pattern to `$s->{pattern}` ".
918             "(from style `$s->{pattern_style}`)");
919             }
920             }
921              
922             sub _extract_category {
923 8     8   13 my ($ospec, $c) = @_;
924 8         18 my $c0 = _ifdef($c, $ospec->{category});
925 8         13 my @res;
926 8 50       18 if (ref($c0) eq 'ARRAY') { @res = @$c0 } else { @res = ($c0) }
  0         0  
  8         16  
927             # replace alias with real value
928 8         22 for (my $i=0; $i<@res; $i++) {
929 8         12 my $c1 = $res[$i];
930 8         18 my $a = $ospec->{main_spec}{category_alias}{$c1};
931 8 100       27 next unless defined($a);
932 2 50       7 if (ref($a) eq 'ARRAY') {
933 2         6 splice @res, $i, 1, @$a;
934 2         8 $i += (@$a-1);
935             } else {
936 0         0 $res[$i] = $a;
937             }
938             }
939 8         16 for (@res) {
940 10         24 s/::/./g;
941             # $_ = lc; # XXX do we need this?
942             }
943 8         24 @res;
944             }
945              
946             sub _cat2apd {
947 0     0   0 my $cat = shift;
948 0         0 $cat =~ s/[^A-Za-z0-9_]+/_/g;
949 0         0 $cat;
950             }
951              
952             sub _check_level {
953 25     25   54 my ($level, $from) = @_;
954 25 50       147 $level =~ /^(off|fatal|error|warn|info|debug|trace)$/i
955             or die "Unknown level (from $from): $level";
956 25         94 lc($1);
957             }
958              
959             sub _set_level {
960 144     144   258 my ($prefix, $which, $spec) = @_;
961             #use Data::Dump; dd $spec;
962 144 100       394 my $p_ = $prefix ? "${prefix}_" : "";
963 144 100       295 my $P_ = $prefix ? uc("${prefix}_") : "";
964 144 100       277 my $F_ = $prefix ? ucfirst("${prefix}_") : "";
965 144 100       268 my $pd = $prefix ? "${prefix}-" : "";
966 144 100       2473 my $pr = $prefix ? qr/$prefix(_|-)/ : qr//;
967 144         235 my ($level, $from);
968              
969 144         629 my @label2level =([trace=>"trace"], [debug=>"debug"],
970             [verbose=>"info"], [quiet=>"error"]);
971              
972 144 100       463 _debug("Setting ", ($which ? "level of $which" : "general level"), " ...");
973             SET:
974             {
975 144 50       207 if ($INC{"App/Options.pm"}) {
  144         313  
976 0         0 my $key;
977 0         0 for (qw/log_level loglevel/) {
978 0         0 $key = $p_ . $_;
979 0         0 _debug("Checking \$App::options{$key}: ", _ifdef($App::options{$key}, "(undef)"));
980 0 0       0 if ($App::options{$key}) {
981 0         0 $level = _check_level($App::options{$key}, "\$App::options{$key}");
982 0         0 $from = "\$App::options{$key}";
983 0         0 last SET;
984             }
985             }
986 0         0 for (@label2level) {
987 0         0 $key = $p_ . $_->[0];
988 0         0 _debug("Checking \$App::options{$key}: ", _ifdef($App::options{$key}, "(undef)"));
989 0 0       0 if ($App::options{$key}) {
990 0         0 $level = $_->[1];
991 0         0 $from = "\$App::options{$key}";
992 0         0 last SET;
993             }
994             }
995             }
996              
997 144         177 my $i = 0;
998 144         243 _debug("Checking \@ARGV ...");
999 144         368 while ($i < @ARGV) {
1000 36         51 my $arg = $ARGV[$i];
1001 36         54 $from = "cmdline arg $arg";
1002 36 50       638 if ($arg =~ /^--${pr}log[_-]?level=(.+)/) {
1003 0         0 _debug("\$ARGV[$i] looks like an option to specify level: $arg");
1004 0         0 $level = _check_level($1, "ARGV $arg");
1005 0         0 last SET;
1006             }
1007 36 100 66     549 if ($arg =~ /^--${pr}log[_-]?level$/ and $i < @ARGV-1) {
1008 6         13 _debug("\$ARGV[$i] and \$ARGV[${\($i+1)}] looks like an option to specify level: $arg ", $ARGV[$i+1]);
  6         30  
1009 6         25 $level = _check_level($ARGV[$i+1], "ARGV $arg ".$ARGV[$i+1]);
1010 6         18 last SET;
1011             }
1012 30         63 for (@label2level) {
1013 120 100       3613 if ($arg =~ /^--${pr}$_->[0](=(1|yes|true))?$/i) {
1014 2         9 _debug("\$ARGV[$i] looks like an option to specify level: $arg");
1015 2         4 $level = $_->[1];
1016 2         8 last SET;
1017             }
1018             }
1019 28         92 $i++;
1020             }
1021              
1022 136         248 for (qw/LOG_LEVEL LOGLEVEL/) {
1023 270         451 my $key = $P_ . $_;
1024 270         946 _debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)"));
1025 270 100       1005 if ($ENV{$key}) {
1026 2         8 $level = _check_level($ENV{$key}, "ENV $key");
1027 2         6 $from = "\$ENV{$key}";
1028 2         6 last SET;
1029             }
1030             }
1031 134         244 for (@label2level) {
1032 533         1095 my $key = $P_ . uc($_->[0]);
1033 533         1589 _debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)"));
1034 533 100       1831 if ($ENV{$key}) {
1035 2         4 $level = $_->[1];
1036 2         6 $from = "\$ENV{$key}";
1037 2         7 last SET;
1038             }
1039             }
1040              
1041 132         161 for my $dir (@{$spec->{level_flag_paths}}) {
  132         323  
1042 252         436 for (@label2level) {
1043 999         2296 my $filename = "$dir/$spec->{name}." . $P_ . "log_level";
1044 999         13547 my $exists = -f $filename;
1045 999         1137 my $content;
1046 999 100       1825 if ($exists) {
1047 2         68 open my($f), $filename;
1048 2         47 $content = <$f>;
1049 2 50       15 chomp($content) if defined($content);
1050 2         19 close $f;
1051             }
1052 999 100       3037 _debug("Checking level flag file content $filename: ",
1053             (defined($content) ? $content : "(undef)"));
1054 999 100       2325 if (defined $content) {
1055 2         7 $level = _check_level($content,
1056             "level flag file $filename");
1057 2         4 $from = $filename;
1058 2         6 last SET;
1059             }
1060              
1061 997         2500 $filename = "$dir/$spec->{name}." . $P_ . uc($_->[0]);
1062 997         12093 $exists = -e $filename;
1063 997 100       3218 _debug("Checking level flag file $filename: ",
1064             ($exists ? "EXISTS" : 0));
1065 997 100       2892 if ($exists) {
1066 2         5 $level = $_->[1];
1067 2         3 $from = $filename;
1068 2         6 last SET;
1069             }
1070             }
1071             }
1072              
1073 2     2   18 no strict 'refs';
  2         9  
  2         1124  
1074 128         451 for ("${F_}Log_Level", "${P_}LOG_LEVEL", "${p_}log_level",
1075             "${F_}LogLevel", "${P_}LOGLEVEL", "${p_}loglevel") {
1076 738         1126 my $varname = "main::$_";
1077 738         2256 _debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)"));
1078 738 100       2846 if ($$varname) {
1079 12         22 $from = "\$$varname";
1080 12         48 $level = _check_level($$varname, "\$$varname");
1081 12         38 last SET;
1082             }
1083             }
1084 116         225 for (@label2level) {
1085 452         1494 for my $varname (
1086             "main::$F_" . ucfirst($_->[0]),
1087             "main::$P_" . uc($_->[0])) {
1088 900         2540 _debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)"));
1089 900 100       3309 if ($$varname) {
1090 8         18 $from = "\$$varname";
1091 8         13 $level = $_->[1];
1092 8         23 last SET;
1093             }
1094             }
1095             }
1096             }
1097              
1098 144 100       457 _debug("Set ", ($which ? "level of $which" : "general level"), " to $level (from $from)") if $level;
    100          
1099 144         755 return $level;
1100             }
1101              
1102             # return the lower level (e.g. _min_level("debug", "INFO") -> INFO
1103             sub _min_level {
1104 40     40   62 my ($l1, $l2) = @_;
1105 40         161 my %vals = (OFF=>99,
1106             FATAL=>6, ERROR=>5, WARN=>4, INFO=>3, DEBUG=>2, TRACE=>1);
1107 40 100       187 $vals{uc($l1)} > $vals{uc($l2)} ? $l2 : $l1;
1108             }
1109              
1110             sub _export_logger {
1111 1     1   2 my ($caller) = @_;
1112 1         6 my $log_for_caller = Log::Any->get_logger(category => $caller);
1113 1         9383 my $varname = "$caller\::log";
1114 2     2   35 no strict 'refs';
  2         4  
  2         285  
1115 1         5 *$varname = \$log_for_caller;
1116             }
1117              
1118             sub _debug {
1119 5169 50   5169   12463 return unless $ENV{LOGANYAPP_DEBUG};
1120 0 0       0 print $dbg_ctx, ": " if $dbg_ctx;
1121 0         0 print @_, "\n";
1122             }
1123              
1124             sub import {
1125 2     2   44 my ($self, @args) = @_;
1126 2         6 my $caller = caller();
1127 2         7 _parse_args(\@args, $caller);
1128 2         67 $init_args = \@args;
1129             }
1130              
1131             {
1132 2     2   10 no warnings;
  2         6  
  2         216  
1133             # if we are loaded at run-time, it's too late to run INIT blocks, so user
1134             # must call init() manually. but sometimes this is what the user wants. so
1135             # shut up perl warning.
1136             INIT {
1137 2     2   56 my $caller = caller();
1138 2         12 init($init_args, $caller);
1139             }
1140             }
1141              
1142             1;
1143             # ABSTRACT: An easy way to use Log::Any in applications
1144              
1145             __END__