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