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 |