| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Log::Any::App; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $DATE = '2019-01-09'; # DATE |
|
4
|
|
|
|
|
|
|
our $VERSION = '0.540'; # 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
|
|
44026
|
use 5.008000; |
|
|
2
|
|
|
|
|
14
|
|
|
9
|
2
|
|
|
2
|
|
10
|
use strict; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
52
|
|
|
10
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
83
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
11
|
use File::Path qw(make_path); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
138
|
|
|
13
|
2
|
|
|
2
|
|
13
|
use File::Spec; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
60
|
|
|
14
|
2
|
|
|
2
|
|
1681
|
use Log::Any::IfLOG; |
|
|
2
|
|
|
|
|
37
|
|
|
|
2
|
|
|
|
|
10
|
|
|
15
|
2
|
|
|
2
|
|
876
|
use Log::Any::Adapter; |
|
|
2
|
|
|
|
|
19888
|
|
|
|
2
|
|
|
|
|
11
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
2
|
|
|
2
|
|
81
|
use vars qw($dbg_ctx); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
16658
|
|
|
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
|
|
5027
|
my $def = pop @_; |
|
39
|
3482
|
|
|
|
|
5033
|
for (@_) { |
|
40
|
3482
|
100
|
|
|
|
7181
|
return $_ if defined($_); |
|
41
|
|
|
|
|
|
|
} |
|
42
|
3378
|
|
|
|
|
8423
|
$def; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# j=as json (except the last default) |
|
46
|
|
|
|
|
|
|
sub _ifdefj { |
|
47
|
144
|
|
|
144
|
|
714
|
require JSON::MaybeXS; |
|
48
|
|
|
|
|
|
|
|
|
49
|
144
|
|
|
|
|
294
|
my $def = pop @_; |
|
50
|
144
|
|
|
|
|
251
|
for (@_) { |
|
51
|
239
|
50
|
|
|
|
551
|
return JSON::MaybeXS::decode_json($_) if defined($_); |
|
52
|
|
|
|
|
|
|
} |
|
53
|
144
|
|
|
|
|
870
|
$def; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub init { |
|
57
|
49
|
50
|
|
49
|
1
|
72376
|
return if $init_called++; |
|
58
|
|
|
|
|
|
|
|
|
59
|
49
|
|
|
|
|
85
|
$is_daemon = undef; |
|
60
|
|
|
|
|
|
|
|
|
61
|
49
|
|
|
|
|
96
|
my ($args, $caller) = @_; |
|
62
|
49
|
|
66
|
|
|
248
|
$caller ||= caller(); |
|
63
|
|
|
|
|
|
|
|
|
64
|
49
|
|
|
|
|
116
|
my $spec = _parse_opts($args, $caller); |
|
65
|
49
|
100
|
66
|
|
|
198
|
if ($spec->{log} && $spec->{init}) { |
|
66
|
1
|
|
|
|
|
5
|
_init_log4perl($spec); |
|
67
|
1
|
50
|
|
|
|
2710
|
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
|
|
|
|
|
152
|
$spec; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub _gen_appender_config { |
|
76
|
6
|
|
|
6
|
|
12
|
my ($ospec, $apd_name, $filter) = @_; |
|
77
|
|
|
|
|
|
|
|
|
78
|
6
|
|
|
|
|
11
|
my $name = $ospec->{name}; |
|
79
|
6
|
|
|
|
|
8
|
my $class; |
|
80
|
6
|
|
|
|
|
9
|
my $params = {}; |
|
81
|
6
|
50
|
|
|
|
27
|
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
|
|
|
|
|
10
|
$class = "Log::Dispatch::FileWriteRotate"; |
|
90
|
6
|
|
|
|
|
27
|
my ($dir, $prefix) = $ospec->{path} =~ m!(.+)/(.+)!; |
|
91
|
6
|
|
50
|
|
|
15
|
$dir ||= "."; $prefix ||= $ospec->{path}; |
|
|
6
|
|
33
|
|
|
16
|
|
|
92
|
6
|
|
|
|
|
14
|
$params->{dir} = $dir; |
|
93
|
6
|
|
|
|
|
10
|
$params->{prefix} = $prefix; |
|
94
|
6
|
|
|
|
|
8
|
$params->{suffix} = $ospec->{suffix}; |
|
95
|
6
|
|
|
|
|
12
|
$params->{size} = $ospec->{max_size}; |
|
96
|
6
|
|
|
|
|
7
|
$params->{period} = $ospec->{period}; |
|
97
|
6
|
|
|
|
|
9
|
$params->{histories} = $ospec->{histories}; |
|
98
|
6
|
|
|
|
|
11
|
$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
|
|
|
|
|
75
|
(map { "log4perl.appender.$apd_name.$_ = $params->{$_}\n" } |
|
124
|
6
|
50
|
|
|
|
26
|
grep {defined $params->{$_}} keys %$params), |
|
|
42
|
|
|
|
|
69
|
|
|
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
|
|
4
|
my ($spec) = @_; |
|
138
|
|
|
|
|
|
|
|
|
139
|
1
|
|
|
|
|
5
|
my @otypes = qw(file dir screen syslog unixsock array); |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# we use a custom perl code to implement filter_* specs. |
|
142
|
1
|
|
|
|
|
2
|
my @fccode; |
|
143
|
1
|
|
|
|
|
2
|
push @fccode, 'my %p = @_'; |
|
144
|
1
|
|
|
|
|
2
|
push @fccode, 'my $str'; |
|
145
|
1
|
|
|
|
|
3
|
for my $ospec (map { @{ $spec->{$_} } } @otypes) { |
|
|
6
|
|
|
|
|
7
|
|
|
|
6
|
|
|
|
|
15
|
|
|
146
|
2
|
50
|
|
|
|
7
|
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
|
|
|
|
6
|
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
|
|
|
|
6
|
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
|
|
|
|
6
|
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
|
|
|
|
|
3
|
push @fccode, "1"; |
|
178
|
1
|
|
|
|
|
5
|
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
|
|
|
|
|
6
|
map {join( |
|
|
5
|
|
|
|
|
29
|
|
|
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
|
|
|
|
|
4
|
my %levels; # key = output name; value = { cat => level, ... } |
|
205
|
|
|
|
|
|
|
my %cats; # list of categories |
|
206
|
1
|
|
|
|
|
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
|
|
|
|
|
4
|
for my $ospec (map { @{ $spec->{$_} } } @otypes) { |
|
|
6
|
|
|
|
|
7
|
|
|
|
6
|
|
|
|
|
12
|
|
|
210
|
2
|
|
|
|
|
5
|
my $oname = $ospec->{name}; |
|
211
|
2
|
|
|
|
|
4
|
$ospecs{$oname} = $ospec; |
|
212
|
2
|
|
|
|
|
5
|
$levels{$oname} = {}; |
|
213
|
2
|
|
|
|
|
3
|
my %seen_cats; |
|
214
|
2
|
50
|
|
|
|
7
|
if ($ospec->{category_level}) { |
|
215
|
2
|
|
|
|
|
3
|
while (my ($cat0, $level) = each %{ $ospec->{category_level} }) { |
|
|
6
|
|
|
|
|
75
|
|
|
216
|
4
|
|
|
|
|
12
|
my @cat = _extract_category($ospec, $cat0); |
|
217
|
4
|
|
|
|
|
8
|
for my $cat (@cat) { |
|
218
|
4
|
50
|
|
|
|
12
|
next if $seen_cats{$cat}++; |
|
219
|
4
|
|
|
|
|
6
|
$cats{$cat}++; |
|
220
|
4
|
|
|
|
|
11
|
$levels{$oname}{$cat} = $level; |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
2
|
50
|
|
|
|
6
|
if ($spec->{category_level}) { |
|
225
|
2
|
|
|
|
|
3
|
while (my ($cat0, $level) = each %{ $spec->{category_level} }) { |
|
|
4
|
|
|
|
|
14
|
|
|
226
|
2
|
|
|
|
|
5
|
my @cat = _extract_category($ospec, $cat0); |
|
227
|
2
|
|
|
|
|
3
|
for my $cat (@cat) { |
|
228
|
4
|
50
|
|
|
|
12
|
next if $seen_cats{$cat}++; |
|
229
|
4
|
|
|
|
|
6
|
$cats{$cat}++; |
|
230
|
4
|
|
|
|
|
10
|
$levels{$oname}{$cat} = $level; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
} |
|
234
|
2
|
|
|
|
|
5
|
my @cat = _extract_category($ospec); |
|
235
|
2
|
|
|
|
|
4
|
for my $cat (@cat) { |
|
236
|
2
|
50
|
|
|
|
6
|
next if $seen_cats{$cat}++; |
|
237
|
2
|
|
|
|
|
2
|
$cats{$cat}++; |
|
238
|
2
|
|
|
|
|
9
|
$levels{$oname}{$cat} = $ospec->{level}; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
#print Dumper \%levels; exit; |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $find_olevel = sub { |
|
244
|
40
|
|
|
40
|
|
73
|
my ($oname, $cat) = @_; |
|
245
|
40
|
|
|
|
|
59
|
my $olevel = $levels{$oname}{''}; |
|
246
|
40
|
|
|
|
|
91
|
my @c = split /\./, $cat; |
|
247
|
40
|
|
|
|
|
85
|
for (my $i=0; $i<@c; $i++) { |
|
248
|
64
|
|
|
|
|
118
|
my $c = join(".", @c[0..$i]); |
|
249
|
64
|
100
|
|
|
|
133
|
if ($levels{$oname}{$c}) { |
|
250
|
42
|
|
|
|
|
89
|
$olevel = $levels{$oname}{$c}; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
} |
|
253
|
40
|
|
|
|
|
83
|
$olevel; |
|
254
|
1
|
|
|
|
|
18
|
}; |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# 2. determine level for each category (which is the minimum level of all |
|
257
|
|
|
|
|
|
|
# appenders for that category) |
|
258
|
1
|
|
|
|
|
3
|
my %cat_configs; # key = cat, value = [catlevel, apdname, ...] |
|
259
|
1
|
|
|
|
|
2
|
my $add_str = ''; |
|
260
|
1
|
|
|
|
|
2
|
my $apd_str = ''; |
|
261
|
1
|
|
|
|
|
8
|
for my $cat0 (sort {$a cmp $b} keys %cats) { |
|
|
13
|
|
|
|
|
21
|
|
|
262
|
7
|
100
|
|
|
|
25
|
$add_str .= "log4perl.additivity.$cat0 = 0\n" unless $cat0 eq ''; |
|
263
|
7
|
|
|
|
|
14
|
my @cats = ($cat0); |
|
264
|
|
|
|
|
|
|
# since we don't use additivity, we need to add supercategories ourselves |
|
265
|
7
|
|
|
|
|
32
|
while ($cat0 =~ s/\.[^.]+$//) { push @cats, $cat0 } |
|
|
6
|
|
|
|
|
19
|
|
|
266
|
7
|
|
|
|
|
13
|
for my $cat (@cats) { |
|
267
|
13
|
|
|
|
|
16
|
my $cat_level; |
|
268
|
13
|
|
|
|
|
25
|
for my $oname (keys %levels) { |
|
269
|
26
|
|
|
|
|
42
|
my $olevel = $find_olevel->($oname, $cat); |
|
270
|
26
|
50
|
|
|
|
395
|
next unless $olevel; |
|
271
|
26
|
|
|
|
|
43
|
$cat_level = _ifdef($cat_level, $olevel); |
|
272
|
26
|
|
|
|
|
39
|
$cat_level = _min_level($cat_level, $olevel); |
|
273
|
|
|
|
|
|
|
} |
|
274
|
13
|
|
|
|
|
54
|
$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
|
|
|
|
|
3
|
my %generated_appenders; # key = apdname, just a memory hash |
|
282
|
1
|
|
|
|
|
5
|
for my $cat (keys %cat_configs) { |
|
283
|
7
|
|
|
|
|
12
|
my $cat_level = $cat_configs{$cat}[0]; |
|
284
|
7
|
|
|
|
|
14
|
for my $oname (keys %levels) { |
|
285
|
14
|
|
|
|
|
18
|
my $ospec = $ospecs{$oname}; |
|
286
|
14
|
|
|
|
|
23
|
my $olevel = $find_olevel->($oname, $cat); |
|
287
|
|
|
|
|
|
|
#print "D:oname=$oname, cat=$cat, olevel=$olevel, cat_level=$cat_level\n"; |
|
288
|
14
|
|
|
|
|
21
|
my $apd_name; |
|
289
|
|
|
|
|
|
|
my $filter; |
|
290
|
14
|
100
|
66
|
|
|
33
|
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
|
|
|
|
|
12
|
$apd_name = $oname . "_" . uc($olevel); |
|
295
|
5
|
|
|
|
|
7
|
$filter = "Filter".uc($olevel); |
|
296
|
|
|
|
|
|
|
} else { |
|
297
|
9
|
|
|
|
|
12
|
$apd_name = $oname; |
|
298
|
9
|
|
|
|
|
14
|
$filter = "FilterCustom"; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
14
|
100
|
|
|
|
44
|
unless ($generated_appenders{$apd_name}++) { |
|
301
|
6
|
|
|
|
|
16
|
$apd_str .= _gen_appender_config($ospec, $apd_name, $filter). |
|
302
|
|
|
|
|
|
|
"\n"; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
14
|
|
|
|
|
23
|
push @{ $cat_configs{$cat} }, $apd_name; |
|
|
14
|
|
|
|
|
38
|
|
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
#print Dumper \%cat_configs; exit; |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# 4. write out log4perl category line |
|
310
|
1
|
|
|
|
|
4
|
my $cat_str = ''; |
|
311
|
1
|
|
|
|
|
49
|
for my $cat (sort {$a cmp $b} keys %cat_configs) { |
|
|
13
|
|
|
|
|
19
|
|
|
312
|
7
|
100
|
|
|
|
45
|
my $l = $cat eq '' ? '' : ".$cat"; |
|
313
|
7
|
|
|
|
|
13
|
$cat_str .= "log4perl.logger$l = ".join(", ", @{ $cat_configs{$cat} })."\n"; |
|
|
7
|
|
|
|
|
21
|
|
|
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
|
|
844
|
require Log::Log4perl; |
|
326
|
|
|
|
|
|
|
|
|
327
|
1
|
|
|
|
|
45918
|
my ($spec) = @_; |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# create intermediate directories for dir |
|
330
|
1
|
|
|
|
|
3
|
for (@{ $spec->{dir} }) { |
|
|
1
|
|
|
|
|
5
|
|
|
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
|
|
|
|
|
4
|
|
|
337
|
2
|
|
|
|
|
9
|
my $dir = _dirname($_->{path}); |
|
338
|
2
|
50
|
33
|
|
|
38
|
make_path($dir) if length($dir) && !(-d $dir); |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
1
|
|
|
|
|
6
|
my $config_str = _gen_l4p_config($spec); |
|
342
|
1
|
50
|
|
|
|
5
|
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: <<EOC\n", $config_str, "EOC\n"; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
1
|
|
|
|
|
7
|
Log::Log4perl->init(\$config_str); |
|
350
|
1
|
|
|
|
|
347507
|
Log::Any::Adapter->set('Log4perl'); |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub _basename { |
|
354
|
49
|
|
|
49
|
|
79
|
my $path = shift; |
|
355
|
49
|
|
|
|
|
544
|
my ($vol, $dir, $file) = File::Spec->splitpath($path); |
|
356
|
49
|
|
|
|
|
142
|
$file; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub _dirname { |
|
360
|
2
|
|
|
2
|
|
4
|
my $path = shift; |
|
361
|
2
|
|
|
|
|
30
|
my ($vol, $dir, $file) = File::Spec->splitpath($path); |
|
362
|
2
|
|
|
|
|
6
|
$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
|
|
4
|
my ($args, $caller) = @_; |
|
371
|
2
|
|
|
|
|
7
|
$args = _ifdef($args, []); # if we don't import(), we never get args |
|
372
|
|
|
|
|
|
|
|
|
373
|
2
|
|
|
|
|
4
|
my $i = 0; |
|
374
|
2
|
|
|
|
|
9
|
while ($i < @$args) { |
|
375
|
10
|
|
|
|
|
17
|
my $arg = $args->[$i]; |
|
376
|
10
|
100
|
|
|
|
35
|
do { $i+=2; next } if $arg =~ /^-(\w+)$/; |
|
|
9
|
|
|
|
|
12
|
|
|
|
9
|
|
|
|
|
30
|
|
|
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
|
|
|
|
|
4
|
$i++; |
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub _parse_opts { |
|
387
|
49
|
|
|
49
|
|
1162
|
require File::HomeDir; |
|
388
|
|
|
|
|
|
|
|
|
389
|
49
|
|
|
|
|
10651
|
my ($args, $caller) = @_; |
|
390
|
49
|
|
|
|
|
123
|
$args = _ifdef($args, []); # if we don't import(), we never get args |
|
391
|
49
|
|
|
|
|
259
|
_debug("parse_opts: args = [".join(", ", @$args)."]"); |
|
392
|
|
|
|
|
|
|
|
|
393
|
49
|
|
|
|
|
80
|
my $i = 0; |
|
394
|
49
|
|
|
|
|
69
|
my %opts; |
|
395
|
49
|
|
|
|
|
110
|
while ($i < @$args) { |
|
396
|
73
|
|
|
|
|
117
|
my $arg = $args->[$i]; |
|
397
|
73
|
100
|
|
|
|
382
|
do { $i++; next } unless $arg =~ /^-(\w+)$/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
398
|
72
|
|
|
|
|
177
|
my $opt = $1; |
|
399
|
72
|
50
|
|
|
|
156
|
die "Missing argument for option $opt" unless $i++ < @$args-1; |
|
400
|
72
|
|
|
|
|
114
|
$arg = $args->[$i]; |
|
401
|
72
|
|
|
|
|
137
|
$opts{$opt} = $arg; |
|
402
|
72
|
|
|
|
|
151
|
$i++; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
|
|
405
|
49
|
|
|
|
|
79
|
my $spec = {}; |
|
406
|
|
|
|
|
|
|
|
|
407
|
49
|
|
|
|
|
149
|
$spec->{log} = _ifdef($ENV{LOG}, 1); |
|
408
|
49
|
50
|
|
|
|
127
|
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
|
|
|
|
107
|
goto END_PARSE_OPTS unless $spec->{log}; |
|
414
|
|
|
|
|
|
|
|
|
415
|
49
|
|
|
|
|
96
|
$spec->{name} = _basename($0); |
|
416
|
49
|
100
|
|
|
|
114
|
if (defined $opts{name}) { |
|
417
|
6
|
|
|
|
|
12
|
$spec->{name} = $opts{name}; |
|
418
|
6
|
|
|
|
|
12
|
delete $opts{name}; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
49
|
|
|
|
|
160
|
$spec->{level_flag_paths} = [File::HomeDir->my_home, "/etc"]; |
|
422
|
49
|
100
|
|
|
|
1786
|
if (defined $opts{level_flag_paths}) { |
|
423
|
4
|
|
|
|
|
9
|
$spec->{level_flag_paths} = $opts{level_flag_paths}; |
|
424
|
4
|
|
|
|
|
9
|
delete $opts{level_flag_paths}; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
49
|
|
|
|
|
129
|
$spec->{level} = _set_level("", "", $spec); |
|
428
|
49
|
50
|
66
|
|
|
230
|
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
|
|
|
|
|
59
|
$spec->{level} = "warn"; |
|
433
|
31
|
|
|
|
|
74
|
_debug("Set general level to $spec->{level} (default)"); |
|
434
|
|
|
|
|
|
|
} |
|
435
|
49
|
|
|
|
|
79
|
delete $opts{level}; |
|
436
|
|
|
|
|
|
|
|
|
437
|
49
|
|
|
|
|
150
|
$spec->{category_alias} = _ifdefj($ENV{LOG_CATEGORY_ALIAS}, {}); |
|
438
|
49
|
100
|
|
|
|
124
|
if (defined $opts{category_alias}) { |
|
439
|
|
|
|
|
|
|
die "category_alias must be a hashref" |
|
440
|
1
|
50
|
|
|
|
5
|
unless ref($opts{category_alias}) eq 'HASH'; |
|
441
|
1
|
|
|
|
|
3
|
$spec->{category_alias} = $opts{category_alias}; |
|
442
|
1
|
|
|
|
|
3
|
delete $opts{category_alias}; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
49
|
100
|
|
|
|
98
|
if (defined $opts{category_level}) { |
|
446
|
|
|
|
|
|
|
die "category_level must be a hashref" |
|
447
|
1
|
50
|
|
|
|
4
|
unless ref($opts{category_level}) eq 'HASH'; |
|
448
|
1
|
|
|
|
|
24
|
$spec->{category_level} = {}; |
|
449
|
1
|
|
|
|
|
17
|
for (keys %{ $opts{category_level} }) { |
|
|
1
|
|
|
|
|
7
|
|
|
450
|
|
|
|
|
|
|
$spec->{category_level}{$_} = |
|
451
|
1
|
|
|
|
|
7
|
_check_level($opts{category_level}{$_}, "-category_level{$_}"); |
|
452
|
|
|
|
|
|
|
} |
|
453
|
1
|
|
|
|
|
3
|
delete $opts{category_level}; |
|
454
|
|
|
|
|
|
|
} |
|
455
|
|
|
|
|
|
|
|
|
456
|
49
|
|
|
|
|
73
|
$spec->{init} = 1; |
|
457
|
49
|
100
|
|
|
|
122
|
if (defined $opts{init}) { |
|
458
|
48
|
|
|
|
|
96
|
$spec->{init} = $opts{init}; |
|
459
|
48
|
|
|
|
|
84
|
delete $opts{init}; |
|
460
|
|
|
|
|
|
|
} |
|
461
|
|
|
|
|
|
|
|
|
462
|
49
|
|
|
|
|
77
|
$spec->{daemon} = 0; |
|
463
|
49
|
100
|
|
|
|
99
|
if (defined $opts{daemon}) { |
|
464
|
2
|
|
|
|
|
4
|
$spec->{daemon} = $opts{daemon}; |
|
465
|
2
|
|
|
|
|
7
|
_debug("setting is_daemon=$opts{daemon} (from daemon option)"); |
|
466
|
2
|
|
|
|
|
4
|
$is_daemon = $opts{daemon}; |
|
467
|
2
|
|
|
|
|
5
|
delete $opts{daemon}; |
|
468
|
|
|
|
|
|
|
} |
|
469
|
|
|
|
|
|
|
|
|
470
|
49
|
|
|
|
|
138
|
$spec->{dump} = $ENV{LOGANYAPP_DEBUG}; |
|
471
|
49
|
50
|
|
|
|
98
|
if (defined $opts{dump}) { |
|
472
|
0
|
|
|
|
|
0
|
$spec->{dump} = 1; |
|
473
|
0
|
|
|
|
|
0
|
delete $opts{dump}; |
|
474
|
|
|
|
|
|
|
} |
|
475
|
|
|
|
|
|
|
|
|
476
|
49
|
|
|
|
|
81
|
$spec->{filter_text} = $ENV{LOG_FILTER_TEXT}; |
|
477
|
49
|
50
|
|
|
|
90
|
if (defined $opts{filter_text}) { |
|
478
|
0
|
|
|
|
|
0
|
$spec->{filter_text} = $opts{filter_text}; |
|
479
|
0
|
|
|
|
|
0
|
delete $opts{filter_text}; |
|
480
|
|
|
|
|
|
|
} |
|
481
|
49
|
|
|
|
|
85
|
$spec->{filter_no_text} = $ENV{LOG_FILTER_NO_TEXT}; |
|
482
|
49
|
50
|
|
|
|
88
|
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
|
|
|
|
|
79
|
$spec->{filter_citext} = $ENV{LOG_FILTER_CITEXT}; |
|
487
|
49
|
50
|
|
|
|
93
|
if (defined $opts{filter_citext}) { |
|
488
|
0
|
|
|
|
|
0
|
$spec->{filter_citext} = $opts{filter_citext}; |
|
489
|
0
|
|
|
|
|
0
|
delete $opts{filter_citext}; |
|
490
|
|
|
|
|
|
|
} |
|
491
|
49
|
|
|
|
|
103
|
$spec->{filter_no_citext} = $ENV{LOG_FILTER_NO_CITEXT}; |
|
492
|
49
|
50
|
|
|
|
97
|
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
|
|
|
|
|
84
|
$spec->{filter_re} = $ENV{LOG_FILTER_RE}; |
|
497
|
49
|
50
|
|
|
|
85
|
if (defined $opts{filter_re}) { |
|
498
|
0
|
|
|
|
|
0
|
$spec->{filter_re} = $opts{filter_re}; |
|
499
|
0
|
|
|
|
|
0
|
delete $opts{filter_re}; |
|
500
|
|
|
|
|
|
|
} |
|
501
|
49
|
|
|
|
|
84
|
$spec->{filter_no_re} = $ENV{LOG_FILTER_NO_RE}; |
|
502
|
49
|
50
|
|
|
|
85
|
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
|
|
|
|
|
102
|
$spec->{file} = []; |
|
508
|
49
|
100
|
|
|
|
196
|
_parse_opt_file($spec, _ifdef($opts{file}, ($0 ne '-e' ? 1:0))); |
|
509
|
49
|
|
|
|
|
293
|
delete $opts{file}; |
|
510
|
|
|
|
|
|
|
|
|
511
|
49
|
|
|
|
|
164
|
$spec->{dir} = []; |
|
512
|
49
|
|
|
|
|
128
|
_parse_opt_dir($spec, _ifdef($opts{dir}, 0)); |
|
513
|
49
|
|
|
|
|
92
|
delete $opts{dir}; |
|
514
|
|
|
|
|
|
|
|
|
515
|
49
|
|
|
|
|
99
|
$spec->{screen} = []; |
|
516
|
49
|
|
|
|
|
115
|
_parse_opt_screen($spec, _ifdef($opts{screen}, !_is_daemon())); |
|
517
|
49
|
|
|
|
|
98
|
delete $opts{screen}; |
|
518
|
|
|
|
|
|
|
|
|
519
|
49
|
|
|
|
|
97
|
$spec->{syslog} = []; |
|
520
|
49
|
|
|
|
|
170
|
_parse_opt_syslog($spec, _ifdef($opts{syslog}, _is_daemon())); |
|
521
|
49
|
|
|
|
|
90
|
delete $opts{syslog}; |
|
522
|
|
|
|
|
|
|
|
|
523
|
49
|
|
|
|
|
93
|
$spec->{unixsock} = []; |
|
524
|
49
|
|
|
|
|
113
|
_parse_opt_unixsock($spec, _ifdef($opts{unixsock}, 0)); |
|
525
|
49
|
|
|
|
|
255
|
delete $opts{unixsock}; |
|
526
|
|
|
|
|
|
|
|
|
527
|
49
|
|
|
|
|
94
|
$spec->{array} = []; |
|
528
|
49
|
|
|
|
|
125
|
_parse_opt_array($spec, _ifdef($opts{array}, 0)); |
|
529
|
49
|
|
|
|
|
88
|
delete $opts{array}; |
|
530
|
|
|
|
|
|
|
|
|
531
|
49
|
50
|
|
|
|
128
|
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
|
|
|
|
|
124
|
$spec; |
|
541
|
|
|
|
|
|
|
} |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
sub _is_daemon { |
|
544
|
98
|
100
|
|
98
|
|
192
|
if (defined $is_daemon) { return $is_daemon } |
|
|
51
|
|
|
|
|
102
|
|
|
545
|
47
|
100
|
|
|
|
81
|
if (defined $main::IS_DAEMON) { |
|
546
|
1
|
|
|
|
|
2
|
$is_daemon = $main::IS_DAEMON; |
|
547
|
1
|
|
|
|
|
6
|
_debug("Setting is_daemon=$main::IS_DAEMON (from \$main::IS_DAEMON)"); |
|
548
|
1
|
|
|
|
|
3
|
return $main::IS_DAEMON; |
|
549
|
|
|
|
|
|
|
} |
|
550
|
|
|
|
|
|
|
|
|
551
|
46
|
|
|
|
|
85
|
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
|
|
|
|
1174
|
if ($INC{$_}) { |
|
568
|
2
|
|
|
|
|
8
|
_debug("setting is_daemon=1 (from existence of module $_)"); |
|
569
|
2
|
|
|
|
|
4
|
$is_daemon = 1; |
|
570
|
2
|
|
|
|
|
5
|
return 1; |
|
571
|
|
|
|
|
|
|
} |
|
572
|
|
|
|
|
|
|
} |
|
573
|
44
|
|
|
|
|
98
|
_debug("setting is_daemon=0 (no indication that we are a daemon)"); |
|
574
|
44
|
|
|
|
|
65
|
$is_daemon = 0; |
|
575
|
44
|
|
|
|
|
86
|
0; |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
sub _parse_opt_OUTPUT { |
|
579
|
296
|
|
|
296
|
|
887
|
my (%args) = @_; |
|
580
|
296
|
|
|
|
|
498
|
my $kind = $args{kind}; |
|
581
|
296
|
|
|
|
|
404
|
my $default_sub = $args{default_sub}; |
|
582
|
296
|
|
|
|
|
390
|
my $postprocess = $args{postprocess}; |
|
583
|
296
|
|
|
|
|
370
|
my $spec = $args{spec}; |
|
584
|
296
|
|
|
|
|
388
|
my $arg = $args{arg}; |
|
585
|
|
|
|
|
|
|
|
|
586
|
296
|
100
|
|
|
|
674
|
return unless $arg; |
|
587
|
|
|
|
|
|
|
|
|
588
|
96
|
100
|
100
|
|
|
266
|
if (!ref($arg) || ref($arg) eq 'HASH') { |
|
|
|
50
|
|
|
|
|
|
|
589
|
95
|
|
|
|
|
150
|
my $name = uc($kind).(@{ $spec->{$kind} }+0); |
|
|
95
|
|
|
|
|
246
|
|
|
590
|
95
|
|
|
|
|
180
|
local $dbg_ctx = $name; |
|
591
|
95
|
|
|
|
|
116
|
push @{ $spec->{$kind} }, $default_sub->($spec); |
|
|
95
|
|
|
|
|
195
|
|
|
592
|
95
|
|
|
|
|
419
|
$spec->{$kind}[-1]{name} = $name; |
|
593
|
95
|
100
|
|
|
|
211
|
if (!ref($arg)) { |
|
594
|
|
|
|
|
|
|
# leave every output parameter as is |
|
595
|
|
|
|
|
|
|
} else { |
|
596
|
6
|
|
|
|
|
23
|
for my $k (keys %$arg) { |
|
597
|
12
|
|
|
|
|
21
|
for ($spec->{$kind}[-1]) { |
|
598
|
12
|
50
|
|
|
|
27
|
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
|
|
|
|
35
|
_check_level($arg->{$k}, "-$kind") : $arg->{$k}; |
|
602
|
12
|
100
|
|
|
|
33
|
_debug("Set level of $kind to $_->{$k} (spec)") |
|
603
|
|
|
|
|
|
|
if $k eq 'level'; |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
} |
|
607
|
95
|
|
|
|
|
181
|
$spec->{$kind}[-1]{main_spec} = $spec; |
|
608
|
95
|
|
|
|
|
220
|
_set_pattern($spec->{$kind}[-1], $kind); |
|
609
|
95
|
100
|
|
|
|
341
|
$postprocess->(spec => $spec, ospec => $spec->{$kind}[-1]) |
|
610
|
|
|
|
|
|
|
if $postprocess; |
|
611
|
|
|
|
|
|
|
} elsif (ref($arg) eq 'ARRAY') { |
|
612
|
1
|
|
|
|
|
4
|
for (@$arg) { |
|
613
|
2
|
|
|
|
|
19
|
_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
|
|
239
|
my ($x) = @_; |
|
623
|
|
|
|
|
|
|
($ENV{LOG_SHOW_LOCATION} ? 'loc_': |
|
624
|
95
|
50
|
|
|
|
473
|
$ENV{LOG_SHOW_CATEGORY} ? 'cat_':'') . $x; |
|
|
|
50
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
sub _default_file { |
|
628
|
48
|
|
|
48
|
|
190
|
require File::HomeDir; |
|
629
|
|
|
|
|
|
|
|
|
630
|
48
|
|
|
|
|
89
|
my ($spec) = @_; |
|
631
|
48
|
|
|
|
|
91
|
my $level = _set_level("file", "file", $spec); |
|
632
|
48
|
100
|
|
|
|
114
|
if (!$level) { |
|
633
|
39
|
|
|
|
|
73
|
$level = $spec->{level}; |
|
634
|
39
|
|
|
|
|
88
|
_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
|
|
|
|
197
|
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
|
|
97
|
my ($spec, $arg) = @_; |
|
662
|
|
|
|
|
|
|
|
|
663
|
49
|
100
|
100
|
|
|
373
|
if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) { |
|
|
|
|
100
|
|
|
|
|
|
664
|
2
|
|
|
|
|
7
|
$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
|
|
138
|
my (%args) = @_; |
|
672
|
48
|
|
|
|
|
80
|
my $spec = $args{spec}; |
|
673
|
48
|
|
|
|
|
77
|
my $ospec = $args{ospec}; |
|
674
|
48
|
100
|
|
|
|
270
|
if ($ospec->{path} =~ m!/$!) { |
|
675
|
2
|
|
|
|
|
3
|
my $p = $ospec->{path}; |
|
676
|
2
|
|
|
|
|
6
|
$p .= "$spec->{name}.log"; |
|
677
|
2
|
|
|
|
|
8
|
_debug("File path ends with /, assumed to be dir, ". |
|
678
|
|
|
|
|
|
|
"final path becomes $p"); |
|
679
|
2
|
|
|
|
|
9
|
$ospec->{path} = $p; |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
}, |
|
682
|
49
|
|
|
|
|
299
|
); |
|
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
|
|
115
|
my ($spec, $arg) = @_; |
|
720
|
|
|
|
|
|
|
|
|
721
|
49
|
50
|
33
|
|
|
204
|
if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) { |
|
|
|
|
33
|
|
|
|
|
|
722
|
0
|
|
|
|
|
0
|
$arg = {path => $arg}; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
_parse_opt_OUTPUT( |
|
726
|
49
|
|
|
|
|
125
|
kind => 'dir', default_sub => \&_default_dir, |
|
727
|
|
|
|
|
|
|
spec => $spec, arg => $arg, |
|
728
|
|
|
|
|
|
|
); |
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
sub _default_screen { |
|
732
|
43
|
|
|
43
|
|
79
|
my ($spec) = @_; |
|
733
|
43
|
|
|
|
|
88
|
my $level = _set_level("screen", "screen", $spec); |
|
734
|
43
|
100
|
|
|
|
94
|
if (!$level) { |
|
735
|
34
|
|
|
|
|
68
|
$level = $spec->{level}; |
|
736
|
34
|
|
|
|
|
78
|
_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
|
|
|
|
360
|
filter_no_re => _ifdef($ENV{SCREEN_FILTER_NO_RE}, $spec->{filter_no_re}), |
|
756
|
|
|
|
|
|
|
}; |
|
757
|
|
|
|
|
|
|
} |
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
sub _parse_opt_screen { |
|
760
|
49
|
|
|
49
|
|
95
|
my ($spec, $arg) = @_; |
|
761
|
49
|
|
|
|
|
101
|
_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
|
|
7
|
my ($spec) = @_; |
|
769
|
4
|
|
|
|
|
10
|
my $level = _set_level("syslog", "syslog", $spec); |
|
770
|
4
|
50
|
|
|
|
10
|
if (!$level) { |
|
771
|
4
|
|
|
|
|
9
|
$level = $spec->{level}; |
|
772
|
4
|
|
|
|
|
11
|
_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
|
|
|
|
|
19
|
filter_no_re => _ifdef($ENV{SYSLOG_FILTER_NO_RE}, $spec->{filter_no_re}), |
|
791
|
|
|
|
|
|
|
}; |
|
792
|
|
|
|
|
|
|
} |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
sub _parse_opt_syslog { |
|
795
|
49
|
|
|
49
|
|
93
|
my ($spec, $arg) = @_; |
|
796
|
49
|
|
|
|
|
106
|
_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
|
|
114
|
my ($spec, $arg) = @_; |
|
833
|
|
|
|
|
|
|
|
|
834
|
49
|
50
|
33
|
|
|
201
|
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
|
|
|
|
|
251
|
); |
|
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
|
|
79
|
my ($spec, $arg) = @_; |
|
899
|
|
|
|
|
|
|
|
|
900
|
49
|
|
|
|
|
122
|
_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
|
|
191
|
my ($s, $name) = @_; |
|
908
|
95
|
|
|
|
|
261
|
_debug("Setting $name pattern ..."); |
|
909
|
95
|
50
|
|
|
|
232
|
unless (defined($s->{pattern})) { |
|
910
|
|
|
|
|
|
|
die "BUG: neither pattern nor pattern_style is defined ($name)" |
|
911
|
95
|
50
|
|
|
|
186
|
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
|
|
|
|
233
|
unless defined($PATTERN_STYLES{ $s->{pattern_style} }); |
|
915
|
95
|
|
|
|
|
167
|
$s->{pattern} = $PATTERN_STYLES{ $s->{pattern_style} }; |
|
916
|
95
|
|
|
|
|
300
|
_debug("Set $name pattern to `$s->{pattern}` ". |
|
917
|
|
|
|
|
|
|
"(from style `$s->{pattern_style}`)"); |
|
918
|
|
|
|
|
|
|
} |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
sub _extract_category { |
|
922
|
8
|
|
|
8
|
|
13
|
my ($ospec, $c) = @_; |
|
923
|
8
|
|
|
|
|
16
|
my $c0 = _ifdef($c, $ospec->{category}); |
|
924
|
8
|
|
|
|
|
12
|
my @res; |
|
925
|
8
|
50
|
|
|
|
17
|
if (ref($c0) eq 'ARRAY') { @res = @$c0 } else { @res = ($c0) } |
|
|
0
|
|
|
|
|
0
|
|
|
|
8
|
|
|
|
|
15
|
|
|
926
|
|
|
|
|
|
|
# replace alias with real value |
|
927
|
8
|
|
|
|
|
17
|
for (my $i=0; $i<@res; $i++) { |
|
928
|
8
|
|
|
|
|
14
|
my $c1 = $res[$i]; |
|
929
|
8
|
|
|
|
|
12
|
my $a = $ospec->{main_spec}{category_alias}{$c1}; |
|
930
|
8
|
100
|
|
|
|
22
|
next unless defined($a); |
|
931
|
2
|
50
|
|
|
|
6
|
if (ref($a) eq 'ARRAY') { |
|
932
|
2
|
|
|
|
|
7
|
splice @res, $i, 1, @$a; |
|
933
|
2
|
|
|
|
|
6
|
$i += (@$a-1); |
|
934
|
|
|
|
|
|
|
} else { |
|
935
|
0
|
|
|
|
|
0
|
$res[$i] = $a; |
|
936
|
|
|
|
|
|
|
} |
|
937
|
|
|
|
|
|
|
} |
|
938
|
8
|
|
|
|
|
14
|
for (@res) { |
|
939
|
10
|
|
|
|
|
27
|
s/::/./g; |
|
940
|
|
|
|
|
|
|
# $_ = lc; # XXX do we need this? |
|
941
|
|
|
|
|
|
|
} |
|
942
|
8
|
|
|
|
|
22
|
@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
|
|
60
|
my ($level, $from) = @_; |
|
953
|
25
|
50
|
|
|
|
149
|
$level =~ /^(off|fatal|error|warn|info|debug|trace)$/i |
|
954
|
|
|
|
|
|
|
or die "Unknown level (from $from): $level"; |
|
955
|
25
|
|
|
|
|
87
|
lc($1); |
|
956
|
|
|
|
|
|
|
} |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
sub _set_level { |
|
959
|
144
|
|
|
144
|
|
269
|
my ($prefix, $which, $spec) = @_; |
|
960
|
|
|
|
|
|
|
#use Data::Dump; dd $spec; |
|
961
|
144
|
100
|
|
|
|
302
|
my $p_ = $prefix ? "${prefix}_" : ""; |
|
962
|
144
|
100
|
|
|
|
279
|
my $P_ = $prefix ? uc("${prefix}_") : ""; |
|
963
|
144
|
100
|
|
|
|
284
|
my $F_ = $prefix ? ucfirst("${prefix}_") : ""; |
|
964
|
144
|
100
|
|
|
|
258
|
my $pd = $prefix ? "${prefix}-" : ""; |
|
965
|
144
|
100
|
|
|
|
2261
|
my $pr = $prefix ? qr/$prefix(_|-)/ : qr//; |
|
966
|
144
|
|
|
|
|
311
|
my ($level, $from); |
|
967
|
|
|
|
|
|
|
|
|
968
|
144
|
|
|
|
|
496
|
my @label2level =([trace=>"trace"], [debug=>"debug"], |
|
969
|
|
|
|
|
|
|
[verbose=>"info"], [quiet=>"error"]); |
|
970
|
|
|
|
|
|
|
|
|
971
|
144
|
100
|
|
|
|
468
|
_debug("Setting ", ($which ? "level of $which" : "general level"), " ..."); |
|
972
|
|
|
|
|
|
|
SET: |
|
973
|
|
|
|
|
|
|
{ |
|
974
|
144
|
50
|
|
|
|
217
|
if ($INC{"App/Options.pm"}) { |
|
|
144
|
|
|
|
|
338
|
|
|
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
|
|
|
|
|
224
|
my $i = 0; |
|
997
|
144
|
|
|
|
|
300
|
_debug("Checking \@ARGV ..."); |
|
998
|
144
|
|
|
|
|
305
|
while ($i < @ARGV) { |
|
999
|
36
|
|
|
|
|
61
|
my $arg = $ARGV[$i]; |
|
1000
|
36
|
|
|
|
|
59
|
$from = "cmdline arg $arg"; |
|
1001
|
36
|
50
|
|
|
|
585
|
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
|
|
|
468
|
if ($arg =~ /^--${pr}log[_-]?level$/ and $i < @ARGV-1) { |
|
1007
|
6
|
|
|
|
|
20
|
_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
|
|
|
|
|
17
|
last SET; |
|
1010
|
|
|
|
|
|
|
} |
|
1011
|
30
|
|
|
|
|
70
|
for (@label2level) { |
|
1012
|
120
|
100
|
|
|
|
2581
|
if ($arg =~ /^--${pr}$_->[0](=(1|yes|true))?$/i) { |
|
1013
|
2
|
|
|
|
|
12
|
_debug("\$ARGV[$i] looks like an option to specify level: $arg"); |
|
1014
|
2
|
|
|
|
|
4
|
$level = $_->[1]; |
|
1015
|
2
|
|
|
|
|
6
|
last SET; |
|
1016
|
|
|
|
|
|
|
} |
|
1017
|
|
|
|
|
|
|
} |
|
1018
|
28
|
|
|
|
|
91
|
$i++; |
|
1019
|
|
|
|
|
|
|
} |
|
1020
|
|
|
|
|
|
|
|
|
1021
|
136
|
|
|
|
|
243
|
for (qw/LOG_LEVEL LOGLEVEL/) { |
|
1022
|
270
|
|
|
|
|
480
|
my $key = $P_ . $_; |
|
1023
|
270
|
|
|
|
|
774
|
_debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)")); |
|
1024
|
270
|
100
|
|
|
|
693
|
if ($ENV{$key}) { |
|
1025
|
2
|
|
|
|
|
7
|
$level = _check_level($ENV{$key}, "ENV $key"); |
|
1026
|
2
|
|
|
|
|
7
|
$from = "\$ENV{$key}"; |
|
1027
|
2
|
|
|
|
|
5
|
last SET; |
|
1028
|
|
|
|
|
|
|
} |
|
1029
|
|
|
|
|
|
|
} |
|
1030
|
134
|
|
|
|
|
255
|
for (@label2level) { |
|
1031
|
533
|
|
|
|
|
968
|
my $key = $P_ . uc($_->[0]); |
|
1032
|
533
|
|
|
|
|
1215
|
_debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)")); |
|
1033
|
533
|
100
|
|
|
|
1220
|
if ($ENV{$key}) { |
|
1034
|
2
|
|
|
|
|
4
|
$level = $_->[1]; |
|
1035
|
2
|
|
|
|
|
4
|
$from = "\$ENV{$key}"; |
|
1036
|
2
|
|
|
|
|
5
|
last SET; |
|
1037
|
|
|
|
|
|
|
} |
|
1038
|
|
|
|
|
|
|
} |
|
1039
|
|
|
|
|
|
|
|
|
1040
|
132
|
|
|
|
|
170
|
for my $dir (@{$spec->{level_flag_paths}}) { |
|
|
132
|
|
|
|
|
278
|
|
|
1041
|
252
|
|
|
|
|
416
|
for (@label2level) { |
|
1042
|
999
|
|
|
|
|
2100
|
my $filename = "$dir/$spec->{name}." . $P_ . "log_level"; |
|
1043
|
999
|
|
|
|
|
7311
|
my $exists = -f $filename; |
|
1044
|
999
|
|
|
|
|
2049
|
my $content; |
|
1045
|
999
|
100
|
|
|
|
1714
|
if ($exists) { |
|
1046
|
2
|
|
|
|
|
64
|
open my($f), $filename; |
|
1047
|
2
|
|
|
|
|
41
|
$content = <$f>; |
|
1048
|
2
|
50
|
|
|
|
11
|
chomp($content) if defined($content); |
|
1049
|
2
|
|
|
|
|
21
|
close $f; |
|
1050
|
|
|
|
|
|
|
} |
|
1051
|
999
|
100
|
|
|
|
3354
|
_debug("Checking level flag file content $filename: ", |
|
1052
|
|
|
|
|
|
|
(defined($content) ? $content : "(undef)")); |
|
1053
|
999
|
100
|
|
|
|
1819
|
if (defined $content) { |
|
1054
|
2
|
|
|
|
|
10
|
$level = _check_level($content, |
|
1055
|
|
|
|
|
|
|
"level flag file $filename"); |
|
1056
|
2
|
|
|
|
|
5
|
$from = $filename; |
|
1057
|
2
|
|
|
|
|
6
|
last SET; |
|
1058
|
|
|
|
|
|
|
} |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
997
|
|
|
|
|
2323
|
$filename = "$dir/$spec->{name}." . $P_ . uc($_->[0]); |
|
1061
|
997
|
|
|
|
|
7534
|
$exists = -e $filename; |
|
1062
|
997
|
100
|
|
|
|
3927
|
_debug("Checking level flag file $filename: ", |
|
1063
|
|
|
|
|
|
|
($exists ? "EXISTS" : 0)); |
|
1064
|
997
|
100
|
|
|
|
2504
|
if ($exists) { |
|
1065
|
2
|
|
|
|
|
4
|
$level = $_->[1]; |
|
1066
|
2
|
|
|
|
|
4
|
$from = $filename; |
|
1067
|
2
|
|
|
|
|
7
|
last SET; |
|
1068
|
|
|
|
|
|
|
} |
|
1069
|
|
|
|
|
|
|
} |
|
1070
|
|
|
|
|
|
|
} |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
2
|
|
|
2
|
|
20
|
no strict 'refs'; |
|
|
2
|
|
|
|
|
13
|
|
|
|
2
|
|
|
|
|
934
|
|
|
1073
|
128
|
|
|
|
|
452
|
for ("${F_}Log_Level", "${P_}LOG_LEVEL", "${p_}log_level", |
|
1074
|
|
|
|
|
|
|
"${F_}LogLevel", "${P_}LOGLEVEL", "${p_}loglevel") { |
|
1075
|
738
|
|
|
|
|
1258
|
my $varname = "main::$_"; |
|
1076
|
738
|
|
|
|
|
1785
|
_debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)")); |
|
1077
|
738
|
100
|
|
|
|
1914
|
if ($$varname) { |
|
1078
|
12
|
|
|
|
|
24
|
$from = "\$$varname"; |
|
1079
|
12
|
|
|
|
|
39
|
$level = _check_level($$varname, "\$$varname"); |
|
1080
|
12
|
|
|
|
|
34
|
last SET; |
|
1081
|
|
|
|
|
|
|
} |
|
1082
|
|
|
|
|
|
|
} |
|
1083
|
116
|
|
|
|
|
198
|
for (@label2level) { |
|
1084
|
452
|
|
|
|
|
1258
|
for my $varname ( |
|
1085
|
|
|
|
|
|
|
"main::$F_" . ucfirst($_->[0]), |
|
1086
|
|
|
|
|
|
|
"main::$P_" . uc($_->[0])) { |
|
1087
|
900
|
|
|
|
|
1990
|
_debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)")); |
|
1088
|
900
|
100
|
|
|
|
2335
|
if ($$varname) { |
|
1089
|
8
|
|
|
|
|
11
|
$from = "\$$varname"; |
|
1090
|
8
|
|
|
|
|
16
|
$level = $_->[1]; |
|
1091
|
8
|
|
|
|
|
16
|
last SET; |
|
1092
|
|
|
|
|
|
|
} |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
} |
|
1095
|
|
|
|
|
|
|
} |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
144
|
100
|
|
|
|
389
|
_debug("Set ", ($which ? "level of $which" : "general level"), " to $level (from $from)") if $level; |
|
|
|
100
|
|
|
|
|
|
|
1098
|
144
|
|
|
|
|
632
|
return $level; |
|
1099
|
|
|
|
|
|
|
} |
|
1100
|
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
# return the lower level (e.g. _min_level("debug", "INFO") -> INFO |
|
1102
|
|
|
|
|
|
|
sub _min_level { |
|
1103
|
40
|
|
|
40
|
|
74
|
my ($l1, $l2) = @_; |
|
1104
|
40
|
|
|
|
|
107
|
my %vals = (OFF=>99, |
|
1105
|
|
|
|
|
|
|
FATAL=>6, ERROR=>5, WARN=>4, INFO=>3, DEBUG=>2, TRACE=>1); |
|
1106
|
40
|
100
|
|
|
|
149
|
$vals{uc($l1)} > $vals{uc($l2)} ? $l2 : $l1; |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
sub _export_logger { |
|
1110
|
1
|
|
|
1
|
|
3
|
my ($caller) = @_; |
|
1111
|
1
|
|
|
|
|
3
|
my $log_for_caller = Log::Any->get_logger(category => $caller); |
|
1112
|
1
|
|
|
|
|
2053
|
my $varname = "$caller\::log"; |
|
1113
|
2
|
|
|
2
|
|
16
|
no strict 'refs'; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
308
|
|
|
1114
|
1
|
|
|
|
|
4
|
*$varname = \$log_for_caller; |
|
1115
|
|
|
|
|
|
|
} |
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
sub _debug { |
|
1118
|
5169
|
50
|
|
5169
|
|
9628
|
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
|
|
31
|
my ($self, @args) = @_; |
|
1125
|
2
|
|
|
|
|
4
|
my $caller = caller(); |
|
1126
|
2
|
|
|
|
|
7
|
_parse_args(\@args, $caller); |
|
1127
|
2
|
|
|
|
|
73
|
$init_args = \@args; |
|
1128
|
|
|
|
|
|
|
} |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
{ |
|
1131
|
2
|
|
|
2
|
|
14
|
no warnings; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
208
|
|
|
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
|
|
11
|
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__ |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
=pod |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
=encoding UTF-8 |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
=head1 NAME |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
Log::Any::App - An easy way to use Log::Any in applications |
|
1153
|
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
=head1 VERSION |
|
1155
|
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
This document describes version 0.540 of Log::Any::App (from Perl distribution Log-Any-App), released on 2019-01-09. |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
Most of the time you only need to do this: |
|
1161
|
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
# in your script.pl |
|
1163
|
|
|
|
|
|
|
use Log::Any::App '$log'; |
|
1164
|
|
|
|
|
|
|
$log->warn("blah ..."); |
|
1165
|
|
|
|
|
|
|
if ($log->is_debug) { ... } |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
# or, in command line |
|
1168
|
|
|
|
|
|
|
% perl -MLog::Any::App -MModuleThatUsesLogAny -e'...' |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
Here's the default logging that Log::Any::App sets up for you: |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
Condition screen file syslog dir |
|
1173
|
|
|
|
|
|
|
--------------------------------+-------+------------------+-------------+--- |
|
1174
|
|
|
|
|
|
|
-e (one-liners) y - - - |
|
1175
|
|
|
|
|
|
|
Scripts running as normal user y ~/NAME.log - - |
|
1176
|
|
|
|
|
|
|
Scripts running as root y /var/log/NAME.log - - |
|
1177
|
|
|
|
|
|
|
Daemons - y y - |
|
1178
|
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
You can customize level from outside the script, using environment variables or |
|
1180
|
|
|
|
|
|
|
command-line options (won't interfere with command-line processing modules like |
|
1181
|
|
|
|
|
|
|
Getopt::Long etc): |
|
1182
|
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
% DEBUG=1 script.pl |
|
1184
|
|
|
|
|
|
|
% LOG_LEVEL=trace script.pl |
|
1185
|
|
|
|
|
|
|
% script.pl --verbose |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
And to customize other stuffs: |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1190
|
|
|
|
|
|
|
-syslog => 1, # turn on syslog logging explicitly |
|
1191
|
|
|
|
|
|
|
-screen => 0, # turn off screen logging explicitly |
|
1192
|
|
|
|
|
|
|
-file => {path=>'/foo/bar', max_size=>'10M', histories=>10}; |
|
1193
|
|
|
|
|
|
|
# customize file logging |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
For more customization like categories, per-category level, per-output level, |
|
1196
|
|
|
|
|
|
|
multiple outputs, string patterns, etc see L</USING AND EXAMPLES> and init(). |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
1199
|
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
IMPORTANT: Please read L</"ROAD TO 1.0"> on some incompatibilities in the near |
|
1201
|
|
|
|
|
|
|
future, before 1.0 is released. |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
Log::Any::App is a convenient combo for L<Log::Any> and L<Log::Log4perl> |
|
1204
|
|
|
|
|
|
|
(although alternative backends beside Log4perl might be considered in the |
|
1205
|
|
|
|
|
|
|
future). To use Log::Any::App you need to be sold on the idea of Log::Any first, |
|
1206
|
|
|
|
|
|
|
so please do a read up on that first. |
|
1207
|
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
The goal of Log::Any::App is to provide developers an easy and concise way to |
|
1209
|
|
|
|
|
|
|
add logging to their I<*applications*>. That is, instead of modules; modules |
|
1210
|
|
|
|
|
|
|
remain using Log::Any to produce logs. Applications can upgrade to full Log4perl |
|
1211
|
|
|
|
|
|
|
later when necessary, although in my experience, they usually don't. |
|
1212
|
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
With Log::Any::App, you can replace this code in your application: |
|
1214
|
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
use Log::Any '$log'; |
|
1216
|
|
|
|
|
|
|
use Log::Any::Adapter; |
|
1217
|
|
|
|
|
|
|
use Log::Log4perl; |
|
1218
|
|
|
|
|
|
|
my $log4perl_config = ' |
|
1219
|
|
|
|
|
|
|
some |
|
1220
|
|
|
|
|
|
|
long |
|
1221
|
|
|
|
|
|
|
multiline |
|
1222
|
|
|
|
|
|
|
config...'; |
|
1223
|
|
|
|
|
|
|
Log::Log4perl->init(\$log4perl_config); |
|
1224
|
|
|
|
|
|
|
Log::Any::Adapter->set('Log4perl'); |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
with just this: |
|
1227
|
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
use Log::Any::App '$log'; # plus some other options when necessary |
|
1229
|
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
Most of the time you don't need to configure anything as Log::Any::App will |
|
1231
|
|
|
|
|
|
|
construct the most appropriate default Log4perl configuration for your |
|
1232
|
|
|
|
|
|
|
application. |
|
1233
|
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
=head1 USING AND EXAMPLES |
|
1235
|
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
To use Log::Any::App, just do: |
|
1237
|
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
use Log::Any::App '$log'; |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
or from the command line: |
|
1241
|
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
% perl -MLog::Any::App -MModuleThatUsesLogAny -e ... |
|
1243
|
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
This will send logs to screen as well as file (unless -e scripts, which only log |
|
1245
|
|
|
|
|
|
|
to screen). Default log file is ~/$SCRIPT_NAME.log, or /var/log/$SCRIPT_NAME.log |
|
1246
|
|
|
|
|
|
|
if script is running as root. Default level is 'warn'. |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
The 'use Log::Any::App' statement can be issued before or after the modules that |
|
1249
|
|
|
|
|
|
|
use Log::Any, it doesn't matter. Logging will be initialized in the INIT phase |
|
1250
|
|
|
|
|
|
|
by Log::Any::App. |
|
1251
|
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
You are not required to import '$log', and don't need to if you do not produce |
|
1253
|
|
|
|
|
|
|
logs in your application (only in the modules). |
|
1254
|
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
=head2 Changing logging level |
|
1256
|
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
Since one of the most commonly tweaked logging setting is level (for example: |
|
1258
|
|
|
|
|
|
|
increasing level when debugging problems), Log::Any::App provides several |
|
1259
|
|
|
|
|
|
|
mechanisms to change log level, either from the script or from outside the |
|
1260
|
|
|
|
|
|
|
script, for your convenience. Below are the mechanisms, ordered from highest |
|
1261
|
|
|
|
|
|
|
priority: |
|
1262
|
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
=over 4 |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
=item * import argument (inside the script) |
|
1266
|
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
=item * command line arguments (outside the script) |
|
1268
|
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=item * environment variables (outside the script) |
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=item * level flag files (outside the script) |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
=item * variables in 'main' package (inside the script) |
|
1274
|
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
=back |
|
1276
|
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
These mechanisms are explained in more details in the documentation for the |
|
1278
|
|
|
|
|
|
|
B<init()> function. But below are some examples. |
|
1279
|
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
To change level from inside the script: |
|
1281
|
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
use Log::Any::App '$log', -level => 'debug'; |
|
1283
|
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
This is useful if you want a fixed level that cannot be overridden by other |
|
1285
|
|
|
|
|
|
|
mechanisms (since setting level using import argument has the highest priority). |
|
1286
|
|
|
|
|
|
|
But oftentimes what you want is changing level without modifying the script |
|
1287
|
|
|
|
|
|
|
itself. Thereby, just write: |
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
use Log::Any::App '$log'; |
|
1290
|
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
and then you can use environment variables to change level: |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
TRACE=1 script.pl; # setting level to trace |
|
1294
|
|
|
|
|
|
|
DEBUG=1 script.pl; # setting level to debug |
|
1295
|
|
|
|
|
|
|
VERBOSE=1 script.pl; # setting level to info |
|
1296
|
|
|
|
|
|
|
QUIET=1 script.pl; # setting level to error |
|
1297
|
|
|
|
|
|
|
LOG_LEVEL=trace script.pl; # setting a specific log level |
|
1298
|
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
or command-line options: |
|
1300
|
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
script.pl --trace |
|
1302
|
|
|
|
|
|
|
script.pl --debug |
|
1303
|
|
|
|
|
|
|
script.pl --verbose |
|
1304
|
|
|
|
|
|
|
script.pl --quiet |
|
1305
|
|
|
|
|
|
|
script.pl --log_level=debug; # '--log-level debug' will also do |
|
1306
|
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
Regarding command-line options: Log::Any::App won't consume the command-line |
|
1308
|
|
|
|
|
|
|
options from @ARGV and thus won't interfere with command-line processing modules |
|
1309
|
|
|
|
|
|
|
like L<Getopt::Long> or L<App::Options>. If you use a command-line processing |
|
1310
|
|
|
|
|
|
|
module and plan to use command-line options to set level, you might want to |
|
1311
|
|
|
|
|
|
|
define these level options, or your command-line processing module will complain |
|
1312
|
|
|
|
|
|
|
about unknown options. |
|
1313
|
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
=head2 Changing default level |
|
1315
|
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
The default log level is 'warn'. To change the default level, you can use 'main' |
|
1317
|
|
|
|
|
|
|
package variables (since they have the lowest priority): |
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
use Log::Any::App '$log'; |
|
1320
|
|
|
|
|
|
|
BEGIN { our $Log_Level = 'info' } # be more verbose by default |
|
1321
|
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
Then you will still be able to use level flag files or environment variables or |
|
1323
|
|
|
|
|
|
|
command-line options to override this setting. |
|
1324
|
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
=head2 Changing per-output level |
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
Logging level can also be specified on a per-output level. For example, if you |
|
1328
|
|
|
|
|
|
|
want your script to be chatty on the screen but still logs to file at the |
|
1329
|
|
|
|
|
|
|
default 'warn' level: |
|
1330
|
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
SCREEN_VERBOSE=1 script.pl |
|
1332
|
|
|
|
|
|
|
SCREEN_DEBUG=1 script.pl |
|
1333
|
|
|
|
|
|
|
SCREEN_TRACE=1 script.pl |
|
1334
|
|
|
|
|
|
|
SCREEN_LOG_LEVEL=info script.pl |
|
1335
|
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
script.pl --screen_verbose |
|
1337
|
|
|
|
|
|
|
script.pl --screen-debug |
|
1338
|
|
|
|
|
|
|
script.pl --screen-trace=1 |
|
1339
|
|
|
|
|
|
|
script.pl --screen-log-level=info |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
Similarly, to set only file level, use FILE_VERBOSE, FILE_LOG_LEVEL, |
|
1342
|
|
|
|
|
|
|
--file-trace, and so on. |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
=head2 Setting default per-output level |
|
1345
|
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
As with setting default level, you can also set default level on a per-output |
|
1347
|
|
|
|
|
|
|
basis: |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
use Log::Any::App '$log'; |
|
1350
|
|
|
|
|
|
|
BEGIN { |
|
1351
|
|
|
|
|
|
|
our $Screen_Log_Level = 'off'; |
|
1352
|
|
|
|
|
|
|
our $File_Quiet = 1; # setting file level to 'error' |
|
1353
|
|
|
|
|
|
|
# and so on |
|
1354
|
|
|
|
|
|
|
} |
|
1355
|
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
If a per-output level is not specified, it will default to the general log level. |
|
1357
|
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
=head2 Enabling/disabling output |
|
1359
|
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
To disable a certain output, you can do this: |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
use Log::Any::App '$log', -file => 0; |
|
1363
|
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
or: |
|
1365
|
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
use Log::Any::App '$log', -screen => {level=>'off'}; |
|
1367
|
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
and this won't allow the output to be re-enabled from outside the script. However |
|
1369
|
|
|
|
|
|
|
if you do this: |
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
use Log::Any::App; |
|
1372
|
|
|
|
|
|
|
BEGIN { our $Screen_Log_Level = 'off' } |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
then by default screen logging is turned off but you will be able to override |
|
1375
|
|
|
|
|
|
|
the screen log level using level flag files or environment variables or |
|
1376
|
|
|
|
|
|
|
command-line options (SCREEN_DEBUG, --screen-verbose, and so on). |
|
1377
|
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
=head2 Changing log level of cron scripts |
|
1379
|
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
Environment variables and command-line options allow changing log level without |
|
1381
|
|
|
|
|
|
|
modifying the script. But for scripts specified in crontab, they still require |
|
1382
|
|
|
|
|
|
|
changing crontab entries, e.g.: |
|
1383
|
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
# turn on debugging |
|
1385
|
|
|
|
|
|
|
*/5 * * * * DEBUG=1 foo |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
# be silent |
|
1388
|
|
|
|
|
|
|
*/5 * * * * bar --quiet |
|
1389
|
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
Another mechanism, level flag file, is useful in this case. By doing: |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
$ echo debug > ~/foo.log_level |
|
1393
|
|
|
|
|
|
|
# touch /etc/bar.QUIET |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
you can also change log levels without modifying your crontab. |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
=head2 Changing log file name/location |
|
1398
|
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
By default Log::Any::App will log to file to ~/$NAME.log (or /var/log/$NAME.log |
|
1400
|
|
|
|
|
|
|
if script is running as root), where $NAME is taken from the basename of $0. But |
|
1401
|
|
|
|
|
|
|
this can be changed using: |
|
1402
|
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
use Log::Any::App '$log', -name => 'myprog'; |
|
1404
|
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
Or, using custom path: |
|
1406
|
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
use Log::Any::App '$log', -file => '/path/to/file'; |
|
1408
|
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
=head2 Changing other output parameters |
|
1410
|
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
Each output argument can accept a hashref to specify various options. For |
|
1412
|
|
|
|
|
|
|
example: |
|
1413
|
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1415
|
|
|
|
|
|
|
-screen => {color=>0}, # never use color |
|
1416
|
|
|
|
|
|
|
-file => {path=>'/var/log/foo', |
|
1417
|
|
|
|
|
|
|
max_size=>'10M', |
|
1418
|
|
|
|
|
|
|
histories=>10, |
|
1419
|
|
|
|
|
|
|
}, |
|
1420
|
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
For all the available options of each output, see the init() function. |
|
1422
|
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
=head2 Logging to syslog |
|
1424
|
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
Logging to syslog is enabled by default if your script looks like or declare |
|
1426
|
|
|
|
|
|
|
that it is a daemon, e.g.: |
|
1427
|
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
use Net::Daemon; # this indicate your program is a daemon |
|
1429
|
|
|
|
|
|
|
use Log::Any::App; # syslog logging will be turned on by default |
|
1430
|
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
use Log::Any::App -daemon => 1; # script declares that it is a daemon |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# idem |
|
1434
|
|
|
|
|
|
|
package main; |
|
1435
|
|
|
|
|
|
|
our $IS_DAEMON = 1; |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
But if you are certain you don't want syslog logging: |
|
1438
|
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
use Log::Any::App -syslog => 0; |
|
1440
|
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
=head2 Logging to directory |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
This is done using L<Log::Dispatch::Dir> where each log message is logged to a |
|
1444
|
|
|
|
|
|
|
different file in a specified directory. By default logging to dir is not turned |
|
1445
|
|
|
|
|
|
|
on, to turn it on: |
|
1446
|
|
|
|
|
|
|
|
|
1447
|
|
|
|
|
|
|
use Log::Any::App '$log', -dir => 1; |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
For all the available options of directory output, see the init() function. |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
=head2 Multiple outputs |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
Each output argument can accept an arrayref to specify more than one output. For |
|
1454
|
|
|
|
|
|
|
example below is a code to log to three files: |
|
1455
|
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1457
|
|
|
|
|
|
|
-file => [1, # default, to ~/$NAME.log or /var/log/$NAME.log |
|
1458
|
|
|
|
|
|
|
"/var/log/log1", |
|
1459
|
|
|
|
|
|
|
{path=>"/var/log/debug_foo", category=>'Foo', level=>'debug'}]; |
|
1460
|
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
=head2 Changing level of certain module(s) |
|
1462
|
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
Suppose you want to shut up logs from modules Foo, Bar::Baz, and Qux (and their |
|
1464
|
|
|
|
|
|
|
submodules as well, e.g. Foo::Alpha, Bar::Baz::Beta::Gamma) because they are too |
|
1465
|
|
|
|
|
|
|
noisy: |
|
1466
|
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1468
|
|
|
|
|
|
|
-category_level => { Foo => 'off', 'Bar::Baz' => 'off', Qux => 'off' }; |
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
or (same thing): |
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1473
|
|
|
|
|
|
|
-category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, |
|
1474
|
|
|
|
|
|
|
-category_level => { -noisy => 'off' }; |
|
1475
|
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
You can even specify this on a per-output basis. Suppose you only want to shut |
|
1477
|
|
|
|
|
|
|
up the noisy modules on the screen, but not on the file: |
|
1478
|
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1480
|
|
|
|
|
|
|
-category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, |
|
1481
|
|
|
|
|
|
|
-screen => { category_level => { -noisy => 'off' } }; |
|
1482
|
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
Or perhaps, you want to shut up the noisy modules everywhere, except on the |
|
1484
|
|
|
|
|
|
|
screen: |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
use Log::Any::App '$log', |
|
1487
|
|
|
|
|
|
|
-category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, |
|
1488
|
|
|
|
|
|
|
-category_level => { -noisy => 'off' }, |
|
1489
|
|
|
|
|
|
|
-syslog => 1, # uses general -category_level |
|
1490
|
|
|
|
|
|
|
-file => "/var/log/foo", # uses general -category_level |
|
1491
|
|
|
|
|
|
|
-screen => { category_level => {} }; # overrides general -category_level |
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
You can also do this from the outside the script using environment variable, |
|
1494
|
|
|
|
|
|
|
which is more flexible. Encode data structure using JSON: |
|
1495
|
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
% LOG_SHOW_CATEGORY=1 \ |
|
1497
|
|
|
|
|
|
|
LOG_CATEGORY_ALIAS='{"-noisy":["Foo","Bar::Baz","Quz"]}' \ |
|
1498
|
|
|
|
|
|
|
LOG_CATEGORY_LEVEL='{"-noisy":"off"}' script.pl ... |
|
1499
|
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
=head2 Only displaying log from certain module(s) |
|
1501
|
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
Use a combination of LOG_LEVEL and LOG_CATEGORY_LEVEL. For example: |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
% LOG_LEVEL=off LOG_CATEGORY_LEVEL='{"Foo.Bar":"trace", "Baz":"info"}' \ |
|
1505
|
|
|
|
|
|
|
script.pl ... |
|
1506
|
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
=head2 Displaying category name |
|
1508
|
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
% LOG_SHOW_CATEGORY=1 script.pl ... |
|
1510
|
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
Now instead of: |
|
1512
|
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
[25] Starting baz ritual ... |
|
1514
|
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
now log messages will be prefixed with category: |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
[cat Foo.Bar][25] Starting baz ritual ... |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
=head2 Displaying location name |
|
1520
|
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
% LOG_SHOW_LOCATION=1 script.pl ... |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
Now log messages will be prefixed with location (function/file/line number) |
|
1524
|
|
|
|
|
|
|
information: |
|
1525
|
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
[loc Foo::Bar lib/Foo/Bar.pm (12)][25] Starting baz ritual ... |
|
1527
|
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
=head2 Preventing logging level to be changed from outside the script |
|
1529
|
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
Sometimes, for security/audit reasons, you don't want to allow script caller to |
|
1531
|
|
|
|
|
|
|
change logging level. As explained previously, you can use the 'level' import |
|
1532
|
|
|
|
|
|
|
argument (the highest priority of level-setting): |
|
1533
|
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
use Log::Any::App '$log', -level => 'debug'; # always use debug level |
|
1535
|
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
TODO: Allow something like 'debug+' to allow other mechanisms to *increase* the |
|
1537
|
|
|
|
|
|
|
level but not decrease it. Or 'debug-' to allow other mechanisms to decrease |
|
1538
|
|
|
|
|
|
|
level but not increase it. And finally 'debug,trace' to specify allowable levels |
|
1539
|
|
|
|
|
|
|
(is this necessary?) |
|
1540
|
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
=head2 Debugging |
|
1542
|
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
To see the Log4perl configuration that is generated by Log::Any::App and how it |
|
1544
|
|
|
|
|
|
|
came to be, set environment LOGANYAPP_DEBUG to true. |
|
1545
|
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
=head1 PATTERN STYLES |
|
1547
|
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
Log::Any::App provides some styles for Log4perl patterns. You can specify |
|
1549
|
|
|
|
|
|
|
C<pattern_style> instead of directly specifying C<pattern>. example: |
|
1550
|
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
use Log::Any::App -screen => {pattern_style=>"script_long"}; |
|
1552
|
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
Name Description Example output |
|
1554
|
|
|
|
|
|
|
---- ----------- -------------- |
|
1555
|
|
|
|
|
|
|
plain The message, the whole message, Message |
|
1556
|
|
|
|
|
|
|
and nothing but the message. |
|
1557
|
|
|
|
|
|
|
Used by dir logging. |
|
1558
|
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
Equivalent to pattern: '%m' |
|
1560
|
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
plain_nl Message plus newline. The default Message |
|
1562
|
|
|
|
|
|
|
for screen without |
|
1563
|
|
|
|
|
|
|
LOG_ELAPSED_TIME_IN_SCREEN. |
|
1564
|
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
Equivalent to pattern: '%m%n' |
|
1566
|
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
script_short For scripts that run for a short [234] Message |
|
1568
|
|
|
|
|
|
|
time (a few seconds). Shows just |
|
1569
|
|
|
|
|
|
|
the number of milliseconds. This |
|
1570
|
|
|
|
|
|
|
is the default for screen under |
|
1571
|
|
|
|
|
|
|
LOG_ELAPSED_TIME_IN_SCREEN. |
|
1572
|
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
Equivalent to pattern: |
|
1574
|
|
|
|
|
|
|
'[%r] %m%n' |
|
1575
|
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
script_long Scripts that will run for a [2010-04-22 18:01:02] Message |
|
1577
|
|
|
|
|
|
|
while (more than a few seconds). |
|
1578
|
|
|
|
|
|
|
Shows date/time. |
|
1579
|
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
Equivalent to pattern: |
|
1581
|
|
|
|
|
|
|
'[%d] %m%n' |
|
1582
|
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
daemon For typical daemons. Shows PID [pid 1234] [2010-04-22 18:01:02] Message |
|
1584
|
|
|
|
|
|
|
and date/time. This is the |
|
1585
|
|
|
|
|
|
|
default for file logging. |
|
1586
|
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
Equivalent to pattern: |
|
1588
|
|
|
|
|
|
|
'[pid %P] [%d] %m%n' |
|
1589
|
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
syslog Style suitable for syslog [pid 1234] Message |
|
1591
|
|
|
|
|
|
|
logging. |
|
1592
|
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
Equivalent to pattern: |
|
1594
|
|
|
|
|
|
|
'[pid %p] %m' |
|
1595
|
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
For each of the above there are also C<cat_XXX> (e.g. C<cat_script_long>) which |
|
1597
|
|
|
|
|
|
|
are the same as XXX but with C<[cat %c]> in front of the pattern. It is used |
|
1598
|
|
|
|
|
|
|
mainly to show categories and then filter by categories. You can turn picking |
|
1599
|
|
|
|
|
|
|
default pattern style with category using environment variable |
|
1600
|
|
|
|
|
|
|
LOG_SHOW_CATEGORY. |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
And for each of the above there are also C<loc_XXX> (e.g. C<loc_syslog>) which |
|
1603
|
|
|
|
|
|
|
are the same as XXX but with C<[loc %l]> in front of the pattern. It is used to |
|
1604
|
|
|
|
|
|
|
show calling location (file, function/method, and line number). You can turn |
|
1605
|
|
|
|
|
|
|
picking default pattern style with location prefix using environment variable |
|
1606
|
|
|
|
|
|
|
LOG_SHOW_LOCATION. |
|
1607
|
|
|
|
|
|
|
|
|
1608
|
|
|
|
|
|
|
If you have a favorite pattern style, please do share them. |
|
1609
|
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
=head1 BUGS/TODOS |
|
1611
|
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
Need to provide appropriate defaults for Windows/other OS. |
|
1613
|
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
=head1 ROAD TO 1.0 |
|
1615
|
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
Here are some planned changes/development before 1.0 is reached. There might be |
|
1617
|
|
|
|
|
|
|
some incompatibilities, please read this section carefully. |
|
1618
|
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
=over 4 |
|
1620
|
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
=item * Everything is configurable via environment/command-line/option file |
|
1622
|
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
As I I<love> specifying log options from environment, I will make I<every> |
|
1624
|
|
|
|
|
|
|
init() options configurable from outside the script |
|
1625
|
|
|
|
|
|
|
(environment/command-line/control file). Of course, init() arguments still take |
|
1626
|
|
|
|
|
|
|
precedence for authors that do not want some/all options to be overridden from |
|
1627
|
|
|
|
|
|
|
outside. |
|
1628
|
|
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
=item * Reorganization of command-line/environment names |
|
1630
|
|
|
|
|
|
|
|
|
1631
|
|
|
|
|
|
|
Aside from the handy and short TRACE (--trace), DEBUG, VERBOSE, QUIET, all the |
|
1632
|
|
|
|
|
|
|
other environment names will be put under LOG_ prefix. This means FILE_LOG_LEVEL |
|
1633
|
|
|
|
|
|
|
will be changed to LOG_FILE_LEVEL, and so on. SCREEN_VERBOSE will be changed to |
|
1634
|
|
|
|
|
|
|
VERBOSE_SCREEN. |
|
1635
|
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
This is meant to reduce "pollution" of the environment variables namespace. |
|
1637
|
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
Log option file (option file for short, previously "flag file") will be searched |
|
1639
|
|
|
|
|
|
|
in <PROG>.log_options. Its content is in JSON and will become init() arguments. |
|
1640
|
|
|
|
|
|
|
For example: |
|
1641
|
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
{"file": 1, "screen":{"level":"trace"}} |
|
1643
|
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
or more akin to init() (both will be supported): |
|
1645
|
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
["-file": 1, "-screen":{"level":"trace"}] |
|
1647
|
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
=item * Possible reorganization of package variable names |
|
1649
|
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
To be more strict and reduce confusion, case variation might not be searched. |
|
1651
|
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
=item * Pluggable backend |
|
1653
|
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
This is actually the main motivator to reach 1.0 and all these changes. Backends |
|
1655
|
|
|
|
|
|
|
will be put in Log::Any::App::Backend::Log4perl, and so on. |
|
1656
|
|
|
|
|
|
|
|
|
1657
|
|
|
|
|
|
|
=item * Pluggable output |
|
1658
|
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
Probably split to Log::Any::App::Output::file, and so on. Each output needs |
|
1660
|
|
|
|
|
|
|
its backend support. |
|
1661
|
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
=item * App::Options support will probably be dropped |
|
1663
|
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
I no longer use App::Options these days, and I don't know of any Log::Any::App |
|
1665
|
|
|
|
|
|
|
user who does. |
|
1666
|
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
=item * Probably some hooks to allow for more flexibility. |
|
1668
|
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
For example, if user wants to parse or detect levels/log file paths/etc from |
|
1670
|
|
|
|
|
|
|
some custom logic. |
|
1671
|
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
=back |
|
1673
|
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
1675
|
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
None is exported. |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
=head2 init(\@args) |
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
This is the actual function that implements the setup and configuration of |
|
1681
|
|
|
|
|
|
|
logging. You normally need not call this function explicitly (but see below), it |
|
1682
|
|
|
|
|
|
|
will be called once in an INIT block. In fact, when you do: |
|
1683
|
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
use Log::Any::App 'a', 'b', 'c'; |
|
1685
|
|
|
|
|
|
|
|
|
1686
|
|
|
|
|
|
|
it is actually passed as: |
|
1687
|
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
init(['a', 'b', 'c']); |
|
1689
|
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
You will need to call init() manually if you require Log::Any::App at runtime, |
|
1691
|
|
|
|
|
|
|
in which case it is too late to run INIT block. If you want to run Log::Any::App |
|
1692
|
|
|
|
|
|
|
in runtime phase, do this: |
|
1693
|
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
require Log::Any::App; |
|
1695
|
|
|
|
|
|
|
Log::Any::App::init(['a', 'b', 'c']); |
|
1696
|
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
Arguments to init can be one or more of: |
|
1698
|
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
=over 4 |
|
1700
|
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
=item -log => BOOL |
|
1702
|
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
Whether to do log at all. Default is from LOG environment variable, or 1. This |
|
1704
|
|
|
|
|
|
|
option is only to allow users to disable Log::Any::App (thus speeding up startup |
|
1705
|
|
|
|
|
|
|
by avoiding loading Log4perl, etc) by passing LOG=1 environment when running |
|
1706
|
|
|
|
|
|
|
programs. However, if you explicitly set this option to 1, Log::Any::App cannot |
|
1707
|
|
|
|
|
|
|
be disabled this way. |
|
1708
|
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
=item -init => BOOL |
|
1710
|
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
Whether to call Log::Log4perl->init() after setting up the Log4perl |
|
1712
|
|
|
|
|
|
|
configuration. Default is true. You can set this to false, and you can |
|
1713
|
|
|
|
|
|
|
initialize Log4perl yourself (but then there's not much point in using this |
|
1714
|
|
|
|
|
|
|
module, right?) |
|
1715
|
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
=item -name => STRING |
|
1717
|
|
|
|
|
|
|
|
|
1718
|
|
|
|
|
|
|
Change the program name. Default is taken from $0. |
|
1719
|
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
=item -level_flag_paths => ARRAY OF STRING |
|
1721
|
|
|
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
Edit level flag file locations. The default is [$homedir, "/etc"]. |
|
1723
|
|
|
|
|
|
|
|
|
1724
|
|
|
|
|
|
|
=item -daemon => BOOL |
|
1725
|
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
Declare that script is a daemon. Default is no. Aside from this, to declare that |
|
1727
|
|
|
|
|
|
|
your script is a daemon you can also set $main::IS_DAEMON to true. |
|
1728
|
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
=item -category_alias => {ALIAS=>CATEGORY, ...} |
|
1730
|
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
Create category aliases so the ALIAS can be used in place of real categories in |
|
1732
|
|
|
|
|
|
|
each output's category specification. For example, instead of doing this: |
|
1733
|
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
init( |
|
1735
|
|
|
|
|
|
|
-file => [category=>[qw/Foo Bar Baz/], ...], |
|
1736
|
|
|
|
|
|
|
-screen => [category=>[qw/Foo Bar Baz/]], |
|
1737
|
|
|
|
|
|
|
); |
|
1738
|
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
you can do this instead: |
|
1740
|
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
init( |
|
1742
|
|
|
|
|
|
|
-category_alias => {-fbb => [qw/Foo Bar Baz/]}, |
|
1743
|
|
|
|
|
|
|
-file => [category=>'-fbb', ...], |
|
1744
|
|
|
|
|
|
|
-screen => [category=>'-fbb', ...], |
|
1745
|
|
|
|
|
|
|
); |
|
1746
|
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
You can also specify this from the environment variable LOG_CATEGORY_ALIAS using |
|
1748
|
|
|
|
|
|
|
JSON encoding, e.g. |
|
1749
|
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
LOG_CATEGORY_ALIAS='{"-fbb":["Foo","Bar","Baz"]}' |
|
1751
|
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
=item -category_level => {CATEGORY=>LEVEL, ...} |
|
1753
|
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
Specify per-category level. Categories not mentioned on this will use the |
|
1755
|
|
|
|
|
|
|
general level (-level). This can be used to increase or decrease logging on |
|
1756
|
|
|
|
|
|
|
certain categories/modules. |
|
1757
|
|
|
|
|
|
|
|
|
1758
|
|
|
|
|
|
|
You can also specify this from the environment variable LOG_CATEGORY_LEVEL using |
|
1759
|
|
|
|
|
|
|
JSON encoding, e.g. |
|
1760
|
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
LOG_CATEGORY_LEVEL='{"-fbb":"off"}' |
|
1762
|
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
=item -level => 'trace'|'debug'|'info'|'warn'|'error'|'fatal'|'off' |
|
1764
|
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
Specify log level for all outputs. Each output can override this value. The |
|
1766
|
|
|
|
|
|
|
default log level is determined as follow: |
|
1767
|
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
B<Search in command-line options>. If L<App::Options> is present, these keys are |
|
1769
|
|
|
|
|
|
|
checked in B<%App::options>: B<log_level>, B<trace> (if true then level is |
|
1770
|
|
|
|
|
|
|
C<trace>), B<debug> (if true then level is C<debug>), B<verbose> (if true then |
|
1771
|
|
|
|
|
|
|
level is C<info>), B<quiet> (if true then level is C<error>). |
|
1772
|
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
Otherwise, it will try to scrape @ARGV for the presence of B<--log-level>, |
|
1774
|
|
|
|
|
|
|
B<--trace>, B<--debug>, B<--verbose>, or B<--quiet> (this usually works because |
|
1775
|
|
|
|
|
|
|
Log::Any::App does this in the INIT phase, before you call L<Getopt::Long>'s |
|
1776
|
|
|
|
|
|
|
GetOptions() or the like). |
|
1777
|
|
|
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
B<Search in environment variables>. Otherwise, it will look for environment |
|
1779
|
|
|
|
|
|
|
variables: B<LOG_LEVEL>, B<QUIET>. B<VERBOSE>, B<DEBUG>, B<TRACE>. |
|
1780
|
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
B<Search in level flag files>. Otherwise, it will look for existence of files |
|
1782
|
|
|
|
|
|
|
with one of these names C<$NAME.QUIET>, C<$NAME.VERBOSE>, C<$NAME.TRACE>, |
|
1783
|
|
|
|
|
|
|
C<$NAME.DEBUG>, or content of C<$NAME.log_level> in ~ or /etc. |
|
1784
|
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
B<Search in main package variables>. Otherwise, it will try to search for |
|
1786
|
|
|
|
|
|
|
package variables in the C<main> namespace with names like C<$Log_Level> or |
|
1787
|
|
|
|
|
|
|
C<$LOG_LEVEL> or C<$log_level>, C<$Quiet> or C<$QUIET> or C<$quiet>, C<$Verbose> |
|
1788
|
|
|
|
|
|
|
or C<$VERBOSE> or C<$verbose>, C<$Trace> or C<$TRACE> or C<$trace>, C<$Debug> or |
|
1789
|
|
|
|
|
|
|
C<$DEBUG> or C<$debug>. |
|
1790
|
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
If everything fails, it defaults to 'warn'. |
|
1792
|
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
=item -filter_text => STR |
|
1794
|
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
Only show log lines matching STR. Default from C<LOG_FILTER_TEXT> environment. |
|
1796
|
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
=item -filter_no_text => STR |
|
1798
|
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
Only show log lines not matching STR. Default from C<LOG_FILTER_NO_TEXT> |
|
1800
|
|
|
|
|
|
|
environment. |
|
1801
|
|
|
|
|
|
|
|
|
1802
|
|
|
|
|
|
|
=item -filter_citext => STR |
|
1803
|
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
Only show log lines matching STR (case insensitive). Default from |
|
1805
|
|
|
|
|
|
|
C<LOG_FILTER_CITEXT> environment. |
|
1806
|
|
|
|
|
|
|
|
|
1807
|
|
|
|
|
|
|
=item -filter_no_citext => STR |
|
1808
|
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
Only show log lines not matching STR (case insensitive). Default from |
|
1810
|
|
|
|
|
|
|
C<LOG_FILTER_NO_CITEXT> environment. |
|
1811
|
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
=item -filter_re => RE |
|
1813
|
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
Only show log lines matching regex pattern RE. Default from C<LOG_FILTER_RE> |
|
1815
|
|
|
|
|
|
|
environment. |
|
1816
|
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
=item -filter_no_re => RE |
|
1818
|
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
Only show log lines not matching regex pattern RE. Default from |
|
1820
|
|
|
|
|
|
|
C<LOG_FILTER_NO_RE> environment. |
|
1821
|
|
|
|
|
|
|
|
|
1822
|
|
|
|
|
|
|
=item -file => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...] |
|
1823
|
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
Specify output to one or more files, using L<Log::Dispatch::FileWriteRotate>. |
|
1825
|
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
If the argument is a false boolean value, file logging will be turned off. If |
|
1827
|
|
|
|
|
|
|
argument is a true value that matches /^(1|yes|true)$/i, file logging will be |
|
1828
|
|
|
|
|
|
|
turned on with default path, etc. If the argument is another scalar value then |
|
1829
|
|
|
|
|
|
|
it is assumed to be a path. If the argument is a hashref, then the keys of the |
|
1830
|
|
|
|
|
|
|
hashref must be one of: C<level>, C<path>, C<max_size> (maximum size before |
|
1831
|
|
|
|
|
|
|
rotating, in bytes, 0 means unlimited or never rotate), C<histories> (number of |
|
1832
|
|
|
|
|
|
|
old files to keep, excluding the current file), C<suffix> (will be passed to |
|
1833
|
|
|
|
|
|
|
Log::Dispatch::FileWriteRotate's constructor), C<period> (will be passed to |
|
1834
|
|
|
|
|
|
|
Log::Dispatch::FileWriteRotate's constructor), C<buffer_size> (will be passed to |
|
1835
|
|
|
|
|
|
|
Log::Dispatch::FileWriteRotate's constructor), C<category> (a string of ref to |
|
1836
|
|
|
|
|
|
|
array of strings), C<category_level> (a hashref, similar to -category_level), |
|
1837
|
|
|
|
|
|
|
C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern), |
|
1838
|
|
|
|
|
|
|
C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>, |
|
1839
|
|
|
|
|
|
|
C<filter_re>, C<filter_no_re>. |
|
1840
|
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
If the argument is an arrayref, it is assumed to be specifying multiple files, |
|
1842
|
|
|
|
|
|
|
with each element of the array as a hashref. |
|
1843
|
|
|
|
|
|
|
|
|
1844
|
|
|
|
|
|
|
How Log::Any::App determines defaults for file logging: |
|
1845
|
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
If program is a one-liner script specified using "perl -e", the default is no |
|
1847
|
|
|
|
|
|
|
file logging. Otherwise file logging is turned on. |
|
1848
|
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
If the program runs as root, the default path is C</var/log/$NAME.log>, where |
|
1850
|
|
|
|
|
|
|
$NAME is taken from B<$0> (or C<-name>). Otherwise the default path is |
|
1851
|
|
|
|
|
|
|
~/$NAME.log. Intermediate directories will be made with L<File::Path>. |
|
1852
|
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
If specified C<path> ends with a slash (e.g. "/my/log/"), it is assumed to be a |
|
1854
|
|
|
|
|
|
|
directory and the final file path is directory appended with $NAME.log. |
|
1855
|
|
|
|
|
|
|
|
|
1856
|
|
|
|
|
|
|
Default rotating behaviour is no rotate (max_size = 0). |
|
1857
|
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
Default level for file is the same as the global level set by B<-level>. But |
|
1859
|
|
|
|
|
|
|
App::options, command line, environment, level flag file, and package variables |
|
1860
|
|
|
|
|
|
|
in main are also searched first (for B<FILE_LOG_LEVEL>, B<FILE_TRACE>, |
|
1861
|
|
|
|
|
|
|
B<FILE_DEBUG>, B<FILE_VERBOSE>, B<FILE_QUIET>, and the similars). |
|
1862
|
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
You can also specify category level from environment FILE_LOG_CATEGORY_LEVEL. |
|
1864
|
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
=item -dir => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...] |
|
1866
|
|
|
|
|
|
|
|
|
1867
|
|
|
|
|
|
|
Log messages using L<Log::Dispatch::Dir>. Each message is logged into separate |
|
1868
|
|
|
|
|
|
|
files in the directory. Useful for dumping content (e.g. HTML, network dumps, or |
|
1869
|
|
|
|
|
|
|
temporary results). |
|
1870
|
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
If the argument is a false boolean value, dir logging will be turned off. If |
|
1872
|
|
|
|
|
|
|
argument is a true value that matches /^(1|yes|true)$/i, dir logging will be |
|
1873
|
|
|
|
|
|
|
turned on with defaults path, etc. If the argument is another scalar value then |
|
1874
|
|
|
|
|
|
|
it is assumed to be a directory path. If the argument is a hashref, then the |
|
1875
|
|
|
|
|
|
|
keys of the hashref must be one of: C<level>, C<path>, C<max_size> (maximum |
|
1876
|
|
|
|
|
|
|
total size of files before deleting older files, in bytes, 0 means unlimited), |
|
1877
|
|
|
|
|
|
|
C<max_age> (maximum age of files to keep, in seconds, undef means unlimited). |
|
1878
|
|
|
|
|
|
|
C<histories> (number of old files to keep, excluding the current file), |
|
1879
|
|
|
|
|
|
|
C<category>, C<category_level> (a hashref, similar to -category_level), |
|
1880
|
|
|
|
|
|
|
C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern), |
|
1881
|
|
|
|
|
|
|
C<filename_pattern> (pattern of file name), C<filter_text>, C<filter_no_text>, |
|
1882
|
|
|
|
|
|
|
C<filter_citext>, C<filter_no_citext>, C<filter_re>, C<filter_no_re>. |
|
1883
|
|
|
|
|
|
|
|
|
1884
|
|
|
|
|
|
|
If the argument is an arrayref, it is assumed to be specifying multiple |
|
1885
|
|
|
|
|
|
|
directories, with each element of the array as a hashref. |
|
1886
|
|
|
|
|
|
|
|
|
1887
|
|
|
|
|
|
|
How Log::Any::App determines defaults for dir logging: |
|
1888
|
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
Directory logging is by default turned off. You have to explicitly turn it on. |
|
1890
|
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
If the program runs as root, the default path is C</var/log/$NAME/>, where $NAME |
|
1892
|
|
|
|
|
|
|
is taken from B<$0>. Otherwise the default path is ~/log/$NAME/. Intermediate |
|
1893
|
|
|
|
|
|
|
directories will be created with File::Path. Program name can be changed using |
|
1894
|
|
|
|
|
|
|
C<-name>. |
|
1895
|
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
Default rotating parameters are: histories=1000, max_size=0, max_age=undef. |
|
1897
|
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
Default level for dir logging is the same as the global level set by B<-level>. |
|
1899
|
|
|
|
|
|
|
But App::options, command line, environment, level flag file, and package |
|
1900
|
|
|
|
|
|
|
variables in main are also searched first (for B<DIR_LOG_LEVEL>, B<DIR_TRACE>, |
|
1901
|
|
|
|
|
|
|
B<DIR_DEBUG>, B<DIR_VERBOSE>, B<DIR_QUIET>, and the similars). |
|
1902
|
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
You can also specify category level from environment DIR_LOG_CATEGORY_LEVEL. |
|
1904
|
|
|
|
|
|
|
|
|
1905
|
|
|
|
|
|
|
=item -screen => 0 | 1|yes|true | {opts} |
|
1906
|
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
Log messages using L<Log::Log4perl::Appender::ScreenColoredLevels>. |
|
1908
|
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
If the argument is a false boolean value, screen logging will be turned off. If |
|
1910
|
|
|
|
|
|
|
argument is a true value that matches /^(1|yes|true)$/i, screen logging will be |
|
1911
|
|
|
|
|
|
|
turned on with default settings. If the argument is a hashref, then the keys of |
|
1912
|
|
|
|
|
|
|
the hashref must be one of: C<color> (default is true, set to 0 to turn off |
|
1913
|
|
|
|
|
|
|
color), C<stderr> (default is true, set to 0 to log to stdout instead), |
|
1914
|
|
|
|
|
|
|
C<level>, C<category>, C<category_level> (a hashref, similar to |
|
1915
|
|
|
|
|
|
|
-category_level), C<pattern_style> (see L<"PATTERN STYLE">), C<pattern> |
|
1916
|
|
|
|
|
|
|
(Log4perl string pattern), C<filter_text>, C<filter_no_text>, C<filter_citext>, |
|
1917
|
|
|
|
|
|
|
C<filter_no_citext>, C<filter_re>, C<filter_no_re>. |
|
1918
|
|
|
|
|
|
|
|
|
1919
|
|
|
|
|
|
|
How Log::Any::App determines defaults for screen logging: |
|
1920
|
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
Screen logging is turned on by default. |
|
1922
|
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
Default level for screen logging is the same as the global level set by |
|
1924
|
|
|
|
|
|
|
B<-level>. But App::options, command line, environment, level flag file, and |
|
1925
|
|
|
|
|
|
|
package variables in main are also searched first (for B<SCREEN_LOG_LEVEL>, |
|
1926
|
|
|
|
|
|
|
B<SCREEN_TRACE>, B<SCREEN_DEBUG>, B<SCREEN_VERBOSE>, B<SCREEN_QUIET>, and the |
|
1927
|
|
|
|
|
|
|
similars). |
|
1928
|
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
Color can also be turned on/off using environment variable COLOR (if B<color> |
|
1930
|
|
|
|
|
|
|
argument is not set). |
|
1931
|
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
You can also specify category level from environment SCREEN_LOG_CATEGORY_LEVEL. |
|
1933
|
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
=item -syslog => 0 | 1|yes|true | {opts} |
|
1935
|
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
Log messages using L<Log::Dispatch::Syslog>. |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
If the argument is a false boolean value, syslog logging will be turned off. If |
|
1939
|
|
|
|
|
|
|
argument is a true value that matches /^(1|yes|true)$/i, syslog logging will be |
|
1940
|
|
|
|
|
|
|
turned on with default level, ident, etc. If the argument is a hashref, then the |
|
1941
|
|
|
|
|
|
|
keys of the hashref must be one of: C<level>, C<ident>, C<facility>, |
|
1942
|
|
|
|
|
|
|
C<category>, C<category_level> (a hashref, similar to -category_level), |
|
1943
|
|
|
|
|
|
|
C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern), |
|
1944
|
|
|
|
|
|
|
C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>, |
|
1945
|
|
|
|
|
|
|
C<filter_re>, C<filter_no_re>. |
|
1946
|
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
How Log::Any::App determines defaults for syslog logging: |
|
1948
|
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
If a program is a daemon (determined by detecting modules like L<Net::Server> or |
|
1950
|
|
|
|
|
|
|
L<Proc::PID::File>, or by checking if -daemon or $main::IS_DAEMON is true) then |
|
1951
|
|
|
|
|
|
|
syslog logging is turned on by default and facility is set to C<daemon>, |
|
1952
|
|
|
|
|
|
|
otherwise the default is off. |
|
1953
|
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
Ident is program's name by default ($0, or C<-name>). |
|
1955
|
|
|
|
|
|
|
|
|
1956
|
|
|
|
|
|
|
Default level for syslog logging is the same as the global level set by |
|
1957
|
|
|
|
|
|
|
B<-level>. But App::options, command line, environment, level flag file, and |
|
1958
|
|
|
|
|
|
|
package variables in main are also searched first (for B<SYSLOG_LOG_LEVEL>, |
|
1959
|
|
|
|
|
|
|
B<SYSLOG_TRACE>, B<SYSLOG_DEBUG>, B<SYSLOG_VERBOSE>, B<SYSLOG_QUIET>, and the |
|
1960
|
|
|
|
|
|
|
similars). |
|
1961
|
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
You can also specify category level from environment SYSLOG_LOG_CATEGORY_LEVEL. |
|
1963
|
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
=item -unixsock => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...] |
|
1965
|
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
Specify output to one or more B<existing, listening, datagram> Unix domain |
|
1967
|
|
|
|
|
|
|
sockets, using L<Log::Log4perl::Appender::Socket::UNIX>. |
|
1968
|
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
The listening end might be a different process, or the same process using a |
|
1970
|
|
|
|
|
|
|
different thread of nonblocking I/O. It usually makes little sense to make the |
|
1971
|
|
|
|
|
|
|
same program the listening end. If you want, for example, to let a client |
|
1972
|
|
|
|
|
|
|
connects to your program to see logs being produced, you might want to setup an |
|
1973
|
|
|
|
|
|
|
in-memory output (C<-array>) and create another thread or non-blocking I/O to |
|
1974
|
|
|
|
|
|
|
listen to client requests and show them the content of the array when requested. |
|
1975
|
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
If the argument is a false boolean value, Unix domain socket logging will be |
|
1977
|
|
|
|
|
|
|
turned off. If argument is a true value that matches /^(1|yes|true)$/i, Unix |
|
1978
|
|
|
|
|
|
|
domain socket logging will be turned on with default path, etc. If the argument |
|
1979
|
|
|
|
|
|
|
is another scalar value then it is assumed to be a path. If the argument is a |
|
1980
|
|
|
|
|
|
|
hashref, then the keys of the hashref must be one of: C<level>, C<path>, |
|
1981
|
|
|
|
|
|
|
C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>, |
|
1982
|
|
|
|
|
|
|
C<filter_re>, C<filter_no_re>. |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
If the argument is an arrayref, it is assumed to be specifying multiple sockets, |
|
1985
|
|
|
|
|
|
|
with each element of the array as a hashref. |
|
1986
|
|
|
|
|
|
|
|
|
1987
|
|
|
|
|
|
|
How Log::Any::App determines defaults for Unix domain socket logging: |
|
1988
|
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
By default Unix domain socket logging is off. |
|
1990
|
|
|
|
|
|
|
|
|
1991
|
|
|
|
|
|
|
If the program runs as root, the default path is C</var/run/$NAME-log.sock>, |
|
1992
|
|
|
|
|
|
|
where $NAME is taken from B<$0> (or C<-name>). Otherwise the default path is |
|
1993
|
|
|
|
|
|
|
~/$NAME-log.sock. |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
If specified C<path> ends with a slash (e.g. "/my/log/"), it is assumed to be a |
|
1996
|
|
|
|
|
|
|
directory and the final socket path is directory appended with $NAME-log.sock. |
|
1997
|
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
Default level is the same as the global level set by B<-level>. But |
|
1999
|
|
|
|
|
|
|
App::options, command line, environment, level flag file, and package variables |
|
2000
|
|
|
|
|
|
|
in main are also searched first (for B<UNIXSOCK_LOG_LEVEL>, B<UNIXSOCK_TRACE>, |
|
2001
|
|
|
|
|
|
|
B<UNIXSOCK_DEBUG>, B<UNIXSOCK_VERBOSE>, B<UNIXSOCK_QUIET>, and the similars). |
|
2002
|
|
|
|
|
|
|
|
|
2003
|
|
|
|
|
|
|
You can also specify category level from environment |
|
2004
|
|
|
|
|
|
|
UNIXSOCK_LOG_CATEGORY_LEVEL. |
|
2005
|
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
=item -array => 0 | {opts} | [{opts}, ...] |
|
2007
|
|
|
|
|
|
|
|
|
2008
|
|
|
|
|
|
|
Specify output to one or more Perl arrays. Logging will be done using |
|
2009
|
|
|
|
|
|
|
L<Log::Dispatch::ArrayWithLimits>. Note that the syntax is: |
|
2010
|
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
-array => {array=>$ary} |
|
2012
|
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
and not just: |
|
2014
|
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
-array => $ary |
|
2016
|
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
because that will be interpreted as multiple array outputs: |
|
2018
|
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
-array => [{output1}, ...] |
|
2020
|
|
|
|
|
|
|
|
|
2021
|
|
|
|
|
|
|
If the argument is a false boolean value, array logging will be turned off. |
|
2022
|
|
|
|
|
|
|
Otherwise argument must be a hashref or an arrayref (to specify multiple |
|
2023
|
|
|
|
|
|
|
outputs). If the argument is a hashref, then the keys of the hashref must be one |
|
2024
|
|
|
|
|
|
|
of: C<level>, C<array> (defaults to new anonymous array []), C<filter_text>, |
|
2025
|
|
|
|
|
|
|
C<filter_no_text>, C<filter_citext>, C<filter_no_citext>, C<filter_re>, |
|
2026
|
|
|
|
|
|
|
C<filter_no_re>. If the argument is an arrayref, it is assumed to be specifying |
|
2027
|
|
|
|
|
|
|
multiple sockets, with each element of the array as a hashref. |
|
2028
|
|
|
|
|
|
|
|
|
2029
|
|
|
|
|
|
|
How Log::Any::App determines defaults for array logging: |
|
2030
|
|
|
|
|
|
|
|
|
2031
|
|
|
|
|
|
|
By default array logging is off. |
|
2032
|
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
Default level is the same as the global level set by B<-level>. But |
|
2034
|
|
|
|
|
|
|
App::options, command line, environment, level flag file, and package variables |
|
2035
|
|
|
|
|
|
|
in main are also searched first (for B<ARRAY_LOG_LEVEL>, B<ARRAY_TRACE>, |
|
2036
|
|
|
|
|
|
|
B<ARRAY_DEBUG>, B<ARRAY_VERBOSE>, B<ARRAY_QUIET>, and the similars). |
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
You can also specify category level from environment ARRAY_LOG_CATEGORY_LEVEL. |
|
2039
|
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
=item -dump => BOOL |
|
2041
|
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
If set to true then Log::Any::App will dump the generated Log4perl config. |
|
2043
|
|
|
|
|
|
|
Useful for debugging the logging. |
|
2044
|
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
=back |
|
2046
|
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
=head1 FAQ |
|
2048
|
|
|
|
|
|
|
|
|
2049
|
|
|
|
|
|
|
=head2 Why? |
|
2050
|
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
I initially wrote Log::Any::App because I'm sick of having to parse command-line |
|
2052
|
|
|
|
|
|
|
options to set log level like --verbose, --log-level=debug for every script. |
|
2053
|
|
|
|
|
|
|
Also, before using Log::Any I previously used Log4perl directly and modules |
|
2054
|
|
|
|
|
|
|
which produce logs using Log4perl cannot be directly use'd in one-liners without |
|
2055
|
|
|
|
|
|
|
Log4perl complaining about uninitialized configuration or some such. Thus, I |
|
2056
|
|
|
|
|
|
|
like Log::Any's default null adapter and want to settle using Log::Any for any |
|
2057
|
|
|
|
|
|
|
kind of logging. Log::Any::App makes it easy to output Log::Any logs in your |
|
2058
|
|
|
|
|
|
|
scripts and even one-liners. |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
=head2 What's the benefit of using Log::Any::App? |
|
2061
|
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
You get all the benefits of Log::Any, as what Log::Any::App does is just wrap |
|
2063
|
|
|
|
|
|
|
Log::Any and Log4perl with some nice defaults. It provides you with an easy way |
|
2064
|
|
|
|
|
|
|
to consume Log::Any logs and customize level/some other options via various |
|
2065
|
|
|
|
|
|
|
ways. |
|
2066
|
|
|
|
|
|
|
|
|
2067
|
|
|
|
|
|
|
=head2 And what's the benefit of using Log::Any? |
|
2068
|
|
|
|
|
|
|
|
|
2069
|
|
|
|
|
|
|
This is better described in the Log::Any documentation itself, but in short: |
|
2070
|
|
|
|
|
|
|
Log::Any frees your module users to use whatever logging framework they want. It |
|
2071
|
|
|
|
|
|
|
increases the reusability of your modules. |
|
2072
|
|
|
|
|
|
|
|
|
2073
|
|
|
|
|
|
|
=head2 Do I need Log::Any::App if I am writing modules? |
|
2074
|
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
No, if you write modules just use Log::Any. |
|
2076
|
|
|
|
|
|
|
|
|
2077
|
|
|
|
|
|
|
=head2 Why use Log4perl? |
|
2078
|
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
Log::Any::App uses the Log4perl adapter to display the logs because it is |
|
2080
|
|
|
|
|
|
|
mature, flexible, featureful. The other alternative adapter is Log::Dispatch, |
|
2081
|
|
|
|
|
|
|
but you can use Log::Dispatch::* output modules in Log4perl and (currently) not |
|
2082
|
|
|
|
|
|
|
vice versa. |
|
2083
|
|
|
|
|
|
|
|
|
2084
|
|
|
|
|
|
|
Other adapters might be considered in the future, for now I'm fairly satisfied |
|
2085
|
|
|
|
|
|
|
with Log4perl. It does have a slightly heavy startup cost for my taste, but it |
|
2086
|
|
|
|
|
|
|
is still bearable. |
|
2087
|
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
=head2 Are you coupling adapter with Log::Any (thus defeating Log::Any's purpose)? |
|
2089
|
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
No, producing logs are still done with Log::Any as usual and not tied to |
|
2091
|
|
|
|
|
|
|
Log4perl in any way. Your modules, as explained above, only 'use Log::Any' and |
|
2092
|
|
|
|
|
|
|
do not depend on Log::Any::App at all. |
|
2093
|
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
Should portions of your application code get refactored into modules later, you |
|
2095
|
|
|
|
|
|
|
don't need to change the logging part. And if your application becomes more |
|
2096
|
|
|
|
|
|
|
complex and Log::Any::App doesn't suffice your custom logging needs anymore, you |
|
2097
|
|
|
|
|
|
|
can just replace 'use Log::Any::App' line with something more adequate. |
|
2098
|
|
|
|
|
|
|
|
|
2099
|
|
|
|
|
|
|
=head2 How do I create extra logger objects? |
|
2100
|
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
The usual way as with Log::Any: |
|
2102
|
|
|
|
|
|
|
|
|
2103
|
|
|
|
|
|
|
my $other_log = Log::Any->get_logger(category => $category); |
|
2104
|
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
=head2 My needs are not met by the simple configuration system of Log::Any::App! |
|
2106
|
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
You can use the Log4perl adapter directly and write your own Log4perl |
|
2108
|
|
|
|
|
|
|
configuration (or even other adapters). Log::Any::App is meant for quick and |
|
2109
|
|
|
|
|
|
|
simple logging output needs anyway (but do tell me if your logging output needs |
|
2110
|
|
|
|
|
|
|
are reasonably simple and should be supported by Log::Any::App). |
|
2111
|
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
=head2 What is array output for? |
|
2113
|
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
Logging to a Perl array might be useful for testing/debugging, or (one use-case |
|
2115
|
|
|
|
|
|
|
I can think of) for letting users of your program connect to your program |
|
2116
|
|
|
|
|
|
|
directly to request viewing the logs being produced (although logging to other |
|
2117
|
|
|
|
|
|
|
outputs doesn't preclude this ability). For example, here is a program that uses |
|
2118
|
|
|
|
|
|
|
a separate thread to listen to Unix socket for requests to view the (last 100) |
|
2119
|
|
|
|
|
|
|
logs. Requires perl built with threads enabled. |
|
2120
|
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
use threads; |
|
2122
|
|
|
|
|
|
|
use threads::shared; |
|
2123
|
|
|
|
|
|
|
BEGIN { our @buf :shared } |
|
2124
|
|
|
|
|
|
|
use IO::Socket::UNIX::Util qw(create_unix_stream_socket); |
|
2125
|
|
|
|
|
|
|
use Log::Any::App '$log', -array => [{array => 'main::buf', max_elems=>100}]; |
|
2126
|
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
my $sock = create_unix_stream_socket('/tmp/app-logview.sock'); |
|
2128
|
|
|
|
|
|
|
|
|
2129
|
|
|
|
|
|
|
# thread to listen to unix socket and receive log viewing instruction |
|
2130
|
|
|
|
|
|
|
my $thr = threads->create( |
|
2131
|
|
|
|
|
|
|
sub { |
|
2132
|
|
|
|
|
|
|
local $| = 1; |
|
2133
|
|
|
|
|
|
|
while (my $cli = $sock->accept) { |
|
2134
|
|
|
|
|
|
|
while (1) { |
|
2135
|
|
|
|
|
|
|
print $cli "> "; |
|
2136
|
|
|
|
|
|
|
my $line = <$cli>; |
|
2137
|
|
|
|
|
|
|
last unless $line; |
|
2138
|
|
|
|
|
|
|
if ($line =~ /\Ar(ead)?\b/i) { |
|
2139
|
|
|
|
|
|
|
print $cli @buf; |
|
2140
|
|
|
|
|
|
|
} else { |
|
2141
|
|
|
|
|
|
|
print $cli "Unknown command\n"; |
|
2142
|
|
|
|
|
|
|
} |
|
2143
|
|
|
|
|
|
|
} |
|
2144
|
|
|
|
|
|
|
} |
|
2145
|
|
|
|
|
|
|
}); |
|
2146
|
|
|
|
|
|
|
|
|
2147
|
|
|
|
|
|
|
# main thread, application which produces logs |
|
2148
|
|
|
|
|
|
|
$|++; |
|
2149
|
|
|
|
|
|
|
while (1) { |
|
2150
|
|
|
|
|
|
|
$log->warnf("Log (%d) ...", ++$i); |
|
2151
|
|
|
|
|
|
|
sleep 1; |
|
2152
|
|
|
|
|
|
|
} |
|
2153
|
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
After you run this program, you can connect to it, e.g. from another terminal: |
|
2155
|
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
% socat UNIX-CONNECT:/tmp/app-logview.sock - |
|
2157
|
|
|
|
|
|
|
> read |
|
2158
|
|
|
|
|
|
|
[2014/07/06 23:34:49] Log (1) ... |
|
2159
|
|
|
|
|
|
|
[2014/07/06 23:34:50] Log (2) ... |
|
2160
|
|
|
|
|
|
|
[2014/07/06 23:34:50] Log (3) ... |
|
2161
|
|
|
|
|
|
|
[2014/07/06 23:34:51] Log (4) ... |
|
2162
|
|
|
|
|
|
|
[2014/07/06 23:34:51] Log (5) ... |
|
2163
|
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
=head1 ENVIRONMENT |
|
2165
|
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
Below is summary of environment variables used. |
|
2167
|
|
|
|
|
|
|
|
|
2168
|
|
|
|
|
|
|
=head2 Turning on/off logging |
|
2169
|
|
|
|
|
|
|
|
|
2170
|
|
|
|
|
|
|
LOG (bool) |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
=head2 Setting general level |
|
2173
|
|
|
|
|
|
|
|
|
2174
|
|
|
|
|
|
|
TRACE (bool) setting general level to trace |
|
2175
|
|
|
|
|
|
|
DEBUG (bool) setting general level to debug |
|
2176
|
|
|
|
|
|
|
VERBOSE (bool) setting general level to info |
|
2177
|
|
|
|
|
|
|
QUIET (bool) setting general level to error (turn off warnings) |
|
2178
|
|
|
|
|
|
|
LOG_LEVEL (str) |
|
2179
|
|
|
|
|
|
|
|
|
2180
|
|
|
|
|
|
|
=head2 Setting per-output level |
|
2181
|
|
|
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
FILE_TRACE, FILE_DEBUG, FILE_VERBOSE, FILE_QUIET, FILE_LOG_LEVEL |
|
2183
|
|
|
|
|
|
|
SCREEN_TRACE and so on |
|
2184
|
|
|
|
|
|
|
DIR_TRACE and so on |
|
2185
|
|
|
|
|
|
|
SYSLOG_TRACE and so on |
|
2186
|
|
|
|
|
|
|
UNIXSOCK_TRACE and so on |
|
2187
|
|
|
|
|
|
|
ARRAY_TRACE and so on |
|
2188
|
|
|
|
|
|
|
|
|
2189
|
|
|
|
|
|
|
=head2 Setting per-category level |
|
2190
|
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
LOG_CATEGORY_LEVEL (hash, json) |
|
2192
|
|
|
|
|
|
|
LOG_CATEGORY_ALIAS (hash, json) |
|
2193
|
|
|
|
|
|
|
|
|
2194
|
|
|
|
|
|
|
=head2 Setting per-output, per-category level |
|
2195
|
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
FILE_LOG_CATEGORY_LEVEL |
|
2197
|
|
|
|
|
|
|
SCREEN_LOG_CATEGORY_LEVEL |
|
2198
|
|
|
|
|
|
|
and so on |
|
2199
|
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
=head2 Controlling extra fields to log |
|
2201
|
|
|
|
|
|
|
|
|
2202
|
|
|
|
|
|
|
LOG_SHOW_LOCATION |
|
2203
|
|
|
|
|
|
|
LOG_SHOW_CATEGORY |
|
2204
|
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
=head2 Force-enable or disable color |
|
2206
|
|
|
|
|
|
|
|
|
2207
|
|
|
|
|
|
|
COLOR (bool) |
|
2208
|
|
|
|
|
|
|
|
|
2209
|
|
|
|
|
|
|
=head2 Turn on Log::Any::App's debugging |
|
2210
|
|
|
|
|
|
|
|
|
2211
|
|
|
|
|
|
|
LOGANYAPP_DEBUG (bool) |
|
2212
|
|
|
|
|
|
|
|
|
2213
|
|
|
|
|
|
|
=head2 Turn on showing elapsed time in screen |
|
2214
|
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
LOG_ELAPSED_TIME_IN_SCREEN (bool) |
|
2216
|
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
Note that elapsed time is currently produced using Log::Log4perl's %r (number of |
|
2218
|
|
|
|
|
|
|
milliseconds since the program started, where program started means when |
|
2219
|
|
|
|
|
|
|
Log::Log4perl starts counting time). |
|
2220
|
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
=head2 Filtering |
|
2222
|
|
|
|
|
|
|
|
|
2223
|
|
|
|
|
|
|
LOG_FILTER_TEXT (str) |
|
2224
|
|
|
|
|
|
|
LOG_FILTER_NO_TEXT (str) |
|
2225
|
|
|
|
|
|
|
LOG_FILTER_CITEXT (str) |
|
2226
|
|
|
|
|
|
|
LOG_FILTER_NO_CITEXT (str) |
|
2227
|
|
|
|
|
|
|
LOG_FILTER_RE (str) |
|
2228
|
|
|
|
|
|
|
LOG_FILTER_NO_RE (str) |
|
2229
|
|
|
|
|
|
|
|
|
2230
|
|
|
|
|
|
|
=head2 Per-output filtering |
|
2231
|
|
|
|
|
|
|
|
|
2232
|
|
|
|
|
|
|
{FILE,DIR,SCREEN,SYSLOG,UNIXSOCK,ARRAY}_LOG_FILTER_TEXT (str) |
|
2233
|
|
|
|
|
|
|
and so on |
|
2234
|
|
|
|
|
|
|
|
|
2235
|
|
|
|
|
|
|
=head2 Extra things to log |
|
2236
|
|
|
|
|
|
|
|
|
2237
|
|
|
|
|
|
|
=over |
|
2238
|
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
=item * LOG_ENV (bool) |
|
2240
|
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
If set to 1, will dump environment variables at the start of program. Useful for |
|
2242
|
|
|
|
|
|
|
debugging e.g. CGI or git hook scripts. You might also want to look at |
|
2243
|
|
|
|
|
|
|
L<Log::Any::Adapter::Core::Patch::UseDataDump> to make the dump more readable. |
|
2244
|
|
|
|
|
|
|
|
|
2245
|
|
|
|
|
|
|
Logging will be done under category C<main> and at level C<trace>. |
|
2246
|
|
|
|
|
|
|
|
|
2247
|
|
|
|
|
|
|
=back |
|
2248
|
|
|
|
|
|
|
|
|
2249
|
|
|
|
|
|
|
=head1 HOMEPAGE |
|
2250
|
|
|
|
|
|
|
|
|
2251
|
|
|
|
|
|
|
Please visit the project's homepage at L<https://metacpan.org/release/Log-Any-App>. |
|
2252
|
|
|
|
|
|
|
|
|
2253
|
|
|
|
|
|
|
=head1 SOURCE |
|
2254
|
|
|
|
|
|
|
|
|
2255
|
|
|
|
|
|
|
Source repository is at L<https://github.com/perlancar/perl-Log-Any-App>. |
|
2256
|
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
=head1 BUGS |
|
2258
|
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Any-App> |
|
2260
|
|
|
|
|
|
|
|
|
2261
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a |
|
2262
|
|
|
|
|
|
|
patch to an existing test-file that illustrates the bug or desired |
|
2263
|
|
|
|
|
|
|
feature. |
|
2264
|
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
2266
|
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
L<Log::Any> and L<Log::Log4perl> |
|
2268
|
|
|
|
|
|
|
|
|
2269
|
|
|
|
|
|
|
Some alternative logging modules: L<Log::Dispatchouli> (based on |
|
2270
|
|
|
|
|
|
|
L<Log::Dispatch>), L<Log::Fast>, L<Log::Log4perl::Tiny>. Really, there are 7,451 |
|
2271
|
|
|
|
|
|
|
of them (roughly one third of CPAN) at the time of this writing. |
|
2272
|
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
=head1 AUTHOR |
|
2274
|
|
|
|
|
|
|
|
|
2275
|
|
|
|
|
|
|
perlancar <perlancar@cpan.org> |
|
2276
|
|
|
|
|
|
|
|
|
2277
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
2278
|
|
|
|
|
|
|
|
|
2279
|
|
|
|
|
|
|
This software is copyright (c) 2019, 2015, 2014, 2013, 2012, 2011, 2010 by perlancar@cpan.org. |
|
2280
|
|
|
|
|
|
|
|
|
2281
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
2282
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
2283
|
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
=cut |