line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Log::ger::Output::Composite; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
4
|
|
|
|
|
|
|
our $DATE = '2020-03-11'; # DATE |
5
|
|
|
|
|
|
|
our $DIST = 'Log-ger-Output-Composite'; # DIST |
6
|
|
|
|
|
|
|
our $VERSION = '0.016'; # VERSION |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
1527
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
9
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
10
|
1
|
|
|
1
|
|
4
|
use Log::ger::Util; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
513
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# this can be used to override all level settings as it has the highest |
13
|
|
|
|
|
|
|
# precedence. |
14
|
|
|
|
|
|
|
our $Current_Level; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub meta { +{ |
17
|
7
|
|
|
7
|
0
|
17188
|
v => 2, |
18
|
|
|
|
|
|
|
} } |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _get_min_max_level { |
21
|
2160
|
|
|
2160
|
|
3074
|
my $level = shift; |
22
|
2160
|
|
|
|
|
2552
|
my ($min, $max); |
23
|
2160
|
100
|
|
|
|
3387
|
if (defined $level) { |
24
|
1620
|
50
|
|
|
|
2933
|
if (defined $Current_Level) { |
|
|
100
|
|
|
|
|
|
25
|
0
|
|
|
|
|
0
|
$min = 0; |
26
|
0
|
|
|
|
|
0
|
$max = $Current_Level; |
27
|
|
|
|
|
|
|
} elsif (ref $level eq 'ARRAY') { |
28
|
144
|
|
|
|
|
292
|
$min = Log::ger::Util::numeric_level($level->[0]); |
29
|
144
|
|
|
|
|
879
|
$max = Log::ger::Util::numeric_level($level->[1]); |
30
|
144
|
100
|
|
|
|
793
|
($min, $max) = ($max, $min) if $min > $max; |
31
|
|
|
|
|
|
|
} else { |
32
|
1476
|
|
|
|
|
1694
|
$min = 0; |
33
|
1476
|
|
|
|
|
2452
|
$max = Log::ger::Util::numeric_level($level); |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
2160
|
|
|
|
|
10142
|
($min, $max); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub get_hooks { |
40
|
7
|
|
|
7
|
0
|
100
|
my %plugin_conf = @_; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# check arguments |
43
|
7
|
|
|
|
|
21
|
for my $k (keys %plugin_conf) { |
44
|
9
|
|
|
|
|
26
|
my $conf = $plugin_conf{$k}; |
45
|
9
|
100
|
|
|
|
42
|
if ($k eq 'outputs') { |
|
|
50
|
|
|
|
|
|
46
|
7
|
|
|
|
|
35
|
for my $o (keys %$conf) { |
47
|
7
|
50
|
|
|
|
25
|
for my $oconf (ref $conf->{$o} eq 'ARRAY' ? |
48
|
7
|
|
|
|
|
17
|
@{ $conf->{$o} } : $conf->{$o}) { |
49
|
13
|
|
|
|
|
28
|
for my $k2 (keys %$oconf) { |
50
|
20
|
50
|
|
|
|
95
|
unless ($k2 =~ |
51
|
|
|
|
|
|
|
/\A(conf|level|category_level|layout)\z/) { |
52
|
0
|
|
|
|
|
0
|
die "Unknown configuration for output '$o': '$k2'"; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
} elsif ($k =~ /\A(category_level)\z/) { |
58
|
|
|
|
|
|
|
} else { |
59
|
0
|
|
|
|
|
0
|
die "Unknown configuration: '$k'"; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
7
|
|
|
|
|
12
|
my @ospecs; |
64
|
|
|
|
|
|
|
{ |
65
|
7
|
|
|
|
|
8
|
my $outputs = $plugin_conf{outputs}; |
|
7
|
|
|
|
|
13
|
|
66
|
7
|
|
|
|
|
22
|
for my $oname (sort keys %$outputs) { |
67
|
7
|
|
|
|
|
13
|
my $ospec0 = $outputs->{$oname}; |
68
|
7
|
|
|
|
|
11
|
my @ospecs0; |
69
|
7
|
50
|
|
|
|
31
|
if (ref $ospec0 eq 'ARRAY') { |
70
|
7
|
|
|
|
|
13
|
@ospecs0 = map { +{ %{$_} } } @$ospec0; |
|
13
|
|
|
|
|
18
|
|
|
13
|
|
|
|
|
42
|
|
71
|
|
|
|
|
|
|
} else { |
72
|
0
|
|
|
|
|
0
|
@ospecs0 = (+{ %{ $ospec0 } }); |
|
0
|
|
|
|
|
0
|
|
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
7
|
50
|
|
|
|
41
|
die "Invalid output name '$oname'" |
76
|
|
|
|
|
|
|
unless $oname =~ /\A\w+(::\w+)*\z/; |
77
|
7
|
|
|
|
|
23
|
my $mod = "Log::ger::Output::$oname"; |
78
|
7
|
|
|
|
|
30
|
(my $mod_pm = "$mod.pm") =~ s!::!/!g; |
79
|
7
|
|
|
|
|
459
|
require $mod_pm; |
80
|
7
|
|
|
|
|
287
|
for my $ospec (@ospecs0) { |
81
|
13
|
|
|
|
|
26
|
$ospec->{_name} = $oname; |
82
|
13
|
|
|
|
|
21
|
$ospec->{_mod} = $mod; |
83
|
13
|
|
|
|
|
28
|
push @ospecs, $ospec; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
return { |
89
|
|
|
|
|
|
|
create_outputter => [ |
90
|
|
|
|
|
|
|
__PACKAGE__, # key |
91
|
|
|
|
|
|
|
9, # priority. |
92
|
|
|
|
|
|
|
# we use a high priority to override Log::ger's default hook (at |
93
|
|
|
|
|
|
|
# priority 10) which create null outputter for levels lower than the |
94
|
|
|
|
|
|
|
# general level, since we want to do our own custom level checking. |
95
|
|
|
|
|
|
|
sub { # hook |
96
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
500
|
|
97
|
468
|
|
|
468
|
|
93211
|
require Data::Dmp; |
98
|
|
|
|
|
|
|
|
99
|
468
|
|
|
|
|
3034
|
my %hook_args = @_; # see Log::ger::Manual::Internals/"Arguments passed to hook" |
100
|
|
|
|
|
|
|
|
101
|
468
|
|
|
|
|
691
|
my $outputters = []; |
102
|
468
|
|
|
|
|
677
|
my $layouters = []; |
103
|
468
|
|
|
|
|
750
|
for my $ospec (@ospecs) { |
104
|
828
|
|
|
|
|
1283
|
my $oname = $ospec->{_name}; |
105
|
828
|
|
|
|
|
1430
|
my $mod = "Log::ger::Output::$oname"; |
106
|
828
|
50
|
|
|
|
971
|
my $hooks = &{"$mod\::get_hooks"}(%{ $ospec->{conf} || {} }) |
|
828
|
50
|
|
|
|
2610
|
|
|
828
|
|
|
|
|
1975
|
|
107
|
|
|
|
|
|
|
or die "Output module $mod does not return any hooks"; |
108
|
|
|
|
|
|
|
my @hook_args = ( |
109
|
|
|
|
|
|
|
routine_name => $hook_args{routine_name}, |
110
|
|
|
|
|
|
|
target_type => $hook_args{target_type}, |
111
|
|
|
|
|
|
|
target_name => $hook_args{target_name}, |
112
|
|
|
|
|
|
|
per_target_conf => $hook_args{per_target_conf}, |
113
|
828
|
|
|
|
|
10631
|
); |
114
|
828
|
|
|
|
|
1033
|
my $res; |
115
|
|
|
|
|
|
|
{ |
116
|
828
|
|
|
|
|
949
|
push @hook_args, (level => 60, str_level => 'trace'); |
|
828
|
|
|
|
|
1347
|
|
117
|
828
|
50
|
|
|
|
1350
|
if ($hooks->{create_log_routine}) { # old name, will be removed in the future |
118
|
0
|
|
|
|
|
0
|
$res = $hooks->{create_log_routine}->[2]->( |
119
|
|
|
|
|
|
|
@hook_args); |
120
|
0
|
0
|
|
|
|
0
|
if ($res->[0]) { |
121
|
0
|
|
|
|
|
0
|
push @$outputters, $res->[0]; |
122
|
0
|
|
|
|
|
0
|
last; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
828
|
50
|
|
|
|
1377
|
if ($hooks->{create_outputter}) { |
126
|
828
|
|
|
|
|
1783
|
$res = $hooks->{create_outputter}->[2]->( |
127
|
|
|
|
|
|
|
@hook_args); |
128
|
828
|
50
|
|
|
|
8172
|
if ($res->[0]) { |
129
|
828
|
|
|
|
|
1178
|
push @$outputters, $res->[0]; |
130
|
828
|
|
|
|
|
1069
|
last; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
0
|
|
|
|
|
0
|
die "Output module $mod does not produce outputter in ". |
134
|
|
|
|
|
|
|
"its create_outputter (or create_log_routine) hook"; # old name create_log_routine will be removed in the future |
135
|
|
|
|
|
|
|
} |
136
|
828
|
100
|
|
|
|
1333
|
if ($ospec->{layout}) { |
137
|
36
|
|
|
|
|
53
|
my $lname = $ospec->{layout}[0]; |
138
|
36
|
|
50
|
|
|
67
|
my $lconf = $ospec->{layout}[1] || {}; |
139
|
36
|
|
|
|
|
63
|
my $lmod = "Log::ger::Layout::$lname"; |
140
|
36
|
|
|
|
|
152
|
(my $lmod_pm = "$lmod.pm") =~ s!::!/!g; |
141
|
36
|
|
|
|
|
708
|
require $lmod_pm; |
142
|
36
|
50
|
|
|
|
3831
|
my $lhooks = &{"$lmod\::get_hooks"}(%$lconf) |
|
36
|
|
|
|
|
124
|
|
143
|
|
|
|
|
|
|
or die "Layout module $lmod does not return ". |
144
|
|
|
|
|
|
|
"any hooks"; |
145
|
|
|
|
|
|
|
$lhooks->{create_layouter} |
146
|
36
|
50
|
|
|
|
419
|
or die "Layout module $mod does not declare ". |
147
|
|
|
|
|
|
|
"layouter"; |
148
|
|
|
|
|
|
|
my @lhook_args = ( |
149
|
|
|
|
|
|
|
target_type => $hook_args{target_type}, |
150
|
|
|
|
|
|
|
target_name => $hook_args{target_name}, |
151
|
|
|
|
|
|
|
per_target_conf => $hook_args{per_target_conf}, |
152
|
36
|
|
|
|
|
85
|
); |
153
|
36
|
50
|
|
|
|
75
|
my $lres = $lhooks->{create_layouter}->[2]->( |
154
|
|
|
|
|
|
|
@lhook_args) or die "Hook from layout module ". |
155
|
|
|
|
|
|
|
"$lmod does not produce layout routine"; |
156
|
36
|
50
|
|
|
|
315
|
ref $lres->[0] eq 'CODE' |
157
|
|
|
|
|
|
|
or die "Layouter from layout module $lmod ". |
158
|
|
|
|
|
|
|
"is not a coderef"; |
159
|
36
|
|
|
|
|
150
|
push @$layouters, $lres->[0]; |
160
|
|
|
|
|
|
|
} else { |
161
|
792
|
|
|
|
|
2434
|
push @$layouters, undef; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
468
|
50
|
|
|
|
883
|
unless (@$outputters) { |
165
|
0
|
|
|
|
|
0
|
$Log::ger::_outputter_is_null = 1; |
166
|
0
|
|
|
|
|
0
|
return [sub {0}]; |
|
0
|
|
|
|
|
0
|
|
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# put the data that are mentioned in string-eval'ed code in a |
170
|
|
|
|
|
|
|
# package so they are addressable |
171
|
468
|
|
|
|
|
527
|
my $varname = do { |
172
|
468
|
|
|
|
|
576
|
my $suffix; |
173
|
468
|
50
|
|
|
|
900
|
if ($hook_args{target_type} eq 'package') { |
174
|
468
|
|
|
|
|
672
|
$suffix = $hook_args{target_name}; |
175
|
|
|
|
|
|
|
} else { |
176
|
0
|
|
|
|
|
0
|
($suffix) = "$hook_args{target_name}" =~ /\(0x(\w+)/; |
177
|
|
|
|
|
|
|
} |
178
|
468
|
|
|
|
|
812
|
"Log::ger::Stash::OComposite_$suffix"; |
179
|
|
|
|
|
|
|
}; |
180
|
|
|
|
|
|
|
{ |
181
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
754
|
|
|
468
|
|
|
|
|
545
|
|
182
|
468
|
|
|
|
|
651
|
${$varname} = []; |
|
468
|
|
|
|
|
4188
|
|
183
|
468
|
|
|
|
|
762
|
${$varname}->[0] = $outputters; |
|
468
|
|
|
|
|
1116
|
|
184
|
468
|
|
|
|
|
631
|
${$varname}->[1] = $layouters; |
|
468
|
|
|
|
|
858
|
|
185
|
468
|
|
|
|
|
596
|
${$varname}->[2] = $hook_args{per_target_conf}; |
|
468
|
|
|
|
|
853
|
|
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# generate our outputter routine |
189
|
468
|
|
|
|
|
596
|
my $composite_outputter; |
190
|
|
|
|
|
|
|
{ |
191
|
468
|
|
|
|
|
497
|
my @src; |
|
468
|
|
|
|
|
586
|
|
192
|
468
|
|
|
|
|
609
|
push @src, "sub {\n"; |
193
|
468
|
|
|
|
|
874
|
push @src, " my (\$per_target_conf, \$fmsg, \$per_msg_conf) = \@_;\n"; |
194
|
468
|
50
|
|
|
|
1392
|
push @src, " my \$lvl; if (\$per_msg_conf) { \$lvl = \$per_msg_conf->{level} }", (defined $hook_args{level} ? " if (!defined \$lvl) { \$lvl = $hook_args{level} }" : ""), "\n"; |
195
|
468
|
|
|
|
|
691
|
push @src, " if (!\$per_msg_conf) { \$per_msg_conf = {level=>\$lvl} }\n"; # since we want to pass level etc to other outputs |
196
|
|
|
|
|
|
|
|
197
|
468
|
|
|
|
|
1022
|
for my $i (0..$#ospecs) { |
198
|
828
|
|
|
|
|
1124
|
my $ospec = $ospecs[$i]; |
199
|
828
|
|
|
|
|
1692
|
push @src, " # output #$i: $ospec->{_name}\n"; |
200
|
828
|
|
|
|
|
1087
|
push @src, " {\n"; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# filter by output's category_level and category-level |
203
|
828
|
100
|
100
|
|
|
2151
|
if ($ospec->{category_level} || $plugin_conf{category_level}) { |
204
|
252
|
|
|
|
|
343
|
push @src, " my \$cat = (\$per_msg_conf ? \$per_msg_conf->{category} : undef) || \$per_target_conf->{category} || '';\n"; |
205
|
252
|
|
|
|
|
329
|
push @src, " local \$per_msg_conf->{category} = \$cat;\n"; |
206
|
|
|
|
|
|
|
|
207
|
252
|
|
|
|
|
293
|
my @cats; |
208
|
252
|
100
|
|
|
|
486
|
if ($ospec->{category_level}) { |
209
|
180
|
|
|
|
|
219
|
for my $cat (keys %{$ospec->{category_level}}) { |
|
180
|
|
|
|
|
472
|
|
210
|
612
|
|
|
|
|
838
|
my $clevel = $ospec->{category_level}{$cat}; |
211
|
612
|
|
|
|
|
1092
|
push @cats, [$cat, 1, $clevel]; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
} |
214
|
252
|
100
|
|
|
|
502
|
if ($plugin_conf{category_level}) { |
215
|
144
|
|
|
|
|
168
|
for my $cat (keys %{$plugin_conf{category_level}}) { |
|
144
|
|
|
|
|
342
|
|
216
|
720
|
|
|
|
|
934
|
my $clevel = $plugin_conf{category_level}{$cat}; |
217
|
720
|
|
|
|
|
1163
|
push @cats, [$cat, 2, $clevel]; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
252
|
|
|
|
|
615
|
for my $cat (sort { |
222
|
2268
|
50
|
100
|
|
|
5287
|
length($b->[0]) <=> length($a->[0]) || |
223
|
|
|
|
|
|
|
$a->[0] cmp $b->[0] || |
224
|
|
|
|
|
|
|
$a->[1] <=> $b->[1]} @cats) { |
225
|
1332
|
|
|
|
|
2487
|
push @src, " if (\$cat eq ".Data::Dmp::dmp($cat->[0])." || index(\$cat, ".Data::Dmp::dmp("$cat->[0]\::").") == 0) { "; |
226
|
1332
|
|
|
|
|
56579
|
my ($min_level, $max_level) = |
227
|
|
|
|
|
|
|
_get_min_max_level($cat->[2]); |
228
|
1332
|
|
|
|
|
3080
|
push @src, "if (\$lvl >= $min_level && ". |
229
|
|
|
|
|
|
|
"\$lvl <= $max_level) { goto LOG } else { last }"; |
230
|
1332
|
|
|
|
|
2096
|
push @src, " }\n"; |
231
|
|
|
|
|
|
|
} |
232
|
252
|
|
|
|
|
639
|
push @src, "\n"; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# filter by output level |
236
|
|
|
|
|
|
|
my ($min_level, $max_level) = _get_min_max_level( |
237
|
828
|
|
|
|
|
1722
|
$ospec->{level}); |
238
|
828
|
100
|
|
|
|
1679
|
if (defined $min_level) { |
239
|
288
|
|
|
|
|
657
|
push @src, " if (\$lvl >= $min_level && ". |
240
|
|
|
|
|
|
|
"\$lvl <= $max_level) { goto LOG } else { last }\n"; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# filter by general level |
244
|
828
|
|
|
|
|
1130
|
push @src, " if (\$Log::ger::Current_Level >= \$lvl) { goto LOG } else { last }\n"; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# run output's log routine |
247
|
828
|
|
|
|
|
971
|
push @src, " LOG:\n"; |
248
|
828
|
|
|
|
|
1546
|
push @src, " if (\$$varname\->[1][$i]) {\n"; |
249
|
828
|
|
|
|
|
2043
|
push @src, " \$$varname\->[0][$i]->(\$per_target_conf, \$$varname\->[1][$i]->(\$fmsg, \$$varname\->[2], \$lvl, Log::ger::Util::string_level(\$lvl)), \$per_msg_conf);\n"; |
250
|
828
|
|
|
|
|
1020
|
push @src, " } else {\n"; |
251
|
828
|
|
|
|
|
1383
|
push @src, " \$$varname\->[0][$i]->(\$per_target_conf, \$fmsg, \$per_msg_conf);\n"; |
252
|
828
|
|
|
|
|
1002
|
push @src, " }\n"; |
253
|
828
|
|
|
|
|
986
|
push @src, " }\n"; |
254
|
828
|
|
|
|
|
1561
|
push @src, " # end output #$i\n\n"; |
255
|
|
|
|
|
|
|
} # for ospec |
256
|
|
|
|
|
|
|
|
257
|
468
|
|
|
|
|
699
|
push @src, "};\n"; |
258
|
468
|
|
|
|
|
2149
|
my $src = join("", @src); |
259
|
468
|
50
|
|
|
|
1009
|
if ($ENV{LOG_LOG_GER_OUTPUT_COMPOSITE_CODE}) { |
260
|
0
|
|
|
|
|
0
|
warn "Log::ger::Output::Composite logger source code (target type=$hook_args{target_type} target name=$hook_args{target_name}, routine name=$hook_args{routine_name}): <<$src>>\n"; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
468
|
|
|
|
|
125381
|
$composite_outputter = eval $src; |
264
|
|
|
|
|
|
|
} |
265
|
468
|
|
|
|
|
2188
|
[$composite_outputter]; |
266
|
7
|
|
|
|
|
134
|
}] # hook record |
267
|
|
|
|
|
|
|
}; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub set_level { |
271
|
0
|
|
|
0
|
1
|
|
$Current_Level = Log::ger::Util::numeric_level(shift); |
272
|
0
|
|
|
|
|
|
Log::ger::Util::reinit_all_targets(); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
1; |
276
|
|
|
|
|
|
|
# ABSTRACT: Composite output |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
__END__ |