| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Log::Message::JSON - structured messages that stringify to JSON |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package My::Application::Module; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Log::Log4perl; |
|
12
|
|
|
|
|
|
|
use Log::Message::JSON qw{logmsg}; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub do_something { |
|
15
|
|
|
|
|
|
|
my ($self, $foo, $bar, @rest) = @_; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $logger = Log::Log4perl->get_logger(); |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$logger->info(logmsg message => "do_something entered", |
|
20
|
|
|
|
|
|
|
foo => $foo, bar => $bar, rest => \@rest); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# ... |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# in flat-file logs entry would look like: |
|
26
|
|
|
|
|
|
|
# Dec 28 00:24:52 example.net My-Application[1587]: {"message":"do_something entered","foo":"value of foo","bar":"value of bar","rest":["value","of","rest"]} |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Good logging requires today a lot more than in Good Ol' Times[tm]. Each log |
|
31
|
|
|
|
|
|
|
entry should have a structure and be machine-parseable. On the other hand, |
|
32
|
|
|
|
|
|
|
there are lot of logging libraries that don't quite support structured logs |
|
33
|
|
|
|
|
|
|
and only process flat strings. |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
L architecture allows both, flat strings and structured |
|
36
|
|
|
|
|
|
|
entries. It's up to appender module whether it accepts one or another form. |
|
37
|
|
|
|
|
|
|
Unfortunately, this makes application developer to decide in advance, which |
|
38
|
|
|
|
|
|
|
appenders could be in use and defeats much of Log::Log4perl's flexibility. |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Log::Message::JSON is an attempt to solve this problem. Developer can create |
|
41
|
|
|
|
|
|
|
a message that has an internal structure (i.e. is a hash(ref)), and at the |
|
42
|
|
|
|
|
|
|
same time it can be used as a simple string, instantly serializing to |
|
43
|
|
|
|
|
|
|
single-line JSON. This way the developer don't need to decide on appenders in |
|
44
|
|
|
|
|
|
|
advance. Moreover, flat string logfiles are easier to parse, especially if |
|
45
|
|
|
|
|
|
|
entries have this form. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Of course, you don't need Log::Log4perl to use this module. It could be used |
|
48
|
|
|
|
|
|
|
wherever a hashref needs to be sensibly stringified while preserving its all |
|
49
|
|
|
|
|
|
|
hash-like features. |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=cut |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
package Log::Message::JSON; |
|
56
|
|
|
|
|
|
|
|
|
57
|
7
|
|
|
7
|
|
308932
|
use warnings; |
|
|
7
|
|
|
|
|
17
|
|
|
|
7
|
|
|
|
|
268
|
|
|
58
|
7
|
|
|
7
|
|
357
|
use strict; |
|
|
7
|
|
|
|
|
16
|
|
|
|
7
|
|
|
|
|
384
|
|
|
59
|
|
|
|
|
|
|
|
|
60
|
7
|
|
|
7
|
|
42
|
use base qw{Exporter}; |
|
|
7
|
|
|
|
|
17
|
|
|
|
7
|
|
|
|
|
1302
|
|
|
61
|
|
|
|
|
|
|
our @EXPORT_OK = qw{&logmsg &logmess &msg &json}; |
|
62
|
|
|
|
|
|
|
|
|
63
|
7
|
|
|
7
|
|
18799
|
use overload ('""' => \&to_json); |
|
|
7
|
|
|
|
|
9889
|
|
|
|
7
|
|
|
|
|
67
|
|
|
64
|
|
|
|
|
|
|
|
|
65
|
7
|
|
|
7
|
|
7021
|
use Log::Message::JSON::Hash; |
|
|
7
|
|
|
|
|
27
|
|
|
|
7
|
|
|
|
|
306
|
|
|
66
|
7
|
|
|
7
|
|
52
|
use Carp; |
|
|
7
|
|
|
|
|
16
|
|
|
|
7
|
|
|
|
|
8240
|
|
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
our $VERSION = '0.30.01'; |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 API |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
The preferred way is the short way. Object-oriented API is described here |
|
77
|
|
|
|
|
|
|
mainly for reference. |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 Short Way |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=over |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=cut |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item C |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item C |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=item C |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item C |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
These are plain functions. They all are exported (but none by default, you |
|
96
|
|
|
|
|
|
|
need to specifically ask for them), they all do the same and they all accept |
|
97
|
|
|
|
|
|
|
the same arguments. They are provided for your convenience. Choose the one |
|
98
|
|
|
|
|
|
|
that don't clash with your methods (but please, make your life easier in |
|
99
|
|
|
|
|
|
|
future and choose one for whole application). |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
These functions accept either a reference to a hash or a list of |
|
102
|
|
|
|
|
|
|
C<< key => value >> pairs. The latter form preserves keys order, so I believe |
|
103
|
|
|
|
|
|
|
it's more useful. Also, in the latter form you may skip the first key name; |
|
104
|
|
|
|
|
|
|
the value will be stored under C key in such case. |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Returned value is an object created with C method (see |
|
107
|
|
|
|
|
|
|
L"Object-Oriented API">), so it's a reference to a hash (blessed, but still |
|
108
|
|
|
|
|
|
|
hashref, with all its consequences). |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Usage example: |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
use Log::Message::JSON qw{logmsg}; |
|
113
|
|
|
|
|
|
|
use Log::Log4perl; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my $msg1 = logmsg { key1 => 1, key2 => 2 }; |
|
116
|
|
|
|
|
|
|
my $msg2 = logmsg foo => 1, bar => 2, text => "some text"; |
|
117
|
|
|
|
|
|
|
my $msg3 = logmsg "my log message", host => hostname(); |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
my $logger = Log::Log4perl->get_logger(); |
|
120
|
|
|
|
|
|
|
$logger->info($msg1); |
|
121
|
|
|
|
|
|
|
$logger->debug($msg2); |
|
122
|
|
|
|
|
|
|
$logger->warn($msg3); |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
print $msg1; |
|
125
|
|
|
|
|
|
|
printf "%s => %s\n", $_, $msg2->{$_} for keys %$msg2; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=cut |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub json { |
|
130
|
1
|
|
|
1
|
1
|
1017
|
return __PACKAGE__->new(@_); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub logmsg { |
|
134
|
1
|
|
|
1
|
1
|
643
|
return __PACKAGE__->new(@_); |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub logmess { |
|
138
|
1
|
|
|
1
|
1
|
660
|
return __PACKAGE__->new(@_); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub msg { |
|
142
|
3
|
|
|
3
|
1
|
1480
|
return __PACKAGE__->new(@_); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=back |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=cut |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head2 Object-Oriented API |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=over |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=cut |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item C<< new(key => value, ...) >> |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item C<< new({ key => value, ... }) >> |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Constructor. |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
This method creates a new hash reference. The underlying hash is tied to |
|
166
|
|
|
|
|
|
|
L (actually, to a proxy class that uses L as |
|
167
|
|
|
|
|
|
|
a backend) and filled with arguments. Because of overloaded stringification |
|
168
|
|
|
|
|
|
|
operator, reference is blessed with Log::Message::JSON package. |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
If the first call form (list of pairs) was used, the order of key/value pairs |
|
171
|
|
|
|
|
|
|
is preserved. If the number of elements is odd, the first element is believed |
|
172
|
|
|
|
|
|
|
to be value of C key. |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
If the second call form (hashref) was used, key/value pairs are sorted using |
|
175
|
|
|
|
|
|
|
C operator, unless the referred hash was tied to L. |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=cut |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub new { |
|
180
|
6
|
|
|
6
|
1
|
23
|
my ($class, @args) = @_; |
|
181
|
|
|
|
|
|
|
|
|
182
|
6
|
|
|
|
|
46
|
tie my %self, 'Log::Message::JSON::Hash'; |
|
183
|
|
|
|
|
|
|
|
|
184
|
6
|
50
|
33
|
|
|
40
|
if (@args == 1 && (ref $args[0] eq 'HASH' || eval {$args[0]->isa('HASH')})) { |
|
|
|
|
66
|
|
|
|
|
|
185
|
0
|
0
|
|
|
|
0
|
if (eval { tied(%{ $args[0] })->isa("Tie::IxHash") }) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
186
|
|
|
|
|
|
|
# no sort, hash probably tied to Tie::IxHash or something |
|
187
|
0
|
|
|
|
|
0
|
%self = %{ $args[0] }; |
|
|
0
|
|
|
|
|
0
|
|
|
188
|
|
|
|
|
|
|
} else { |
|
189
|
|
|
|
|
|
|
# sort keys from the hash |
|
190
|
0
|
|
|
|
|
0
|
%self = map { $_ => $args[0]{$_} } sort keys %{ $args[0] }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} else { |
|
193
|
|
|
|
|
|
|
# keep the order |
|
194
|
6
|
100
|
|
|
|
20
|
if (@args % 2 == 1) { |
|
195
|
1
|
|
|
|
|
5
|
%self = ("message", @args); |
|
196
|
|
|
|
|
|
|
} else { |
|
197
|
5
|
|
|
|
|
29
|
%self = @args; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
6
|
|
|
|
|
123
|
return bless \%self, $class; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
205
|
|
|
|
|
|
|
# |
|
206
|
|
|
|
|
|
|
# auxiliary functions |
|
207
|
|
|
|
|
|
|
# |
|
208
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=begin Test::Pod::Coverage |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=item C |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Helper function for quoting strings in JSON. |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=end Test::Pod::Coverage |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=cut |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub quote($) { |
|
221
|
9
|
|
|
9
|
1
|
12
|
my ($str) = @_; |
|
222
|
|
|
|
|
|
|
|
|
223
|
9
|
|
|
|
|
42
|
my %q = ( |
|
224
|
|
|
|
|
|
|
"\\" => "\\\\", |
|
225
|
|
|
|
|
|
|
'"' => '\"', |
|
226
|
|
|
|
|
|
|
"\n" => "\\n", |
|
227
|
|
|
|
|
|
|
"\r" => "\\r", |
|
228
|
|
|
|
|
|
|
"\t" => "\\t", |
|
229
|
|
|
|
|
|
|
); |
|
230
|
9
|
|
|
|
|
15
|
$str =~ s/([\\"\n\r\t])/$q{$1}/g; |
|
231
|
|
|
|
|
|
|
|
|
232
|
9
|
|
|
|
|
64
|
return $str; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=item C |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
JSON encoding method. This method returns a JSON string that contains no tabs |
|
238
|
|
|
|
|
|
|
nor newlines. Just a single line of text. |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=cut |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# This is my own JSON encoder. This serves as two purposes: first, it relaxes |
|
243
|
|
|
|
|
|
|
# dependencies on external modules; second, it detects object of class |
|
244
|
|
|
|
|
|
|
# Log::Message::JSON (at root level, possibly) to preserve keys order when |
|
245
|
|
|
|
|
|
|
# JSON-infying. |
|
246
|
|
|
|
|
|
|
sub to_json($) { |
|
247
|
12
|
|
|
12
|
1
|
158
|
my ($value) = @_; |
|
248
|
|
|
|
|
|
|
|
|
249
|
12
|
100
|
|
|
|
99
|
if (ref $value eq __PACKAGE__) { # plain hash, tied |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
250
|
1
|
|
|
|
|
2
|
my $tied = tied %$value; |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# store cache for this object if there was no cache for it |
|
253
|
1
|
50
|
|
|
|
5
|
if (not defined $tied->cache) { |
|
254
|
4
|
|
|
|
|
93
|
my @pairs = map { |
|
255
|
1
|
|
|
|
|
6
|
sprintf '%s:%s', to_json($_), to_json($value->{$_}) |
|
256
|
|
|
|
|
|
|
} keys %$value; |
|
257
|
1
|
|
|
|
|
8
|
$tied->cache(sprintf "{%s}", join ",", @pairs); |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
1
|
|
|
|
|
3
|
return $tied->cache; |
|
261
|
|
|
|
|
|
|
} elsif (ref $value eq "HASH") { # plain hash |
|
262
|
1
|
|
|
|
|
3
|
my @pairs = map { |
|
263
|
1
|
|
|
|
|
5
|
sprintf '%s:%s', to_json($_), to_json($value->{$_}) |
|
264
|
|
|
|
|
|
|
} sort keys %$value; |
|
265
|
1
|
|
|
|
|
7
|
return sprintf "{%s}", join ",", @pairs; |
|
266
|
|
|
|
|
|
|
} elsif (ref $value eq "ARRAY") { # plain array |
|
267
|
1
|
|
|
|
|
3
|
my @elems = map { to_json($_) } @$value; |
|
|
1
|
|
|
|
|
5
|
|
|
268
|
1
|
|
|
|
|
7
|
return sprintf "[%s]", join ",", @elems; |
|
269
|
|
|
|
|
|
|
} elsif (ref $value eq "SCALAR") { # plain scalar (reference) |
|
270
|
0
|
|
|
|
|
0
|
return sprintf '"%s"', quote($$value); |
|
271
|
|
|
|
|
|
|
} elsif (not defined $value) { # undef (null) |
|
272
|
0
|
|
|
|
|
0
|
return 'null'; |
|
273
|
|
|
|
|
|
|
} elsif (not ref $value) { # plain scalar |
|
274
|
9
|
|
|
|
|
18
|
return sprintf '"%s"', quote($value); |
|
275
|
|
|
|
|
|
|
} else { # compound object |
|
276
|
|
|
|
|
|
|
# TODO |
|
277
|
0
|
|
|
|
|
|
croak "Type @{[ref $value]} unsupported yet\n"; |
|
|
0
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=back |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=cut |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head1 C NOTES |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
To use Log::Message::JSON as a reason for C, you need to assign it to |
|
290
|
|
|
|
|
|
|
C<$@> variable and call C without arguments (works for Perl 5.8+). |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
unless (open my $f, "<", $file) { |
|
293
|
|
|
|
|
|
|
$@ = msg "error opening file", |
|
294
|
|
|
|
|
|
|
filename => $file, |
|
295
|
|
|
|
|
|
|
error => "$!", errno => $! + 0; |
|
296
|
|
|
|
|
|
|
die; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Of course just calling C will work as well, but it will result |
|
300
|
|
|
|
|
|
|
in a message without end-of-line character. |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=begin Test::Pod::Coverage |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=item C |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
B: C |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=end Test::Pod::Coverage |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub PROPAGATE { |
|
314
|
0
|
|
|
0
|
1
|
|
my ($self, $file, $line) = @_; |
|
315
|
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
return sprintf "died at %s line %d, %s\n", $file, $line, $self; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=head1 C NOTES |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
You might be tempted to use custom I to stringify the |
|
324
|
|
|
|
|
|
|
message. It would look like this: |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
my $logger = Log::Log4perl->get_logger(); |
|
327
|
|
|
|
|
|
|
$logger->info({ filter => \&dumper, value => $mydata }); |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
This won't work too well: the filter gets called before appender module, so |
|
330
|
|
|
|
|
|
|
the appender gets a string instead of a structured message. The better way |
|
331
|
|
|
|
|
|
|
would be: |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
my $logger = Log::Log4perl->get_logger(); |
|
334
|
|
|
|
|
|
|
$logger->info(logmsg $mydata); |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Log::Log4perl only processes C and C when the object is |
|
337
|
|
|
|
|
|
|
a plain, unblessed hash, so you may safely use these two key names. |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=head1 AUTHOR |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Stanislaw Klekot, C<< >> |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Copyright 2012 Stanislaw Klekot. |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
352
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
|
353
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
L, L, |
|
360
|
|
|
|
|
|
|
L, L, |
|
361
|
|
|
|
|
|
|
L. |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=cut |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
366
|
|
|
|
|
|
|
1; |
|
367
|
|
|
|
|
|
|
# vim:ft=perl |