1FAQ(3) User Contributed Perl Documentation FAQ(3)
2
3
4
6 Log::Log4perl::FAQ - Frequently Asked Questions on Log::Log4perl
7
9 This FAQ shows a wide variety of commonly encountered logging tasks and
10 how to solve them in the most elegant way with Log::Log4perl. Most of
11 the time, this will be just a matter of smartly configuring your
12 Log::Log4perl configuration files.
13
14 Why use Log::Log4perl instead of any other logging module on CPAN?
15 That's a good question. There's dozens of logging modules on CPAN.
16 When it comes to logging, people typically think: "Aha. Writing out
17 debug and error messages. Debug is lower than error. Easy. I'm gonna
18 write my own." Writing a logging module is like a rite of passage for
19 every Perl programmer, just like writing your own templating system.
20
21 Of course, after getting the basics right, features need to be added.
22 You'd like to write a timestamp with every message. Then timestamps
23 with microseconds. Then messages need to be written to both the screen
24 and a log file.
25
26 And, as your application grows in size you might wonder: Why doesn't my
27 logging system scale along with it? You would like to switch on logging
28 in selected parts of the application, and not all across the board,
29 because this kills performance. This is when people turn to
30 Log::Log4perl, because it handles all of that.
31
32 Avoid this costly switch.
33
34 Use "Log::Log4perl" right from the start. "Log::Log4perl"'s ":easy"
35 mode supports easy logging in simple scripts:
36
37 use Log::Log4perl qw(:easy);
38 Log::Log4perl->easy_init($DEBUG);
39
40 DEBUG "A low-level message";
41 ERROR "Won't make it until level gets increased to ERROR";
42
43 And when your application inevitably grows, your logging system grows
44 with it without you having to change any code.
45
46 Please, don't re-invent logging. "Log::Log4perl" is here, it's easy to
47 use, it scales, and covers many areas you haven't thought of yet, but
48 will enter soon.
49
50 What's the easiest way to use Log4perl?
51 If you just want to get all the comfort of logging, without much
52 overhead, use Stealth Loggers. If you use Log::Log4perl in ":easy" mode
53 like
54
55 use Log::Log4perl qw(:easy);
56
57 you'll have the following functions available in the current package:
58
59 DEBUG("message");
60 INFO("message");
61 WARN("message");
62 ERROR("message");
63 FATAL("message");
64
65 Just make sure that every package of your code where you're using them
66 in pulls in "use Log::Log4perl qw(:easy)" first, then you're set.
67 Every stealth logger's category will be equivalent to the name of the
68 package it's located in.
69
70 These stealth loggers will be absolutely silent until you initialize
71 Log::Log4perl in your main program with either
72
73 # Define any Log4perl behavior
74 Log::Log4perl->init("foo.conf");
75
76 (using a full-blown Log4perl config file) or the super-easy method
77
78 # Just log to STDERR
79 Log::Log4perl->easy_init($DEBUG);
80
81 or the parameter-style method with a complexity somewhat in between:
82
83 # Append to a log file
84 Log::Log4perl->easy_init( { level => $DEBUG,
85 file => ">>test.log" } );
86
87 For more info, please check out "Stealth Loggers" in Log::Log4perl.
88
89 How can I simply log all my ERROR messages to a file?
90 After pulling in the "Log::Log4perl" module, just initialize its
91 behavior by passing in a configuration to its "init" method as a string
92 reference. Then, obtain a logger instance and write out a message with
93 its error() method:
94
95 use Log::Log4perl qw(get_logger);
96
97 # Define configuration
98 my $conf = q(
99 log4perl.logger = ERROR, FileApp
100 log4perl.appender.FileApp = Log::Log4perl::Appender::File
101 log4perl.appender.FileApp.filename = test.log
102 log4perl.appender.FileApp.layout = PatternLayout
103 log4perl.appender.FileApp.layout.ConversionPattern = %d> %m%n
104 );
105
106 # Initialize logging behavior
107 Log::Log4perl->init( \$conf );
108
109 # Obtain a logger instance
110 my $logger = get_logger("Bar::Twix");
111 $logger->error("Oh my, a dreadful error!");
112 $logger->warn("Oh my, a dreadful warning!");
113
114 This will append something like
115
116 2002/10/29 20:11:55> Oh my, a dreadful error!
117
118 to the log file "test.log". How does this all work?
119
120 While the Log::Log4perl init() method typically takes the name of a
121 configuration file as its input parameter like in
122
123 Log::Log4perl->init( "/path/mylog.conf" );
124
125 the example above shows how to pass in a configuration as text in a
126 scalar reference.
127
128 The configuration as shown defines a logger of the root category, which
129 has an appender of type "Log::Log4perl::Appender::File" attached. The
130 line
131
132 log4perl.logger = ERROR, FileApp
133
134 doesn't list a category, defining a root logger. Compare that with
135
136 log4perl.logger.Bar.Twix = ERROR, FileApp
137
138 which would define a logger for the category "Bar::Twix", showing
139 probably different behavior. "FileApp" on the right side of the
140 assignment is an arbitrarily defined variable name, which is only used
141 to somehow reference an appender defined later on.
142
143 Appender settings in the configuration are defined as follows:
144
145 log4perl.appender.FileApp = Log::Log4perl::Appender::File
146 log4perl.appender.FileApp.filename = test.log
147
148 It selects the file appender of the "Log::Log4perl::Appender"
149 hierarchy, which will append to the file "test.log" if it already
150 exists. If we wanted to overwrite a potentially existing file, we would
151 have to explicitly set the appropriate "Log::Log4perl::Appender::File"
152 parameter "mode":
153
154 log4perl.appender.FileApp = Log::Log4perl::Appender::File
155 log4perl.appender.FileApp.filename = test.log
156 log4perl.appender.FileApp.mode = write
157
158 Also, the configuration defines a PatternLayout format, adding the
159 nicely formatted current date and time, an arrow (>) and a space before
160 the messages, which is then followed by a newline:
161
162 log4perl.appender.FileApp.layout = PatternLayout
163 log4perl.appender.FileApp.layout.ConversionPattern = %d> %m%n
164
165 Obtaining a logger instance and actually logging something is typically
166 done in a different system part as the Log::Log4perl initialisation
167 section, but in this example, it's just done right after init for the
168 sake of compactness:
169
170 # Obtain a logger instance
171 my $logger = get_logger("Bar::Twix");
172 $logger->error("Oh my, a dreadful error!");
173
174 This retrieves an instance of the logger of the category "Bar::Twix",
175 which, as all other categories, inherits behavior from the root logger
176 if no other loggers are defined in the initialization section.
177
178 The error() method fires up a message, which the root logger catches.
179 Its priority is equal to or higher than the root logger's priority
180 (ERROR), which causes the root logger to forward it to its attached
181 appender. By contrast, the following
182
183 $logger->warn("Oh my, a dreadful warning!");
184
185 doesn't make it through, because the root logger sports a higher
186 setting (ERROR and up) than the WARN priority of the message.
187
188 How can I install Log::Log4perl on Microsoft Windows?
189 You can install Log::Log4perl using the CPAN client.
190
191 Alternatively you can install it using
192
193 ppm install Log-Log4perl
194
195 if you're using ActiveState perl.
196
197 That's it! Afterwards, just create a Perl script like
198
199 use Log::Log4perl qw(:easy);
200 Log::Log4perl->easy_init($DEBUG);
201
202 my $logger = get_logger("Twix::Bar");
203 $logger->debug("Watch me!");
204
205 and run it. It should print something like
206
207 2002/11/06 01:22:05 Watch me!
208
209 If you find that something doesn't work, please let us know at
210 log4perl-devel@lists.sourceforge.net -- we'll appreciate it. Have fun!
211
212 How can I include global (thread-specific) data in my log messages?
213 Say, you're writing a web application and want all your log messages to
214 include the current client's IP address. Most certainly, you don't want
215 to include it in each and every log message like in
216
217 $logger->debug( $r->connection->remote_ip,
218 " Retrieving user data from DB" );
219
220 do you? Instead, you want to set it in a global data structure and have
221 Log::Log4perl include it automatically via a PatternLayout setting in
222 the configuration file:
223
224 log4perl.appender.FileApp.layout.ConversionPattern = %X{ip} %m%n
225
226 The conversion specifier %X{ip} references an entry under the key "ip"
227 in the global "MDC" (mapped diagnostic context) table, which you've set
228 once via
229
230 Log::Log4perl::MDC->put("ip", $r->connection->remote_ip);
231
232 at the start of the request handler. Note that this is a static (class)
233 method, there's no logger object involved. You can use this method
234 with as many key/value pairs as you like as long as you reference them
235 under different names.
236
237 The mappings are stored in a global hash table within Log::Log4perl.
238 Luckily, because the thread model in 5.8.0 doesn't share global
239 variables between threads unless they're explicitly marked as such,
240 there's no problem with multi-threaded environments.
241
242 For more details on the MDC, please refer to "Mapped Diagnostic Context
243 (MDC)" in Log::Log4perl and Log::Log4perl::MDC.
244
245 My application is already logging to a file. How can I duplicate all
246 messages to also go to the screen?
247 Assuming that you already have a Log4perl configuration file like
248
249 log4perl.logger = DEBUG, FileApp
250
251 log4perl.appender.FileApp = Log::Log4perl::Appender::File
252 log4perl.appender.FileApp.filename = test.log
253 log4perl.appender.FileApp.layout = PatternLayout
254 log4perl.appender.FileApp.layout.ConversionPattern = %d> %m%n
255
256 and log statements all over your code, it's very easy with Log4perl to
257 have the same messages both printed to the logfile and the screen. No
258 reason to change your code, of course, just add another appender to the
259 configuration file and you're done:
260
261 log4perl.logger = DEBUG, FileApp, ScreenApp
262
263 log4perl.appender.FileApp = Log::Log4perl::Appender::File
264 log4perl.appender.FileApp.filename = test.log
265 log4perl.appender.FileApp.layout = PatternLayout
266 log4perl.appender.FileApp.layout.ConversionPattern = %d> %m%n
267
268 log4perl.appender.ScreenApp = Log::Log4perl::Appender::Screen
269 log4perl.appender.ScreenApp.stderr = 0
270 log4perl.appender.ScreenApp.layout = PatternLayout
271 log4perl.appender.ScreenApp.layout.ConversionPattern = %d> %m%n
272
273 The configuration file above is assuming that both appenders are active
274 in the same logger hierarchy, in this case the "root" category. But
275 even if you've got file loggers defined in several parts of your
276 system, belonging to different logger categories, each logging to
277 different files, you can gobble up all logged messages by defining a
278 root logger with a screen appender, which would duplicate messages from
279 all your file loggers to the screen due to Log4perl's appender
280 inheritance. Check
281
282 http://www.perl.com/pub/a/2002/09/11/log4perl.html
283
284 for details. Have fun!
285
286 How can I make sure my application logs a message when it dies
287 unexpectedly?
288 Whenever you encounter a fatal error in your application, instead of
289 saying something like
290
291 open FILE, "<blah" or die "Can't open blah -- bailing out!";
292
293 just use Log::Log4perl's fatal functions instead:
294
295 my $log = get_logger("Some::Package");
296 open FILE, "<blah" or $log->logdie("Can't open blah -- bailing out!");
297
298 This will both log the message with priority FATAL according to your
299 current Log::Log4perl configuration and then call Perl's die()
300 afterwards to terminate the program. It works the same with stealth
301 loggers (see "Stealth Loggers" in Log::Log4perl), all you need to do is
302 call
303
304 use Log::Log4perl qw(:easy);
305 open FILE, "<blah" or LOGDIE "Can't open blah -- bailing out!";
306
307 What can you do if you're using some library which doesn't use
308 Log::Log4perl and calls die() internally if something goes wrong? Use a
309 $SIG{__DIE__} pseudo signal handler
310
311 use Log::Log4perl qw(get_logger);
312
313 $SIG{__DIE__} = sub {
314 if($^S) {
315 # We're in an eval {} and don't want log
316 # this message but catch it later
317 return;
318 }
319 local $Log::Log4perl::caller_depth =
320 $Log::Log4perl::caller_depth + 1;
321 my $logger = get_logger("");
322 $logger->fatal(@_);
323 die @_; # Now terminate really
324 };
325
326 This will catch every die()-Exception of your application or the
327 modules it uses. In case you want to It will fetch a root logger and
328 pass on the die()-Message to it. If you make sure you've configured
329 with a root logger like this:
330
331 Log::Log4perl->init(\q{
332 log4perl.category = FATAL, Logfile
333 log4perl.appender.Logfile = Log::Log4perl::Appender::File
334 log4perl.appender.Logfile.filename = fatal_errors.log
335 log4perl.appender.Logfile.layout = \
336 Log::Log4perl::Layout::PatternLayout
337 log4perl.appender.Logfile.layout.ConversionPattern = %F{1}-%L (%M)> %m%n
338 });
339
340 then all die() messages will be routed to a file properly. The line
341
342 local $Log::Log4perl::caller_depth =
343 $Log::Log4perl::caller_depth + 1;
344
345 in the pseudo signal handler above merits a more detailed explanation.
346 With the setup above, if a module calls die() in one of its functions,
347 the fatal message will be logged in the signal handler and not in the
348 original function -- which will cause the %F, %L and %M placeholders in
349 the pattern layout to be replaced by the filename, the line number and
350 the function/method name of the signal handler, not the error-throwing
351 module. To adjust this, Log::Log4perl has the $caller_depth variable,
352 which defaults to 0, but can be set to positive integer values to
353 offset the caller level. Increasing it by one will cause it to log the
354 calling function's parameters, not the ones of the signal handler. See
355 "Using Log::Log4perl from wrapper classes" in Log::Log4perl for more
356 details.
357
358 How can I hook up the LWP library with Log::Log4perl?
359 Or, to put it more generally: How can you utilize a third-party
360 library's embedded logging and debug statements in Log::Log4perl? How
361 can you make them print to configurable appenders, turn them on and
362 off, just as if they were regular Log::Log4perl logging statements?
363
364 The easiest solution is to map the third-party library logging
365 statements to Log::Log4perl's stealth loggers via a typeglob
366 assignment.
367
368 As an example, let's take LWP, one of the most popular Perl modules,
369 which makes handling WWW requests and responses a breeze. Internally,
370 LWP uses its own logging and debugging system, utilizing the following
371 calls inside the LWP code (from the LWP::Debug man page):
372
373 # Function tracing
374 LWP::Debug::trace('send()');
375
376 # High-granular state in functions
377 LWP::Debug::debug('url ok');
378
379 # Data going over the wire
380 LWP::Debug::conns("read $n bytes: $data");
381
382 First, let's assign Log::Log4perl priorities to these functions: I'd
383 suggest that debug() messages have priority "INFO", trace() uses
384 "DEBUG" and conns() also logs with "DEBUG" -- although your mileage may
385 certainly vary.
386
387 Now, in order to transparently hook up LWP::Debug with Log::Log4perl,
388 all we have to do is say
389
390 package LWP::Debug;
391 use Log::Log4perl qw(:easy);
392
393 *trace = *INFO;
394 *conns = *DEBUG;
395 *debug = *DEBUG;
396
397 package main;
398 # ... go on with your regular program ...
399
400 at the beginning of our program. In this way, every time the, say,
401 "LWP::UserAgent" module calls LWP::Debug::trace(), it will implicitly
402 call INFO(), which is the info() method of a stealth logger defined for
403 the Log::Log4perl category "LWP::Debug". Is this cool or what?
404
405 Here's a complete program:
406
407 use LWP::UserAgent;
408 use HTTP::Request::Common;
409 use Log::Log4perl qw(:easy);
410
411 Log::Log4perl->easy_init(
412 { category => "LWP::Debug",
413 level => $DEBUG,
414 layout => "%r %p %M-%L %m%n",
415 });
416
417 package LWP::Debug;
418 use Log::Log4perl qw(:easy);
419 *trace = *INFO;
420 *conns = *DEBUG;
421 *debug = *DEBUG;
422
423 package main;
424 my $ua = LWP::UserAgent->new();
425 my $resp = $ua->request(GET "http://amazon.com");
426
427 if($resp->is_success()) {
428 print "Success: Received ",
429 length($resp->content()), "\n";
430 } else {
431 print "Error: ", $resp->code(), "\n";
432 }
433
434 This will generate the following output on STDERR:
435
436 174 INFO LWP::UserAgent::new-164 ()
437 208 INFO LWP::UserAgent::request-436 ()
438 211 INFO LWP::UserAgent::send_request-294 GET http://amazon.com
439 212 DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
440 405 INFO LWP::Protocol::http::request-122 ()
441 859 DEBUG LWP::Protocol::collect-206 read 233 bytes
442 863 DEBUG LWP::UserAgent::request-443 Simple response: Found
443 869 INFO LWP::UserAgent::request-436 ()
444 871 INFO LWP::UserAgent::send_request-294
445 GET http://www.amazon.com:80/exec/obidos/gateway_redirect
446 872 DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
447 873 INFO LWP::Protocol::http::request-122 ()
448 1016 DEBUG LWP::UserAgent::request-443 Simple response: Found
449 1020 INFO LWP::UserAgent::request-436 ()
450 1022 INFO LWP::UserAgent::send_request-294
451 GET http://www.amazon.com/exec/obidos/subst/home/home.html/
452 1023 DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
453 1024 INFO LWP::Protocol::http::request-122 ()
454 1382 DEBUG LWP::Protocol::collect-206 read 632 bytes
455 ...
456 2605 DEBUG LWP::Protocol::collect-206 read 77 bytes
457 2607 DEBUG LWP::UserAgent::request-443 Simple response: OK
458 Success: Received 42584
459
460 Of course, in this way, the embedded logging and debug statements
461 within LWP can be utilized in any Log::Log4perl way you can think of.
462 You can have them sent to different appenders, block them based on the
463 category and everything else Log::Log4perl has to offer.
464
465 Only drawback of this method: Steering logging behavior via category is
466 always based on the "LWP::Debug" package. Although the logging
467 statements reflect the package name of the issuing module properly, the
468 stealth loggers in "LWP::Debug" are all of the category "LWP::Debug".
469 This implies that you can't control the logging behavior based on the
470 package that's initiating a log request (e.g. LWP::UserAgent) but only
471 based on the package that's actually executing the logging statement,
472 "LWP::Debug" in this case.
473
474 To work around this conundrum, we need to write a wrapper function and
475 plant it into the "LWP::Debug" package. It will determine the caller
476 and create a logger bound to a category with the same name as the
477 caller's package:
478
479 package LWP::Debug;
480
481 use Log::Log4perl qw(:levels get_logger);
482
483 sub l4p_wrapper {
484 my($prio, @message) = @_;
485 $Log::Log4perl::caller_depth += 2;
486 get_logger(scalar caller(1))->log($prio, @message);
487 $Log::Log4perl::caller_depth -= 2;
488 }
489
490 no warnings 'redefine';
491 *trace = sub { l4p_wrapper($INFO, @_); };
492 *debug = *conns = sub { l4p_wrapper($DEBUG, @_); };
493
494 package main;
495 # ... go on with your main program ...
496
497 This is less performant than the previous approach, because every log
498 request will request a reference to a logger first, then call the
499 wrapper, which will in turn call the appropriate log function.
500
501 This hierarchy shift has to be compensated for by increasing
502 $Log::Log4perl::caller_depth by 2 before calling the log function and
503 decreasing it by 2 right afterwards. Also, the "l4p_wrapper" function
504 shown above calls caller(1) which determines the name of the package
505 two levels down the calling hierarchy (and therefore compensates for
506 both the wrapper function and the anonymous subroutine calling it).
507
508 "no warnings 'redefine'" suppresses a warning Perl would generate
509 otherwise upon redefining "LWP::Debug"'s trace(), debug() and conns()
510 functions. In case you use a perl prior to 5.6.x, you need to
511 manipulate $^W instead.
512
513 To make things easy for you when dealing with LWP, Log::Log4perl 0.47
514 introduces "Log::Log4perl->infiltrate_lwp()" which does exactly the
515 above.
516
517 What if I need dynamic values in a static Log4perl configuration file?
518 Say, your application uses Log::Log4perl for logging and therefore
519 comes with a Log4perl configuration file, specifying the logging
520 behavior. But, you also want it to take command line parameters to set
521 values like the name of the log file. How can you have both a static
522 Log4perl configuration file and a dynamic command line interface?
523
524 As of Log::Log4perl 0.28, every value in the configuration file can be
525 specified as a Perl hook. So, instead of saying
526
527 log4perl.appender.Logfile.filename = test.log
528
529 you could just as well have a Perl subroutine deliver the value
530 dynamically:
531
532 log4perl.appender.Logfile.filename = sub { logfile(); };
533
534 given that logfile() is a valid function in your "main" package
535 returning a string containing the path to the log file.
536
537 Or, think about using the value of an environment variable:
538
539 log4perl.appender.DBI.user = sub { $ENV{USERNAME} };
540
541 When "Log::Log4perl->init()" parses the configuration file, it will
542 notice the assignment above because of its "sub {...}" pattern and
543 treat it in a special way: It will evaluate the subroutine (which can
544 contain arbitrary Perl code) and take its return value as the right
545 side of the assignment.
546
547 A typical application would be called like this on the command line:
548
549 app # log file is "test.log"
550 app -l mylog.txt # log file is "mylog.txt"
551
552 Here's some sample code implementing the command line interface above:
553
554 use Log::Log4perl qw(get_logger);
555 use Getopt::Std;
556
557 getopt('l:', \our %OPTS);
558
559 my $conf = q(
560 log4perl.category.Bar.Twix = WARN, Logfile
561 log4perl.appender.Logfile = Log::Log4perl::Appender::File
562 log4perl.appender.Logfile.filename = sub { logfile(); };
563 log4perl.appender.Logfile.layout = SimpleLayout
564 );
565
566 Log::Log4perl::init(\$conf);
567
568 my $logger = get_logger("Bar::Twix");
569 $logger->error("Blah");
570
571 ###########################################
572 sub logfile {
573 ###########################################
574 if(exists $OPTS{l}) {
575 return $OPTS{l};
576 } else {
577 return "test.log";
578 }
579 }
580
581 Every Perl hook may contain arbitrary perl code, just make sure to
582 fully qualify eventual variable names (e.g. %main::OPTS instead of
583 %OPTS).
584
585 SECURITY NOTE: this feature means arbitrary perl code can be embedded
586 in the config file. In the rare case where the people who have access
587 to your config file are different from the people who write your code
588 and shouldn't have execute rights, you might want to call
589
590 $Log::Log4perl::Config->allow_code(0);
591
592 before you call init(). This will prevent Log::Log4perl from executing
593 any Perl code in the config file (including code for custom conversion
594 specifiers (see "Custom cspecs" in
595 Log::Log4perl::Layout::PatternLayout).
596
597 How can I roll over my logfiles automatically at midnight?
598 Long-running applications tend to produce ever-increasing logfiles.
599 For backup and cleanup purposes, however, it is often desirable to move
600 the current logfile to a different location from time to time and start
601 writing a new one.
602
603 This is a non-trivial task, because it has to happen in sync with the
604 logging system in order not to lose any messages in the process.
605
606 Luckily, Mark Pfeiffer's "Log::Dispatch::FileRotate" appender works
607 well with Log::Log4perl to rotate your logfiles in a variety of ways.
608
609 Note, however, that having the application deal with rotating a log
610 file is not cheap. Among other things, it requires locking the log file
611 with every write to avoid race conditions. There are good reasons to
612 use external rotators like "newsyslog" instead. See the entry "How can
613 I rotate a logfile with newsyslog?" in the FAQ for more information on
614 how to configure it.
615
616 When using "Log::Dispatch::FileRotate", all you have to do is specify
617 it in your Log::Log4perl configuration file and your logfiles will be
618 rotated automatically.
619
620 You can choose between rolling based on a maximum size ("roll if
621 greater than 10 MB") or based on a date pattern ("roll everyday at
622 midnight"). In both cases, "Log::Dispatch::FileRotate" allows you to
623 define a number "max" of saved files to keep around until it starts
624 overwriting the oldest ones. If you set the "max" parameter to 2 and
625 the name of your logfile is "test.log", "Log::Dispatch::FileRotate"
626 will move "test.log" to "test.log.1" on the first rollover. On the
627 second rollover, it will move "test.log.1" to "test.log.2" and then
628 "test.log" to "test.log.1". On the third rollover, it will move
629 "test.log.1" to "test.log.2" (therefore discarding the old
630 "test.log.2") and "test.log" to "test.log.1". And so forth. This way,
631 there's always going to be a maximum of 2 saved log files around.
632
633 Here's an example of a Log::Log4perl configuration file, defining a
634 daily rollover at midnight (date pattern "yyyy-MM-dd"), keeping a
635 maximum of 5 saved logfiles around:
636
637 log4perl.category = WARN, Logfile
638 log4perl.appender.Logfile = Log::Dispatch::FileRotate
639 log4perl.appender.Logfile.filename = test.log
640 log4perl.appender.Logfile.max = 5
641 log4perl.appender.Logfile.DatePattern = yyyy-MM-dd
642 log4perl.appender.Logfile.TZ = PST
643 log4perl.appender.Logfile.layout = \
644 Log::Log4perl::Layout::PatternLayout
645 log4perl.appender.Logfile.layout.ConversionPattern = %d %m %n
646
647 Please see the "Log::Dispatch::FileRotate" documentation for details.
648 "Log::Dispatch::FileRotate" is available on CPAN.
649
650 What's the easiest way to turn off all logging, even with a lengthy
651 Log4perl configuration file?
652 In addition to category-based levels and appender thresholds,
653 Log::Log4perl supports system-wide logging thresholds. This is the
654 minimum level the system will require of any logging events in order
655 for them to make it through to any configured appenders.
656
657 For example, putting the line
658
659 log4perl.threshold = ERROR
660
661 anywhere in your configuration file will limit any output to any
662 appender to events with priority of ERROR or higher (ERROR or FATAL
663 that is).
664
665 However, in order to suppress all logging entirely, you need to use a
666 priority that's higher than FATAL: It is simply called "OFF", and it is
667 never used by any logger. By definition, it is higher than the highest
668 defined logger level.
669
670 Therefore, if you keep the line
671
672 log4perl.threshold = OFF
673
674 somewhere in your Log::Log4perl configuration, the system will be quiet
675 as a graveyard. If you deactivate the line (e.g. by commenting it out),
676 the system will, upon config reload, snap back to normal operation,
677 providing logging messages according to the rest of the configuration
678 file again.
679
680 How can I log DEBUG and above to the screen and INFO and above to a file?
681 You need one logger with two appenders attached to it:
682
683 log4perl.logger = DEBUG, Screen, File
684
685 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
686 log4perl.appender.Screen.layout = SimpleLayout
687
688 log4perl.appender.File = Log::Log4perl::Appender::File
689 log4perl.appender.File.filename = test.log
690 log4perl.appender.File.layout = SimpleLayout
691 log4perl.appender.Screen.Threshold = INFO
692
693 Since the file logger isn't supposed to get any messages with a
694 priority less than INFO, the appender's "Threshold" setting blocks
695 those out, although the logger forwards them.
696
697 It's a common mistake to think you can define two loggers for this, but
698 it won't work unless those two loggers have different categories. If
699 you wanted to log all DEBUG and above messages from the Foo::Bar module
700 to a file and all INFO and above messages from the Quack::Schmack
701 module to the screen, then you could have defined two loggers with
702 different levels "log4perl.logger.Foo.Bar" (level INFO) and
703 "log4perl.logger.Quack.Schmack" (level DEBUG) and assigned the file
704 appender to the former and the screen appender to the latter. But what
705 we wanted to accomplish was to route all messages, regardless of which
706 module (or category) they came from, to both appenders. The only way to
707 accomplish this is to define the root logger with the lower level
708 (DEBUG), assign both appenders to it, and block unwanted messages at
709 the file appender ("Threshold" set to INFO).
710
711 I keep getting duplicate log messages! What's wrong?
712 Having several settings for related categories in the Log4perl
713 configuration file sometimes leads to a phenomenon called "message
714 duplication". It can be very confusing at first, but if thought through
715 properly, it turns out that Log4perl behaves as advertised. But, don't
716 despair, of course there's a number of ways to avoid message
717 duplication in your logs.
718
719 Here's a sample Log4perl configuration file that produces the
720 phenomenon:
721
722 log4perl.logger.Cat = ERROR, Screen
723 log4perl.logger.Cat.Subcat = WARN, Screen
724
725 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
726 log4perl.appender.Screen.layout = SimpleLayout
727
728 It defines two loggers, one for category "Cat" and one for
729 "Cat::Subcat", which is obviously a subcategory of "Cat". The parent
730 logger has a priority setting of ERROR, the child is set to the lower
731 "WARN" level.
732
733 Now imagine the following code in your program:
734
735 my $logger = get_logger("Cat.Subcat");
736 $logger->warn("Warning!");
737
738 What do you think will happen? An unexperienced Log4perl user might
739 think: "Well, the message is being sent with level WARN, so the
740 "Cat::Subcat" logger will accept it and forward it to the attached
741 "Screen" appender. Then, the message will percolate up the logger
742 hierarchy, find the "Cat" logger, which will suppress the message
743 because of its ERROR setting." But, perhaps surprisingly, what you'll
744 get with the code snippet above is not one but two log messages written
745 to the screen:
746
747 WARN - Warning!
748 WARN - Warning!
749
750 What happened? The culprit is that once the logger "Cat::Subcat"
751 decides to fire, it will forward the message unconditionally to all
752 directly or indirectly attached appenders. The "Cat" logger will never
753 be asked if it wants the message or not -- the message will just be
754 pushed through to the appender attached to "Cat".
755
756 One way to prevent the message from bubbling up the logger hierarchy is
757 to set the "additivity" flag of the subordinate logger to 0:
758
759 log4perl.logger.Cat = ERROR, Screen
760 log4perl.logger.Cat.Subcat = WARN, Screen
761 log4perl.additivity.Cat.Subcat = 0
762
763 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
764 log4perl.appender.Screen.layout = SimpleLayout
765
766 The message will now be accepted by the "Cat::Subcat" logger, forwarded
767 to its appender, but then "Cat::Subcat" will suppress any further
768 action. While this setting avoids duplicate messages as seen before, it
769 is often not the desired behavior. Messages percolating up the
770 hierarchy are a useful Log4perl feature.
771
772 If you're defining different appenders for the two loggers, one other
773 option is to define an appender threshold for the higher-level
774 appender. Typically it is set to be equal to the logger's level
775 setting:
776
777 log4perl.logger.Cat = ERROR, Screen1
778 log4perl.logger.Cat.Subcat = WARN, Screen2
779
780 log4perl.appender.Screen1 = Log::Log4perl::Appender::Screen
781 log4perl.appender.Screen1.layout = SimpleLayout
782 log4perl.appender.Screen1.Threshold = ERROR
783
784 log4perl.appender.Screen2 = Log::Log4perl::Appender::Screen
785 log4perl.appender.Screen2.layout = SimpleLayout
786
787 Since the "Screen1" appender now blocks every message with a priority
788 less than ERROR, even if the logger in charge lets it through, the
789 message percolating up the hierarchy is being blocked at the last
790 minute and not appended to "Screen1".
791
792 So far, we've been operating well within the boundaries of the Log4j
793 standard, which Log4perl adheres to. However, if you would really,
794 really like to use a single appender and keep the message percolation
795 intact without having to deal with message duplication, there's a non-
796 standard solution for you:
797
798 log4perl.logger.Cat = ERROR, Screen
799 log4perl.logger.Cat.Subcat = WARN, Screen
800
801 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
802 log4perl.appender.Screen.layout = SimpleLayout
803
804 log4perl.oneMessagePerAppender = 1
805
806 The "oneMessagePerAppender" flag will suppress duplicate messages to
807 the same appender. Again, that's non-standard. But way cool :).
808
809 How can I configure Log::Log4perl to send me email if something happens?
810 Some incidents require immediate action. You can't wait until someone
811 checks the log files, you need to get notified on your pager right
812 away.
813
814 The easiest way to do that is by using the
815 "Log::Dispatch::Email::MailSend" module as an appender. It comes with
816 the "Log::Dispatch" bundle and allows you to specify recipient and
817 subject of outgoing emails in the Log4perl configuration file:
818
819 log4perl.category = FATAL, Mailer
820 log4perl.appender.Mailer = Log::Dispatch::Email::MailSend
821 log4perl.appender.Mailer.to = drone@pageme.net
822 log4perl.appender.Mailer.subject = Something's broken!
823 log4perl.appender.Mailer.layout = SimpleLayout
824
825 The message of every log incident this appender gets will then be
826 forwarded to the given email address. Check the
827 "Log::Dispatch::Email::MailSend" documentation for details. And please
828 make sure there's not a flood of email messages sent out by your
829 application, filling up the recipient's inbox.
830
831 There's one caveat you need to know about: The "Log::Dispatch::Email"
832 hierarchy of appenders turns on buffering by default. This means that
833 the appender will not send out messages right away but wait until a
834 certain threshold has been reached. If you'd rather have your alerts
835 sent out immediately, use
836
837 log4perl.appender.Mailer.buffered = 0
838
839 to turn buffering off.
840
841 How can I write my own appender?
842 First off, Log::Log4perl comes with a set of standard appenders. Then,
843 there's a lot of Log4perl-compatible appenders already available on
844 CPAN: Just run a search for "Log::Dispatch" on http://search.cpan.org
845 and chances are that what you're looking for has already been
846 developed, debugged and been used successfully in production -- no need
847 for you to reinvent the wheel.
848
849 Also, Log::Log4perl ships with a nifty database appender named
850 Log::Log4perl::Appender::DBI -- check it out if talking to databases is
851 your desire.
852
853 But if you're up for a truly exotic task, you might have to write an
854 appender yourself. That's very easy -- it takes no longer than a couple
855 of minutes.
856
857 Say, we wanted to create an appender of the class
858 "ColorScreenAppender", which logs messages to the screen in a
859 configurable color. Just create a new class in
860 "ColorScreenAppender.pm":
861
862 package ColorScreenAppender;
863
864 Now let's assume that your Log::Log4perl configuration file "test.conf"
865 looks like this:
866
867 log4perl.logger = INFO, ColorApp
868
869 log4perl.appender.ColorApp=ColorScreenAppender
870 log4perl.appender.ColorApp.color=blue
871
872 log4perl.appender.ColorApp.layout = PatternLayout
873 log4perl.appender.ColorApp.layout.ConversionPattern=%d %m %n
874
875 This will cause Log::Log4perl on init() to look for a class
876 ColorScreenAppender and call its constructor new(). Let's add new() to
877 ColorScreenAppender.pm:
878
879 sub new {
880 my($class, %options) = @_;
881
882 my $self = { %options };
883 bless $self, $class;
884
885 return $self;
886 }
887
888 To initialize this appender, Log::Log4perl will call and pass all
889 attributes of the appender as defined in the configuration file to the
890 constructor as name/value pairs (in this case just one):
891
892 ColorScreenAppender->new(color => "blue");
893
894 The new() method listed above stores the contents of the %options hash
895 in the object's instance data hash (referred to by $self). That's all
896 for initializing a new appender with Log::Log4perl.
897
898 Second, ColorScreenAppender needs to expose a log() method, which will
899 be called by Log::Log4perl every time it thinks the appender should
900 fire. Along with the object reference (as usual in Perl's object
901 world), log() will receive a list of name/value pairs, of which only
902 the one under the key "message" shall be of interest for now since it
903 is the message string to be logged. At this point, Log::Log4perl has
904 already taken care of joining the message to be a single string.
905
906 For our special appender ColorScreenAppender, we're using the
907 Term::ANSIColor module to colorize the output:
908
909 use Term::ANSIColor;
910
911 sub log {
912 my($self, %params) = @_;
913
914 print colored($params{message},
915 $self->{color});
916 }
917
918 The color (as configured in the Log::Log4perl configuration file) is
919 available as $self->{color} in the appender object. Don't forget to
920 return
921
922 1;
923
924 at the end of ColorScreenAppender.pm and you're done. Install the new
925 appender somewhere where perl can find it and try it with a test script
926 like
927
928 use Log::Log4perl qw(:easy);
929 Log::Log4perl->init("test.conf");
930 ERROR("blah");
931
932 to see the new colored output. Is this cool or what?
933
934 And it gets even better: You can write dynamically generated appender
935 classes using the "Class::Prototyped" module. Here's an example of an
936 appender prepending every outgoing message with a configurable number
937 of bullets:
938
939 use Class::Prototyped;
940
941 my $class = Class::Prototyped->newPackage(
942 "MyAppenders::Bulletizer",
943 bullets => 1,
944 log => sub {
945 my($self, %params) = @_;
946 print "*" x $self->bullets(),
947 $params{message};
948 },
949 );
950
951 use Log::Log4perl qw(:easy);
952
953 Log::Log4perl->init(\ q{
954 log4perl.logger = INFO, Bully
955
956 log4perl.appender.Bully=MyAppenders::Bulletizer
957 log4perl.appender.Bully.bullets=3
958
959 log4perl.appender.Bully.layout = PatternLayout
960 log4perl.appender.Bully.layout.ConversionPattern=%m %n
961 });
962
963 # ... prints: "***Boo!\n";
964 INFO "Boo!";
965
966 How can I drill down on references before logging them?
967 If you've got a reference to a nested structure or object, then you
968 probably don't want to log it as HASH(0x81141d4) but rather dump it as
969 something like
970
971 $VAR1 = {
972 'a' => 'b',
973 'd' => 'e'
974 };
975
976 via a module like Data::Dumper. While it's syntactically correct to say
977
978 $logger->debug(Data::Dumper::Dumper($ref));
979
980 this call imposes a huge performance penalty on your application if the
981 message is suppressed by Log::Log4perl, because Data::Dumper will
982 perform its expensive operations in any case, because it doesn't know
983 that its output will be thrown away immediately.
984
985 As of Log::Log4perl 0.28, there's a better way: Use the message output
986 filter format as in
987
988 $logger->debug( {filter => \&Data::Dumper::Dumper,
989 value => $ref} );
990
991 and Log::Log4perl won't call the filter function unless the message
992 really gets written out to an appender. Just make sure to pass the
993 whole slew as a reference to a hash specifying a filter function (as a
994 sub reference) under the key "filter" and the value to be passed to the
995 filter function in "value"). When it comes to logging, Log::Log4perl
996 will call the filter function, pass the "value" as an argument and log
997 the return value. Saves you serious cycles.
998
999 How can I collect all FATAL messages in an extra log file?
1000 Suppose you have employed Log4perl all over your system and you've
1001 already activated logging in various subsystems. On top of that,
1002 without disrupting any other settings, how can you collect all FATAL
1003 messages all over the system and send them to a separate log file?
1004
1005 If you define a root logger like this:
1006
1007 log4perl.logger = FATAL, File
1008 log4perl.appender.File = Log::Log4perl::Appender::File
1009 log4perl.appender.File.filename = /tmp/fatal.txt
1010 log4perl.appender.File.layout = PatternLayout
1011 log4perl.appender.File.layout.ConversionPattern= %d %m %n
1012 # !!! Something's missing ...
1013
1014 you'll be surprised to not only receive all FATAL messages issued
1015 anywhere in the system, but also everything else -- gazillions of
1016 ERROR, WARN, INFO and even DEBUG messages will end up in your fatal.txt
1017 logfile! Reason for this is Log4perl's (or better: Log4j's) appender
1018 additivity. Once a lower-level logger decides to fire, the message is
1019 going to be forwarded to all appenders upstream -- without further
1020 priority checks with their attached loggers.
1021
1022 There's a way to prevent this, however: If your appender defines a
1023 minimum threshold, only messages of this priority or higher are going
1024 to be logged. So, just add
1025
1026 log4perl.appender.File.Threshold = FATAL
1027
1028 to the configuration above, and you'll get what you wanted in the first
1029 place: An overall system FATAL message collector.
1030
1031 How can I bundle several log messages into one?
1032 Would you like to tally the messages arriving at your appender and dump
1033 out a summary once they're exceeding a certain threshold? So that
1034 something like
1035
1036 $logger->error("Blah");
1037 $logger->error("Blah");
1038 $logger->error("Blah");
1039
1040 won't be logged as
1041
1042 Blah
1043 Blah
1044 Blah
1045
1046 but as
1047
1048 [3] Blah
1049
1050 instead? If you'd like to hold off on logging a message until it has
1051 been sent a couple of times, you can roll that out by creating a
1052 buffered appender.
1053
1054 Let's define a new appender like
1055
1056 package TallyAppender;
1057
1058 sub new {
1059 my($class, %options) = @_;
1060
1061 my $self = { maxcount => 5,
1062 %options
1063 };
1064
1065 bless $self, $class;
1066
1067 $self->{last_message} = "";
1068 $self->{last_message_count} = 0;
1069
1070 return $self;
1071 }
1072
1073 with two additional instance variables "last_message" and
1074 "last_message_count", storing the content of the last message sent and
1075 a counter of how many times this has happened. Also, it features a
1076 configuration parameter "maxcount" which defaults to 5 in the snippet
1077 above but can be set in the Log4perl configuration file like this:
1078
1079 log4perl.logger = INFO, A
1080 log4perl.appender.A=TallyAppender
1081 log4perl.appender.A.maxcount = 3
1082
1083 The main tallying logic lies in the appender's "log" method, which is
1084 called every time Log4perl thinks a message needs to get logged by our
1085 appender:
1086
1087 sub log {
1088 my($self, %params) = @_;
1089
1090 # Message changed? Print buffer.
1091 if($self->{last_message} and
1092 $params{message} ne $self->{last_message}) {
1093 print "[$self->{last_message_count}]: " .
1094 "$self->{last_message}";
1095 $self->{last_message_count} = 1;
1096 $self->{last_message} = $params{message};
1097 return;
1098 }
1099
1100 $self->{last_message_count}++;
1101 $self->{last_message} = $params{message};
1102
1103 # Threshold exceeded? Print, reset counter
1104 if($self->{last_message_count} >=
1105 $self->{maxcount}) {
1106 print "[$self->{last_message_count}]: " .
1107 "$params{message}";
1108 $self->{last_message_count} = 0;
1109 $self->{last_message} = "";
1110 return;
1111 }
1112 }
1113
1114 We basically just check if the oncoming message in $param{message} is
1115 equal to what we've saved before in the "last_message" instance
1116 variable. If so, we're increasing "last_message_count". We print the
1117 message in two cases: If the new message is different than the buffered
1118 one, because then we need to dump the old stuff and store the new. Or,
1119 if the counter exceeds the threshold, as defined by the "maxcount"
1120 configuration parameter.
1121
1122 Please note that the appender always gets the fully rendered message
1123 and just compares it as a whole -- so if there's a date/timestamp in
1124 there, that might confuse your logic. You can work around this by
1125 specifying %m %n as a layout and add the date later on in the appender.
1126 Or, make the comparison smart enough to omit the date.
1127
1128 At last, don't forget what happens if the program is being shut down.
1129 If there's still messages in the buffer, they should be printed out at
1130 that point. That's easy to do in the appender's DESTROY method, which
1131 gets called at object destruction time:
1132
1133 sub DESTROY {
1134 my($self) = @_;
1135
1136 if($self->{last_message_count}) {
1137 print "[$self->{last_message_count}]: " .
1138 "$self->{last_message}";
1139 return;
1140 }
1141 }
1142
1143 This will ensure that none of the buffered messages are lost. Happy
1144 buffering!
1145
1146 I want to log ERROR and WARN messages to different files! How can I do
1147 that?
1148 Let's assume you wanted to have each logging statement written to a
1149 different file, based on the statement's priority. Messages with
1150 priority "WARN" are supposed to go to "/tmp/app.warn", events
1151 prioritized as "ERROR" should end up in "/tmp/app.error".
1152
1153 Now, if you define two appenders "AppWarn" and "AppError" and assign
1154 them both to the root logger, messages bubbling up from any loggers
1155 below will be logged by both appenders because of Log4perl's message
1156 propagation feature. If you limit their exposure via the appender
1157 threshold mechanism and set "AppWarn"'s threshold to "WARN" and
1158 "AppError"'s to "ERROR", you'll still get "ERROR" messages in
1159 "AppWarn", because "AppWarn"'s "WARN" setting will just filter out
1160 messages with a lower priority than "WARN" -- "ERROR" is higher and
1161 will be allowed to pass through.
1162
1163 What we need for this is a Log4perl Custom Filter, available with
1164 Log::Log4perl 0.30.
1165
1166 Both appenders need to verify that the priority of the oncoming
1167 messages exactly matches the priority the appender is supposed to log
1168 messages of. To accomplish this task, let's define two custom filters,
1169 "MatchError" and "MatchWarn", which, when attached to their appenders,
1170 will limit messages passed on to them to those matching a given
1171 priority:
1172
1173 log4perl.logger = WARN, AppWarn, AppError
1174
1175 # Filter to match level ERROR
1176 log4perl.filter.MatchError = Log::Log4perl::Filter::LevelMatch
1177 log4perl.filter.MatchError.LevelToMatch = ERROR
1178 log4perl.filter.MatchError.AcceptOnMatch = true
1179
1180 # Filter to match level WARN
1181 log4perl.filter.MatchWarn = Log::Log4perl::Filter::LevelMatch
1182 log4perl.filter.MatchWarn.LevelToMatch = WARN
1183 log4perl.filter.MatchWarn.AcceptOnMatch = true
1184
1185 # Error appender
1186 log4perl.appender.AppError = Log::Log4perl::Appender::File
1187 log4perl.appender.AppError.filename = /tmp/app.err
1188 log4perl.appender.AppError.layout = SimpleLayout
1189 log4perl.appender.AppError.Filter = MatchError
1190
1191 # Warning appender
1192 log4perl.appender.AppWarn = Log::Log4perl::Appender::File
1193 log4perl.appender.AppWarn.filename = /tmp/app.warn
1194 log4perl.appender.AppWarn.layout = SimpleLayout
1195 log4perl.appender.AppWarn.Filter = MatchWarn
1196
1197 The appenders "AppWarn" and "AppError" defined above are logging to
1198 "/tmp/app.warn" and "/tmp/app.err" respectively and have the custom
1199 filters "MatchWarn" and "MatchError" attached. This setup will direct
1200 all WARN messages, issued anywhere in the system, to /tmp/app.warn (and
1201 ERROR messages to /tmp/app.error) -- without any overlaps.
1202
1203 On our server farm, Log::Log4perl configuration files differ slightly from
1204 host to host. Can I roll them all into one?
1205 You sure can, because Log::Log4perl allows you to specify attribute
1206 values dynamically. Let's say that one of your appenders expects the
1207 host's IP address as one of its attributes. Now, you could certainly
1208 roll out different configuration files for every host and specify the
1209 value like
1210
1211 log4perl.appender.MyAppender = Log::Log4perl::Appender::SomeAppender
1212 log4perl.appender.MyAppender.ip = 10.0.0.127
1213
1214 but that's a maintenance nightmare. Instead, you can have Log::Log4perl
1215 figure out the IP address at configuration time and set the appender's
1216 value correctly:
1217
1218 # Set the IP address dynamically
1219 log4perl.appender.MyAppender = Log::Log4perl::Appender::SomeAppender
1220 log4perl.appender.MyAppender.ip = sub { \
1221 use Sys::Hostname; \
1222 use Socket; \
1223 return inet_ntoa(scalar gethostbyname hostname); \
1224 }
1225
1226 If Log::Log4perl detects that an attribute value starts with something
1227 like "sub {...", it will interpret it as a perl subroutine which is to
1228 be executed once at configuration time (not runtime!) and its return
1229 value is to be used as the attribute value. This comes in handy for
1230 rolling out applications where Log::Log4perl configuration files show
1231 small host-specific differences, because you can deploy the unmodified
1232 application distribution on all instances of the server farm.
1233
1234 Log4perl doesn't interpret my backslashes correctly!
1235 If you're using Log4perl's feature to specify the configuration as a
1236 string in your program (as opposed to a separate configuration file),
1237 chances are that you've written it like this:
1238
1239 # *** WRONG! ***
1240
1241 Log::Log4perl->init( \ <<END_HERE);
1242 log4perl.logger = WARN, A1
1243 log4perl.appender.A1 = Log::Log4perl::Appender::Screen
1244 log4perl.appender.A1.layout = \
1245 Log::Log4perl::Layout::PatternLayout
1246 log4perl.appender.A1.layout.ConversionPattern = %m%n
1247 END_HERE
1248
1249 # *** WRONG! ***
1250
1251 and you're getting the following error message:
1252
1253 Layout not specified for appender A1 at .../Config.pm line 342.
1254
1255 What's wrong? The problem is that you're using a here-document with
1256 substitution enabled ("<<END_HERE") and that Perl won't interpret
1257 backslashes at line-ends as continuation characters but will
1258 essentially throw them out. So, in the code above, the layout line will
1259 look like
1260
1261 log4perl.appender.A1.layout =
1262
1263 to Log::Log4perl which causes it to report an error. To interpret the
1264 backslash at the end of the line correctly as a line-continuation
1265 character, use the non-interpreting mode of the here-document like in
1266
1267 # *** RIGHT! ***
1268
1269 Log::Log4perl->init( \ <<'END_HERE');
1270 log4perl.logger = WARN, A1
1271 log4perl.appender.A1 = Log::Log4perl::Appender::Screen
1272 log4perl.appender.A1.layout = \
1273 Log::Log4perl::Layout::PatternLayout
1274 log4perl.appender.A1.layout.ConversionPattern = %m%n
1275 END_HERE
1276
1277 # *** RIGHT! ***
1278
1279 (note the single quotes around 'END_HERE') or use "q{...}" instead of a
1280 here-document and Perl will treat the backslashes at line-end as
1281 intended.
1282
1283 I want to suppress certain messages based on their content!
1284 Let's assume you've plastered all your functions with Log4perl
1285 statements like
1286
1287 sub some_func {
1288
1289 INFO("Begin of function");
1290
1291 # ... Stuff happens here ...
1292
1293 INFO("End of function");
1294 }
1295
1296 to issue two log messages, one at the beginning and one at the end of
1297 each function. Now you want to suppress the message at the beginning
1298 and only keep the one at the end, what can you do? You can't use the
1299 category mechanism, because both messages are issued from the same
1300 package.
1301
1302 Log::Log4perl's custom filters (0.30 or better) provide an interface
1303 for the Log4perl user to step in right before a message gets logged and
1304 decide if it should be written out or suppressed, based on the message
1305 content or other parameters:
1306
1307 use Log::Log4perl qw(:easy);
1308
1309 Log::Log4perl::init( \ <<'EOT' );
1310 log4perl.logger = INFO, A1
1311 log4perl.appender.A1 = Log::Log4perl::Appender::Screen
1312 log4perl.appender.A1.layout = \
1313 Log::Log4perl::Layout::PatternLayout
1314 log4perl.appender.A1.layout.ConversionPattern = %m%n
1315
1316 log4perl.filter.M1 = Log::Log4perl::Filter::StringMatch
1317 log4perl.filter.M1.StringToMatch = Begin
1318 log4perl.filter.M1.AcceptOnMatch = false
1319
1320 log4perl.appender.A1.Filter = M1
1321 EOT
1322
1323 The last four statements in the configuration above are defining a
1324 custom filter "M1" of type "Log::Log4perl::Filter::StringMatch", which
1325 comes with Log4perl right out of the box and allows you to define a
1326 text pattern to match (as a perl regular expression) and a flag
1327 "AcceptOnMatch" indicating if a match is supposed to suppress the
1328 message or let it pass through.
1329
1330 The last line then assigns this filter to the "A1" appender, which will
1331 call it every time it receives a message to be logged and throw all
1332 messages out not matching the regular expression "Begin".
1333
1334 Instead of using the standard "Log::Log4perl::Filter::StringMatch"
1335 filter, you can define your own, simply using a perl subroutine:
1336
1337 log4perl.filter.ExcludeBegin = sub { !/Begin/ }
1338 log4perl.appender.A1.Filter = ExcludeBegin
1339
1340 For details on custom filters, check Log::Log4perl::Filter.
1341
1342 My new module uses Log4perl -- but what happens if the calling program
1343 didn't configure it?
1344 If a Perl module uses Log::Log4perl, it will typically rely on the
1345 calling program to initialize it. If it is using Log::Log4perl in
1346 ":easy" mode, like in
1347
1348 package MyMod;
1349 use Log::Log4perl qw(:easy);
1350
1351 sub foo {
1352 DEBUG("In foo");
1353 }
1354
1355 1;
1356
1357 and the calling program doesn't initialize Log::Log4perl at all (e.g.
1358 because it has no clue that it's available), Log::Log4perl will
1359 silently ignore all logging messages. However, if the module is using
1360 Log::Log4perl in regular mode like in
1361
1362 package MyMod;
1363 use Log::Log4perl qw(get_logger);
1364
1365 sub foo {
1366 my $logger = get_logger("");
1367 $logger->debug("blah");
1368 }
1369
1370 1;
1371
1372 and the main program is just using the module like in
1373
1374 use MyMode;
1375 MyMode::foo();
1376
1377 then Log::Log4perl will also ignore all logging messages but issue a
1378 warning like
1379
1380 Log4perl: Seems like no initialization happened.
1381 Forgot to call init()?
1382
1383 (only once!) to remind novice users to not forget to initialize the
1384 logging system before using it. However, if you want to suppress this
1385 message, just add the ":nowarn" target to the module's "use
1386 Log::Log4perl" call:
1387
1388 use Log::Log4perl qw(get_logger :nowarn);
1389
1390 This will have Log::Log4perl silently ignore all logging statements if
1391 no initialization has taken place. If, instead of using init(), you're
1392 using Log4perl's API to define loggers and appenders, the same
1393 notification happens if no call to add_appenders() is made, i.e. no
1394 appenders are defined.
1395
1396 If the module wants to figure out if some other program part has
1397 already initialized Log::Log4perl, it can do so by calling
1398
1399 Log::Log4perl::initialized()
1400
1401 which will return a true value in case Log::Log4perl has been
1402 initialized and a false value if not.
1403
1404 How can I synchronize access to an appender?
1405 If you're using the same instance of an appender in multiple processes,
1406 and each process is passing on messages to the appender in parallel,
1407 you might end up with overlapping log entries.
1408
1409 Typical scenarios include a file appender that you create in the main
1410 program, and which will then be shared between the parent and a forked
1411 child process. Or two separate processes, each initializing a Log4perl
1412 file appender on the same logfile.
1413
1414 Log::Log4perl won't synchronize access to the shared logfile by
1415 default. Depending on your operating system's flush mechanism, buffer
1416 size and the size of your messages, there's a small chance of an
1417 overlap.
1418
1419 The easiest way to prevent overlapping messages in logfiles written to
1420 by multiple processes is setting the file appender's "syswrite" flag
1421 along with a file write mode of "append". This makes sure that
1422 "Log::Log4perl::Appender::File" uses syswrite() (which is guaranteed to
1423 run uninterrupted) instead of print() which might buffer the message or
1424 get interrupted by the OS while it is writing. And in "append" mode,
1425 the OS kernel ensures that multiple processes share one end-of-file
1426 marker, ensuring that each process writes to the real end of the file.
1427 (The value of "append" for the "mode" parameter is the default setting
1428 in Log4perl's file appender so you don't have to set it explicitly.)
1429
1430 # Guarantees atomic writes
1431
1432 log4perl.category.Bar.Twix = WARN, Logfile
1433
1434 log4perl.appender.Logfile = Log::Log4perl::Appender::File
1435 log4perl.appender.Logfile.mode = append
1436 log4perl.appender.Logfile.syswrite = 1
1437 log4perl.appender.Logfile.filename = test.log
1438 log4perl.appender.Logfile.layout = SimpleLayout
1439
1440 Another guaranteed way of having messages separated with any kind of
1441 appender is putting a Log::Log4perl::Appender::Synchronized composite
1442 appender in between Log::Log4perl and the real appender. It will make
1443 sure to let messages pass through this virtual gate one by one only.
1444
1445 Here's a sample configuration to synchronize access to a file appender:
1446
1447 log4perl.category.Bar.Twix = WARN, Syncer
1448
1449 log4perl.appender.Logfile = Log::Log4perl::Appender::File
1450 log4perl.appender.Logfile.autoflush = 1
1451 log4perl.appender.Logfile.filename = test.log
1452 log4perl.appender.Logfile.layout = SimpleLayout
1453
1454 log4perl.appender.Syncer = Log::Log4perl::Appender::Synchronized
1455 log4perl.appender.Syncer.appender = Logfile
1456
1457 "Log::Log4perl::Appender::Synchronized" uses the "IPC::Shareable"
1458 module and its semaphores, which will slow down writing the log
1459 messages, but ensures sequential access featuring atomic checks. Check
1460 Log::Log4perl::Appender::Synchronized for details.
1461
1462 Can I use Log::Log4perl with log4j's Chainsaw?
1463 Yes, Log::Log4perl can be configured to send its events to log4j's
1464 graphical log UI Chainsaw.
1465
1466 Here's how it works:
1467
1468 • Get Guido Carls' <gcarls@cpan.org> Log::Log4perl extension
1469 "Log::Log4perl::Layout::XMLLayout" from CPAN and install it:
1470
1471 perl -MCPAN -eshell
1472 cpan> install Log::Log4perl::Layout::XMLLayout
1473
1474 • Install and start Chainsaw, which is part of the "log4j"
1475 distribution now (see http://jakarta.apache.org/log4j ). Create a
1476 configuration file like
1477
1478 <log4j:configuration debug="true">
1479 <plugin name="XMLSocketReceiver"
1480 class="org.apache.log4j.net.XMLSocketReceiver">
1481 <param name="decoder" value="org.apache.log4j.xml.XMLDecoder"/>
1482 <param name="Port" value="4445"/>
1483 </plugin>
1484 <root> <level value="debug"/> </root>
1485 </log4j:configuration>
1486
1487 and name it e.g. "config.xml". Then start Chainsaw like
1488
1489 java -Dlog4j.debug=true -Dlog4j.configuration=config.xml \
1490 -classpath ".:log4j-1.3alpha.jar:log4j-chainsaw-1.3alpha.jar" \
1491 org.apache.log4j.chainsaw.LogUI
1492
1493 and watch the GUI coming up.
1494
1495 • Configure Log::Log4perl to use a socket appender with an XMLLayout,
1496 pointing to the host/port where Chainsaw (as configured above) is
1497 waiting with its XMLSocketReceiver:
1498
1499 use Log::Log4perl qw(get_logger);
1500 use Log::Log4perl::Layout::XMLLayout;
1501
1502 my $conf = q(
1503 log4perl.category.Bar.Twix = WARN, Appender
1504 log4perl.appender.Appender = Log::Log4perl::Appender::Socket
1505 log4perl.appender.Appender.PeerAddr = localhost
1506 log4perl.appender.Appender.PeerPort = 4445
1507 log4perl.appender.Appender.layout = Log::Log4perl::Layout::XMLLayout
1508 );
1509
1510 Log::Log4perl::init(\$conf);
1511
1512 # Nasty hack to suppress encoding header
1513 my $app = Log::Log4perl::appenders->{"Appender"};
1514 $app->layout()->{enc_set} = 1;
1515
1516 my $logger = get_logger("Bar.Twix");
1517 $logger->error("One");
1518
1519 The nasty hack shown in the code snippet above is currently
1520 (October 2003) necessary, because Chainsaw expects XML messages to
1521 arrive in a format like
1522
1523 <log4j:event logger="Bar.Twix"
1524 timestamp="1066794904310"
1525 level="ERROR"
1526 thread="10567">
1527 <log4j:message><![CDATA[Two]]></log4j:message>
1528 <log4j:NDC><![CDATA[undef]]></log4j:NDC>
1529 <log4j:locationInfo class="main"
1530 method="main"
1531 file="./t"
1532 line="32">
1533 </log4j:locationInfo>
1534 </log4j:event>
1535
1536 without a preceding
1537
1538 <?xml version = "1.0" encoding = "iso8859-1"?>
1539
1540 which Log::Log4perl::Layout::XMLLayout applies to the first event
1541 sent over the socket.
1542
1543 See figure 1 for a screenshot of Chainsaw in action, receiving events
1544 from the Perl script shown above.
1545
1546 Many thanks to Chainsaw's Scott Deboy <sdeboy@comotivsystems.com> for
1547 his support!
1548
1549 How can I run Log::Log4perl under mod_perl?
1550 In persistent environments it's important to play by the rules outlined
1551 in section "Initialize once and only once" in Log::Log4perl. If you
1552 haven't read this yet, please go ahead and read it right now. It's very
1553 important.
1554
1555 And no matter if you use a startup handler to init() Log::Log4perl or
1556 use the init_once() strategy (added in 0.42), either way you're very
1557 likely to have unsynchronized writes to logfiles.
1558
1559 If Log::Log4perl is configured with a log file appender, and it is
1560 initialized via the Apache startup handler, the file handle created
1561 initially will be shared among all Apache processes. Similarly, with
1562 the init_once() approach: although every process has a separate L4p
1563 configuration, processes are gonna share the appender file names
1564 instead, effectively opening several different file handles on the same
1565 file.
1566
1567 Now, having several appenders using the same file handle or having
1568 several appenders logging to the same file unsynchronized, this might
1569 result in overlapping messages. Sometimes, this is acceptable. If it's
1570 not, here's two strategies:
1571
1572 • Use the Log::Log4perl::Appender::Synchronized appender to connect
1573 to your file appenders. Here's the writeup:
1574 http://log4perl.sourceforge.net/releases/Log-Log4perl/docs/html/Log/Log4perl/FAQ.html#23804
1575
1576 • Use a different logfile for every process like in
1577
1578 #log4perl.conf
1579 ...
1580 log4perl.appender.A1.filename = sub { "mylog.$$.log" }
1581
1582 My program already uses warn() and die(). How can I switch to Log4perl?
1583 If your program already uses Perl's warn() function to spew out error
1584 messages and you'd like to channel those into the Log4perl world, just
1585 define a "__WARN__" handler where your program or module resides:
1586
1587 use Log::Log4perl qw(:easy);
1588
1589 $SIG{__WARN__} = sub {
1590 local $Log::Log4perl::caller_depth =
1591 $Log::Log4perl::caller_depth + 1;
1592 WARN @_;
1593 };
1594
1595 Why the "local" setting of $Log::Log4perl::caller_depth? If you leave
1596 that out, "PatternLayout" conversion specifiers like %M or %F (printing
1597 the current function/method and source filename) will refer to where
1598 the __WARN__ handler resides, not the environment Perl's warn()
1599 function was issued from. Increasing "caller_depth" adjusts for this
1600 offset. Having it "local", makes sure the level gets set back after the
1601 handler exits.
1602
1603 Once done, if your program does something like
1604
1605 sub some_func {
1606 warn "Here's a warning";
1607 }
1608
1609 you'll get (depending on your Log::Log4perl configuration) something
1610 like
1611
1612 2004/02/19 20:41:02-main::some_func: Here's a warning at ./t line 25.
1613
1614 in the appropriate appender instead of having a screen full of STDERR
1615 messages. It also works with the "Carp" module and its carp() and
1616 cluck() functions.
1617
1618 If, on the other hand, catching die() and friends is required, a
1619 "__DIE__" handler is appropriate:
1620
1621 $SIG{__DIE__} = sub {
1622 if($^S) {
1623 # We're in an eval {} and don't want log
1624 # this message but catch it later
1625 return;
1626 }
1627 local $Log::Log4perl::caller_depth =
1628 $Log::Log4perl::caller_depth + 1;
1629 LOGDIE @_;
1630 };
1631
1632 This will call Log4perl's LOGDIE() function, which will log a fatal
1633 error and then call die() internally, causing the program to exit.
1634 Works equally well with "Carp"'s croak() and confess() functions.
1635
1636 Some module prints messages to STDERR. How can I funnel them to
1637 Log::Log4perl?
1638 If a module you're using doesn't use Log::Log4perl but prints logging
1639 messages to STDERR instead, like
1640
1641 ########################################
1642 package IgnorantModule;
1643 ########################################
1644
1645 sub some_method {
1646 print STDERR "Parbleu! An error!\n";
1647 }
1648
1649 1;
1650
1651 there's still a way to capture these messages and funnel them into
1652 Log::Log4perl, even without touching the module. What you need is a
1653 trapper module like
1654
1655 ########################################
1656 package Trapper;
1657 ########################################
1658
1659 use Log::Log4perl qw(:easy);
1660
1661 sub TIEHANDLE {
1662 my $class = shift;
1663 bless [], $class;
1664 }
1665
1666 sub PRINT {
1667 my $self = shift;
1668 $Log::Log4perl::caller_depth++;
1669 DEBUG @_;
1670 $Log::Log4perl::caller_depth--;
1671 }
1672
1673 1;
1674
1675 and a "tie" command in the main program to tie STDERR to the trapper
1676 module along with regular Log::Log4perl initialization:
1677
1678 ########################################
1679 package main;
1680 ########################################
1681
1682 use Log::Log4perl qw(:easy);
1683
1684 Log::Log4perl->easy_init(
1685 {level => $DEBUG,
1686 file => 'stdout', # make sure not to use stderr here!
1687 layout => "%d %M: %m%n",
1688 });
1689
1690 tie *STDERR, "Trapper";
1691
1692 Make sure not to use STDERR as Log::Log4perl's file appender here
1693 (which would be the default in ":easy" mode), because it would end up
1694 in an endless recursion.
1695
1696 Now, calling
1697
1698 IgnorantModule::some_method();
1699
1700 will result in the desired output
1701
1702 2004/05/06 11:13:04 IgnorantModule::some_method: Parbleu! An error!
1703
1704 How come PAR (Perl Archive Toolkit) creates executables which then can't
1705 find their Log::Log4perl appenders?
1706 If not instructed otherwise, "Log::Log4perl" dynamically pulls in
1707 appender classes found in its configuration. If you specify
1708
1709 #!/usr/bin/perl
1710 # mytest.pl
1711
1712 use Log::Log4perl qw(get_logger);
1713
1714 my $conf = q(
1715 log4perl.category.Bar.Twix = WARN, Logfile
1716 log4perl.appender.Logfile = Log::Log4perl::Appender::Screen
1717 log4perl.appender.Logfile.layout = SimpleLayout
1718 );
1719
1720 Log::Log4perl::init(\$conf);
1721 my $logger = get_logger("Bar::Twix");
1722 $logger->error("Blah");
1723
1724 then "Log::Log4perl::Appender::Screen" will be pulled in while the
1725 program runs, not at compile time. If you have PAR compile the script
1726 above to an executable binary via
1727
1728 pp -o mytest mytest.pl
1729
1730 and then run "mytest" on a machine without having Log::Log4perl
1731 installed, you'll get an error message like
1732
1733 ERROR: can't load appenderclass 'Log::Log4perl::Appender::Screen'
1734 Can't locate Log/Log4perl/Appender/Screen.pm in @INC ...
1735
1736 Why? At compile time, "pp" didn't realize that
1737 "Log::Log4perl::Appender::Screen" would be needed later on and didn't
1738 wrap it into the executable created. To avoid this, either say "use
1739 Log::Log4perl::Appender::Screen" in the script explicitly or compile it
1740 with
1741
1742 pp -o mytest -M Log::Log4perl::Appender::Screen mytest.pl
1743
1744 to make sure the appender class gets included.
1745
1746 How can I access a custom appender defined in the configuration?
1747 Any appender defined in the configuration file or somewhere in the code
1748 can be accessed later via
1749 "Log::Log4perl->appender_by_name("appender_name")", which returns a
1750 reference of the appender object.
1751
1752 Once you've got a hold of the object, it can be queried or modified to
1753 your liking. For example, see the custom "IndentAppender" defined
1754 below: After calling init() to define the Log4perl settings, the
1755 appender object is retrieved to call its indent_more() and
1756 indent_less() methods to control indentation of messages:
1757
1758 package IndentAppender;
1759
1760 sub new {
1761 bless { indent => 0 }, $_[0];
1762 }
1763
1764 sub indent_more { $_[0]->{indent}++ }
1765 sub indent_less { $_[0]->{indent}-- }
1766
1767 sub log {
1768 my($self, %params) = @_;
1769 print " " x $self->{indent}, $params{message};
1770 }
1771
1772 package main;
1773
1774 use Log::Log4perl qw(:easy);
1775
1776 my $conf = q(
1777 log4perl.category = DEBUG, Indented
1778 log4perl.appender.Indented = IndentAppender
1779 log4perl.appender.Indented.layout = Log::Log4perl::Layout::SimpleLayout
1780 );
1781
1782 Log::Log4perl::init(\$conf);
1783
1784 my $appender = Log::Log4perl->appender_by_name("Indented");
1785
1786 DEBUG "No identation";
1787 $appender->indent_more();
1788 DEBUG "One more";
1789 $appender->indent_more();
1790 DEBUG "Two more";
1791 $appender->indent_less();
1792 DEBUG "One less";
1793
1794 As you would expect, this will print
1795
1796 DEBUG - No identation
1797 DEBUG - One more
1798 DEBUG - Two more
1799 DEBUG - One less
1800
1801 because the very appender used by Log4perl is modified dynamically at
1802 runtime.
1803
1804 I don't know if Log::Log4perl is installed. How can I prepare my script?
1805 In case your script needs to be prepared for environments that may or
1806 may not have Log::Log4perl installed, there's a trick.
1807
1808 If you put the following BEGIN blocks at the top of the program, you'll
1809 be able to use the DEBUG(), INFO(), etc. macros in Log::Log4perl's
1810 ":easy" mode. If Log::Log4perl is installed in the target environment,
1811 the regular Log::Log4perl rules apply. If not, all of DEBUG(), INFO(),
1812 etc. are "stubbed" out, i.e. they turn into no-ops:
1813
1814 use warnings;
1815 use strict;
1816
1817 BEGIN {
1818 eval { require Log::Log4perl; };
1819
1820 if($@) {
1821 print "Log::Log4perl not installed - stubbing.\n";
1822 no strict qw(refs);
1823 *{"main::$_"} = sub { } for qw(DEBUG INFO WARN ERROR FATAL);
1824 } else {
1825 no warnings;
1826 print "Log::Log4perl installed - life is good.\n";
1827 require Log::Log4perl::Level;
1828 Log::Log4perl::Level->import(__PACKAGE__);
1829 Log::Log4perl->import(qw(:easy));
1830 Log::Log4perl->easy_init($main::DEBUG);
1831 }
1832 }
1833
1834 # The regular script begins ...
1835 DEBUG "Hey now!";
1836
1837 This snippet will first probe for Log::Log4perl, and if it can't be
1838 found, it will alias DEBUG(), INFO(), with empty subroutines via
1839 typeglobs. If Log::Log4perl is available, its level constants are
1840 first imported ($DEBUG, $INFO, etc.) and then easy_init() gets called
1841 to initialize the logging system.
1842
1843 Can file appenders create files with different permissions?
1844 Typically, when "Log::Log4perl::Appender::File" creates a new file, its
1845 permissions are set to "rw-r--r--". Why? Because your environment's
1846 umask most likely defaults to 0022, that's the standard setting.
1847
1848 What's a umask, you're asking? It's a template that's applied to the
1849 permissions of all newly created files. While calls like "open(FILE,
1850 ">foo")" will always try to create files in "rw-rw-rw- " mode, the
1851 system will apply the current umask template to determine the final
1852 permission setting. umask is a bit mask that's inverted and then
1853 applied to the requested permission setting, using a bitwise AND:
1854
1855 $request_permission &~ $umask
1856
1857 So, a umask setting of 0000 (the leading 0 simply indicates an octal
1858 value) will create files in "rw-rw-rw-" mode, a setting of 0277 will
1859 use "r--------", and the standard 0022 will use "rw-r--r--".
1860
1861 As an example, if you want your log files to be created with
1862 "rw-r--rw-" permissions, use a umask of 0020 before calling
1863 Log::Log4perl->init():
1864
1865 use Log::Log4perl;
1866
1867 umask 0020;
1868 # Creates log.out in rw-r--rw mode
1869 Log::Log4perl->init(\ q{
1870 log4perl.logger = WARN, File
1871 log4perl.appender.File = Log::Log4perl::Appender::File
1872 log4perl.appender.File.filename = log.out
1873 log4perl.appender.File.layout = SimpleLayout
1874 });
1875
1876 Using Log4perl in an END block causes a problem!
1877 It's not easy to get to this error, but if you write something like
1878
1879 END { Log::Log4perl::get_logger()->debug("Hey there."); }
1880
1881 use Log::Log4perl qw(:easy);
1882 Log::Log4perl->easy_init($DEBUG);
1883
1884 it won't work. The reason is that "Log::Log4perl" defines an END block
1885 that cleans up all loggers. And perl will run END blocks in the reverse
1886 order as they're encountered in the compile phase, so in the scenario
1887 above, the END block will run after Log4perl has cleaned up its
1888 loggers.
1889
1890 Placing END blocks using Log4perl after a "use Log::Log4perl" statement
1891 fixes the problem:
1892
1893 use Log::Log4perl qw(:easy);
1894 Log::Log4perl->easy_init($DEBUG);
1895
1896 END { Log::Log4perl::get_logger()->debug("Hey there."); }
1897
1898 In this scenario, the shown END block is executed before Log4perl
1899 cleans up and the debug message will be processed properly.
1900
1901 Help! My appender is throwing a "Wide character in print" warning!
1902 This warning shows up when Unicode strings are printed without
1903 precautions. The warning goes away if the complaining appender is set
1904 to utf-8 mode:
1905
1906 # Either in the log4perl configuration file:
1907 log4perl.appender.Logfile.filename = test.log
1908 log4perl.appender.Logfile.utf8 = 1
1909
1910 # Or, in easy mode:
1911 Log::Log4perl->easy_init( {
1912 level => $DEBUG,
1913 file => ":utf8> test.log"
1914 } );
1915
1916 If the complaining appender is a screen appender, set its "utf8"
1917 option:
1918
1919 log4perl.appender.Screen.stderr = 1
1920 log4perl.appender.Screen.utf8 = 1
1921
1922 Alternatively, "binmode" does the trick:
1923
1924 # Either STDOUT ...
1925 binmode(STDOUT, ":utf8);
1926
1927 # ... or STDERR.
1928 binmode(STDERR, ":utf8);
1929
1930 Some background on this: Perl's strings are either byte strings or
1931 Unicode strings. "Mike" is a byte string. "\x{30DE}\x{30A4}\x{30AF}"
1932 is a Unicode string. Unicode strings are marked specially and are UTF-8
1933 encoded internally.
1934
1935 If you print a byte string to STDOUT, all is well, because STDOUT is by
1936 default set to byte mode. However, if you print a Unicode string to
1937 STDOUT without precautions, "perl" will try to transform the Unicode
1938 string back to a byte string before printing it out. This is
1939 troublesome if the Unicode string contains 'wide' characters which
1940 can't be represented in Latin-1.
1941
1942 For example, if you create a Unicode string with three japanese
1943 Katakana characters as in
1944
1945 perl -le 'print "\x{30DE}\x{30A4}\x{30AF}"'
1946
1947 (coincidentally pronounced Ma-i-ku, the japanese pronunciation of
1948 "Mike"), STDOUT is in byte mode and the warning
1949
1950 Wide character in print at ./script.pl line 14.
1951
1952 appears. Setting STDOUT to UTF-8 mode as in
1953
1954 perl -le 'binmode(STDOUT, ":utf8"); print "\x{30DE}\x{30A4}\x{30AF}"'
1955
1956 will silently print the Unicode string to STDOUT in UTF-8. To see the
1957 characters printed, you'll need a UTF-8 terminal with a font including
1958 japanese Katakana characters.
1959
1960 How can I send errors to the screen, and debug messages to a file?
1961 Let's assume you want to maintain a detailed DEBUG output in a file and
1962 only messages of level ERROR and higher should be printed on the
1963 screen. Often times, developers come up with something like this:
1964
1965 # Wrong!!!
1966 log4perl.logger = DEBUG, FileApp
1967 log4perl.logger = ERROR, ScreenApp
1968 # Wrong!!!
1969
1970 This won't work, however. Logger definitions aren't additive, and the
1971 second statement will overwrite the first one. Log4perl versions below
1972 1.04 were silently accepting this, leaving people confused why it
1973 wouldn't work as expected. As of 1.04, this will throw a fatal error
1974 to notify the user of the problem.
1975
1976 What you want to do instead, is this:
1977
1978 log4perl.logger = DEBUG, FileApp, ScreenApp
1979
1980 log4perl.appender.FileApp = Log::Log4perl::Appender::File
1981 log4perl.appender.FileApp.filename = test.log
1982 log4perl.appender.FileApp.layout = SimpleLayout
1983
1984 log4perl.appender.ScreenApp = Log::Log4perl::Appender::Screen
1985 log4perl.appender.ScreenApp.stderr = 0
1986 log4perl.appender.ScreenApp.layout = SimpleLayout
1987 ### limiting output to ERROR messages
1988 log4perl.appender.ScreenApp.Threshold = ERROR
1989 ###
1990
1991 Note that without the second appender's "Threshold" setting, both
1992 appenders would receive all messages prioritized DEBUG and higher. With
1993 the threshold set to ERROR, the second appender will filter the
1994 messages as required.
1995
1996 Where should I put my logfiles?
1997 Your log files may go anywhere you want them, but the effective user id
1998 of the calling process must have write access.
1999
2000 If the log file doesn't exist at program start, Log4perl's file
2001 appender will create it. For this, it needs write access to the
2002 directory where the new file will be located in. If the log file
2003 already exists at startup, the process simply needs write access to the
2004 file. Note that it will need write access to the file's directory if
2005 you're encountering situations where the logfile gets recreated, e.g.
2006 during log rotation.
2007
2008 If Log::Log4perl is used by a web server application (e.g. in a CGI
2009 script or mod_perl), then the webserver's user (usually "nobody" or
2010 "www") must have the permissions mentioned above.
2011
2012 To prepare your web server to use log4perl, we'd recommend:
2013
2014 webserver:~$ su -
2015 webserver:~# mkdir /var/log/cgiapps
2016 webserver:~# chown nobody:root /var/log/cgiapps/
2017 webserver:~# chown nobody:root -R /var/log/cgiapps/
2018 webserver:~# chmod 02755 -R /var/log/cgiapps/
2019
2020 Then set your /etc/log4perl.conf file to include:
2021
2022 log4perl.appender.FileAppndr1.filename =
2023 /var/log/cgiapps/<app-name>.log
2024
2025 How can my file appender deal with disappearing log files?
2026 The file appender that comes with Log4perl,
2027 Log::Log4perl::Appender::File, will open a specified log file at
2028 initialization time and will keep writing to it via a file handle.
2029
2030 In case the associated file goes way, messages written by a long-
2031 running process will still be written to the file handle. In case the
2032 file has been moved to a different location on the same file system,
2033 the writer will keep writing to it under the new filename. In case the
2034 file has been removed from the file system, the log messages will end
2035 up in nowhere land. This is not a bug in Log4perl, this is how Unix
2036 works. There is no error message in this case, because the writer has
2037 no idea that the file handle is not associated with a visible file.
2038
2039 To prevent the loss of log messages when log files disappear, the file
2040 appender's "recreate" option needs to be set to a true value:
2041
2042 log4perl.appender.Logfile.recreate = 1
2043
2044 This will instruct the file appender to check in regular intervals
2045 (default: 30 seconds) if the log file is still there. If it finds out
2046 that the file is missing, it will recreate it.
2047
2048 Continuously checking if the log file still exists is fairly expensive.
2049 For this reason it is only performed every 30 seconds. To change this
2050 interval, the option "recreate_check_interval" can be set to the number
2051 of seconds between checks. In the extreme case where the check should
2052 be performed before every write, it can even be set to 0:
2053
2054 log4perl.appender.Logfile.recreate = 1
2055 log4perl.appender.Logfile.recreate_check_interval = 0
2056
2057 To avoid having to check the file system so frequently, a signal
2058 handler can be set up:
2059
2060 log4perl.appender.Logfile.recreate = 1
2061 log4perl.appender.Logfile.recreate_check_signal = USR1
2062
2063 This will install a signal handler which will recreate a missing log
2064 file immediately when it receives the defined signal.
2065
2066 Note that the init_and_watch() method for Log4perl's initialization can
2067 also be instructed to install a signal handler, usually using the HUP
2068 signal. Make sure to use a different signal if you're using both of
2069 them at the same time.
2070
2071 How can I rotate a logfile with newsyslog?
2072 Here's a few things that need to be taken care of when using the
2073 popular log file rotating utility "newsyslog"
2074 (http://www.courtesan.com/newsyslog) with Log4perl's file appender in
2075 long-running processes.
2076
2077 For example, with a newsyslog configuration like
2078
2079 # newsyslog.conf
2080 /tmp/test.log 666 12 5 * B
2081
2082 and a call to
2083
2084 # newsyslog -f /path/to/newsyslog.conf
2085
2086 "newsyslog" will take action if "/tmp/test.log" is larger than the
2087 specified 5K in size. It will move the current log file "/tmp/test.log"
2088 to "/tmp/test.log.0" and create a new and empty "/tmp/test.log" with
2089 the specified permissions (this is why "newsyslog" needs to run as
2090 root). An already existing "/tmp/test.log.0" would be moved to
2091 "/tmp/test.log.1", "/tmp/test.log.1" to "/tmp/test.log.2", and so
2092 forth, for every one of a max number of 12 archived logfiles that have
2093 been configured in "newsyslog.conf".
2094
2095 Although a new file has been created, from Log4perl's appender's point
2096 of view, this situation is identical to the one described in the
2097 previous FAQ entry, labeled "How can my file appender deal with
2098 disappearing log files".
2099
2100 To make sure that log messages are written to the new log file and not
2101 to an archived one or end up in nowhere land, the appender's "recreate"
2102 and "recreate_check_interval" have to be configured to deal with the
2103 'disappearing' log file.
2104
2105 The situation gets interesting when "newsyslog"'s option to compress
2106 archived log files is enabled. This causes the original log file not to
2107 be moved, but to disappear. If the file appender isn't configured to
2108 recreate the logfile in this situation, log messages will actually be
2109 lost without warning. This also applies for the short time frame of
2110 "recreate_check_interval" seconds in between the recreator's file
2111 checks.
2112
2113 To make sure that no messages get lost, one option is to set the
2114 interval to
2115
2116 log4perl.appender.Logfile.recreate_check_interval = 0
2117
2118 However, this is fairly expensive. A better approach is to define a
2119 signal handler:
2120
2121 log4perl.appender.Logfile.recreate = 1
2122 log4perl.appender.Logfile.recreate_check_signal = USR1
2123 log4perl.appender.Logfile.recreate_pid_write = /tmp/myappid
2124
2125 As a service for "newsyslog" users, Log4perl's file appender writes the
2126 current process ID to a PID file specified by the "recreate_pid_write"
2127 option. "newsyslog" then needs to be configured as in
2128
2129 # newsyslog.conf configuration for compressing archive files and
2130 # sending a signal to the Log4perl-enabled application
2131 /tmp/test.log 666 12 5 * B /tmp/myappid 30
2132
2133 to send the defined signal (30, which is USR1 on FreeBSD) to the
2134 application process at rotation time. Note that the signal number is
2135 different on Linux, where USR1 denotes as 10. Check "man signal" for
2136 details.
2137
2138 How can a process under user id A log to a file under user id B?
2139 This scenario often occurs in configurations where processes run under
2140 various user IDs but need to write to a log file under a fixed, but
2141 different user id.
2142
2143 With a traditional file appender, the log file will probably be created
2144 under one user's id and appended to under a different user's id. With a
2145 typical umask of 0002, the file will be created with -rw-rw-r--
2146 permissions. If a user who's not in the first user's group subsequently
2147 appends to the log file, it will fail because of a permission problem.
2148
2149 Two potential solutions come to mind:
2150
2151 • Creating the file with a umask of 0000 will allow all users to
2152 append to the log file. Log4perl's file appender
2153 "Log::Log4perl::Appender::File" has an "umask" option that can be
2154 set to support this:
2155
2156 log4perl.appender.File = Log::Log4perl::Appender::File
2157 log4perl.appender.File.umask = sub { 0000 };
2158
2159 This way, the log file will be created with -rw-rw-rw- permissions
2160 and therefore has world write permissions. This might open up the
2161 logfile for unwanted manipulations by arbitrary users, though.
2162
2163 • Running the process under an effective user id of "root" will allow
2164 it to write to the log file, no matter who started the process.
2165 However, this is not a good idea, because of security concerns.
2166
2167 Luckily, under Unix, there's the syslog daemon which runs as root and
2168 takes log requests from user processes over a socket and writes them to
2169 log files as configured in "/etc/syslog.conf".
2170
2171 By modifying "/etc/syslog.conf" and HUPing the syslog daemon, you can
2172 configure new log files:
2173
2174 # /etc/syslog.conf
2175 ...
2176 user.* /some/path/file.log
2177
2178 Using the "Log::Dispatch::Syslog" appender, which comes with the
2179 "Log::Log4perl" distribution, you can then send messages via syslog:
2180
2181 use Log::Log4perl qw(:easy);
2182
2183 Log::Log4perl->init(\<<EOT);
2184 log4perl.logger = DEBUG, app
2185 log4perl.appender.app=Log::Dispatch::Syslog
2186 log4perl.appender.app.Facility=user
2187 log4perl.appender.app.layout=SimpleLayout
2188 EOT
2189
2190 # Writes to /some/path/file.log
2191 ERROR "Message!";
2192
2193 This way, the syslog daemon will solve the permission problem.
2194
2195 Note that while it is possible to use syslog() without Log4perl (syslog
2196 supports log levels, too), traditional syslog setups have a significant
2197 drawback.
2198
2199 Without Log4perl's ability to activate logging in only specific parts
2200 of a system, complex systems will trigger log events all over the place
2201 and slow down execution to a crawl at high debug levels.
2202
2203 Remote-controlling logging in the hierarchical parts of an application
2204 via Log4perl's categories is one of its most distinguished features.
2205 It allows for enabling high debug levels in specified areas without
2206 noticeable performance impact.
2207
2208 I want to use UTC instead of the local time!
2209 If a layout defines a date, Log::Log4perl uses local time to populate
2210 it. If you want UTC instead, set
2211
2212 log4perl.utcDateTimes = 1
2213
2214 in your configuration. Alternatively, you can set
2215
2216 $Log::Log4perl::DateFormat::GMTIME = 1;
2217
2218 in your program before the first log statement.
2219
2220 Can Log4perl intercept messages written to a filehandle?
2221 You have a function that prints to a filehandle. You want to tie into
2222 that filehandle and forward all arriving messages to a Log4perl logger.
2223
2224 First, let's write a package that ties a file handle and forwards it to
2225 a Log4perl logger:
2226
2227 package FileHandleLogger;
2228 use Log::Log4perl qw(:levels get_logger);
2229
2230 sub TIEHANDLE {
2231 my($class, %options) = @_;
2232
2233 my $self = {
2234 level => $DEBUG,
2235 category => '',
2236 %options
2237 };
2238
2239 $self->{logger} = get_logger($self->{category}),
2240 bless $self, $class;
2241 }
2242
2243 sub PRINT {
2244 my($self, @rest) = @_;
2245 $Log::Log4perl::caller_depth++;
2246 $self->{logger}->log($self->{level}, @rest);
2247 $Log::Log4perl::caller_depth--;
2248 }
2249
2250 sub PRINTF {
2251 my($self, $fmt, @rest) = @_;
2252 $Log::Log4perl::caller_depth++;
2253 $self->PRINT(sprintf($fmt, @rest));
2254 $Log::Log4perl::caller_depth--;
2255 }
2256
2257 1;
2258
2259 Now, if you have a function like
2260
2261 sub function_printing_to_fh {
2262 my($fh) = @_;
2263 printf $fh "Hi there!\n";
2264 }
2265
2266 which takes a filehandle and prints something to it, it can be used
2267 with Log4perl:
2268
2269 use Log::Log4perl qw(:easy);
2270 usa FileHandleLogger;
2271
2272 Log::Log4perl->easy_init($DEBUG);
2273
2274 tie *SOMEHANDLE, 'FileHandleLogger' or
2275 die "tie failed ($!)";
2276
2277 function_printing_to_fh(*SOMEHANDLE);
2278 # prints "2007/03/22 21:43:30 Hi there!"
2279
2280 If you want, you can even specify a different log level or category:
2281
2282 tie *SOMEHANDLE, 'FileHandleLogger',
2283 level => $INFO, category => "Foo::Bar" or die "tie failed ($!)";
2284
2285 I want multiline messages rendered line-by-line!
2286 With the standard "PatternLayout", if you send a multiline message to
2287 an appender as in
2288
2289 use Log::Log4perl qw(:easy);
2290 Log
2291
2292 it gets rendered this way:
2293
2294 2007/04/04 23:23:39 multi
2295 line
2296 message
2297
2298 If you want each line to be rendered separately according to the layout
2299 use "Log::Log4perl::Layout::PatternLayout::Multiline":
2300
2301 use Log::Log4perl qw(:easy);
2302
2303 Log::Log4perl->init(\<<EOT);
2304 log4perl.category = DEBUG, Screen
2305 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
2306 log4perl.appender.Screen.layout = \\
2307 Log::Log4perl::Layout::PatternLayout::Multiline
2308 log4perl.appender.Screen.layout.ConversionPattern = %d %m %n
2309 EOT
2310
2311 DEBUG "some\nmultiline\nmessage";
2312
2313 and you'll get
2314
2315 2007/04/04 23:23:39 some
2316 2007/04/04 23:23:39 multiline
2317 2007/04/04 23:23:39 message
2318
2319 instead.
2320
2321 I'm on Windows and I'm getting all these 'redefined' messages!
2322 If you're on Windows and are getting warning messages like
2323
2324 Constant subroutine Log::Log4perl::_INTERNAL_DEBUG redefined at
2325 C:/Programme/Perl/lib/constant.pm line 103.
2326 Subroutine import redefined at
2327 C:/Programme/Perl/site/lib/Log/Log4Perl.pm line 69.
2328 Subroutine initialized redefined at
2329 C:/Programme/Perl/site/lib/Log/Log4Perl.pm line 207.
2330
2331 then chances are that you're using 'Log::Log4Perl' (wrong uppercase P)
2332 instead of the correct 'Log::Log4perl'. Perl on Windows doesn't handle
2333 this error well and spits out a slew of confusing warning messages. But
2334 now you know, just use the correct module name and you'll be fine.
2335
2336 Log4perl complains that no initialization happened during shutdown!
2337 If you're using Log4perl log commands in DESTROY methods of your
2338 objects, you might see confusing messages like
2339
2340 Log4perl: Seems like no initialization happened. Forgot to call init()?
2341 Use of uninitialized value in subroutine entry at
2342 /home/y/lib/perl5/site_perl/5.6.1/Log/Log4perl.pm line 134 during global
2343 destruction. (in cleanup) Undefined subroutine &main:: called at
2344 /home/y/lib/perl5/site_perl/5.6.1/Log/Log4perl.pm line 134 during global
2345 destruction.
2346
2347 when the program shuts down. What's going on?
2348
2349 This phenomenon happens if you have circular references in your
2350 objects, which perl can't clean up when an object goes out of scope but
2351 waits until global destruction instead. At this time, however, Log4perl
2352 has already shut down, so you can't use it anymore.
2353
2354 For example, here's a simple class which uses a logger in its DESTROY
2355 method:
2356
2357 package A;
2358 use Log::Log4perl qw(:easy);
2359 sub new { bless {}, shift }
2360 sub DESTROY { DEBUG "Waaah!"; }
2361
2362 Now, if the main program creates a self-referencing object, like in
2363
2364 package main;
2365 use Log::Log4perl qw(:easy);
2366 Log::Log4perl->easy_init($DEBUG);
2367
2368 my $a = A->new();
2369 $a->{selfref} = $a;
2370
2371 then you'll see the error message shown above during global
2372 destruction. How to tackle this problem?
2373
2374 First, you should clean up your circular references before global
2375 destruction. They will not only cause objects to be destroyed in an
2376 order that's hard to predict, but also eat up memory until the program
2377 shuts down.
2378
2379 So, the program above could easily be fixed by putting
2380
2381 $a->{selfref} = undef;
2382
2383 at the end or in an END handler. If that's hard to do, use weak
2384 references:
2385
2386 package main;
2387 use Scalar::Util qw(weaken);
2388 use Log::Log4perl qw(:easy);
2389 Log::Log4perl->easy_init($DEBUG);
2390
2391 my $a = A->new();
2392 $a->{selfref} = weaken $a;
2393
2394 This allows perl to clean up the circular reference when the object
2395 goes out of scope, and doesn't wait until global destruction.
2396
2397 How can I access POE heap values from Log4perl's layout?
2398 POE is a framework for creating multitasked applications running in a
2399 single process and a single thread. POE's threads equivalents are
2400 'sessions' and since they run quasi-simultaneously, you can't use
2401 Log4perl's global NDC/MDC to hold session-specific data.
2402
2403 However, POE already maintains a data store for every session. It is
2404 called 'heap' and is just a hash storing session-specific data in key-
2405 value pairs. To access this per-session heap data from a Log4perl
2406 layout, define a custom cspec and reference it with the newly defined
2407 pattern in the layout:
2408
2409 use strict;
2410 use POE;
2411 use Log::Log4perl qw(:easy);
2412
2413 Log::Log4perl->init( \ q{
2414 log4perl.logger = DEBUG, Screen
2415 log4perl.appender.Screen = Log::Log4perl::Appender::Screen
2416 log4perl.appender.Screen.layout = PatternLayout
2417 log4perl.appender.Screen.layout.ConversionPattern = %U %m%n
2418 log4perl.PatternLayout.cspec.U = \
2419 sub { POE::Kernel->get_active_session->get_heap()->{ user } }
2420 } );
2421
2422 for (qw( Huey Lewey Dewey )) {
2423 POE::Session->create(
2424 inline_states => {
2425 _start => sub {
2426 $_[HEAP]->{user} = $_;
2427 POE::Kernel->yield('hello');
2428 },
2429 hello => sub {
2430 DEBUG "I'm here now";
2431 }
2432 }
2433 );
2434 }
2435
2436 POE::Kernel->run();
2437 exit;
2438
2439 The code snippet above defines a new layout placeholder (called 'cspec'
2440 in Log4perl) %U which calls a subroutine, retrieves the active session,
2441 gets its heap and looks up the entry specified ('user').
2442
2443 Starting with Log::Log4perl 1.20, cspecs also support parameters in
2444 curly braces, so you can say
2445
2446 log4perl.appender.Screen.layout.ConversionPattern = %U{user} %U{id} %m%n
2447 log4perl.PatternLayout.cspec.U = \
2448 sub { POE::Kernel->get_active_session-> \
2449 get_heap()->{ $_[0]->{curlies} } }
2450
2451 and print the POE session heap entries 'user' and 'id' with every
2452 logged message. For more details on cpecs, read the PatternLayout
2453 manual.
2454
2455 I want to print something unconditionally!
2456 Sometimes it's a script that's supposed to log messages regardless if
2457 Log4perl has been initialized or not. Or there's a logging statement
2458 that's not going to be suppressed under any circumstances -- many
2459 people want to have the final word, make the executive decision,
2460 because it seems like the only logical choice.
2461
2462 But think about it: First off, if a messages is supposed to be printed,
2463 where is it supposed to end up at? STDOUT? STDERR? And are you sure you
2464 want to set in stone that this message needs to be printed, while
2465 someone else might find it annoying and wants to get rid of it?
2466
2467 The truth is, there's always going to be someone who wants to log a
2468 messages at all cost, but also another person who wants to suppress it
2469 with equal vigilance. There's no good way to serve these two
2470 conflicting desires, someone will always want to win at the cost of
2471 leaving the other party disappointed.
2472
2473 So, the best Log4perl offers is the ALWAYS level for a message that
2474 even fires if the system log level is set to $OFF:
2475
2476 use Log::Log4perl qw(:easy);
2477
2478 Log::Log4perl->easy_init( $OFF );
2479 ALWAYS "This gets logged always. Well, almost always";
2480
2481 The logger won't fire, though, if Log4perl hasn't been initialized or
2482 if someone defines a custom log hurdle that's higher than $OFF.
2483
2484 Bottom line: Leave the setting of the logging level to the initial Perl
2485 script -- let their owners decided what they want, no matter how
2486 tempting it may be to decide it for them.
2487
2488 Why doesn't my END handler remove my log file on Win32?
2489 If you have code like
2490
2491 use Log::Log4perl qw( :easy );
2492 Log::Log4perl->easy_init( { level => $DEBUG, file => "my.log" } );
2493 END { unlink "my.log" or die };
2494
2495 then you might be in for a surprise when you're running it on Windows,
2496 because the unlink() call in the END handler will complain that the
2497 file is still in use.
2498
2499 What happens in Perl if you have something like
2500
2501 END { print "first end in main\n"; }
2502 use Module;
2503 END { print "second end in main\n"; }
2504
2505 and
2506
2507 package Module;
2508 END { print "end in module\n"; }
2509 1;
2510
2511 is that you get
2512
2513 second end in main
2514 end in module
2515 first end in main
2516
2517 because perl stacks the END handlers in reverse order in which it
2518 encounters them in the compile phase.
2519
2520 Log4perl defines an END handler that cleans up left-over appenders
2521 (e.g. file appenders which still hold files open), because those
2522 appenders have circular references and therefore aren't cleaned up
2523 otherwise.
2524
2525 Now if you define an END handler after "use Log::Log4perl", it'll
2526 trigger before Log4perl gets a chance to clean up, which isn't a
2527 problem on Unix where you can delete a file even if some process has a
2528 handle to it open, but it's a problem on Win32, where the OS won't let
2529 you do that.
2530
2531 The solution is easy, just place the END handler before Log4perl gets
2532 loaded, like in
2533
2534 END { unlink "my.log" or die };
2535 use Log::Log4perl qw( :easy );
2536 Log::Log4perl->easy_init( { level => $DEBUG, file => "my.log" } );
2537
2538 which will call the END handlers in the intended order.
2539
2541 Log::Log4perl
2542
2544 Copyright 2002-2013 by Mike Schilli <m@perlmeister.com> and Kevin Goess
2545 <cpan@goess.org>.
2546
2547 This library is free software; you can redistribute it and/or modify it
2548 under the same terms as Perl itself.
2549
2551 Please contribute patches to the project on Github:
2552
2553 http://github.com/mschilli/log4perl
2554
2555 Send bug reports or requests for enhancements to the authors via our
2556
2557 MAILING LIST (questions, bug reports, suggestions/patches):
2558 log4perl-devel@lists.sourceforge.net
2559
2560 Authors (please contact them via the list above, not directly): Mike
2561 Schilli <m@perlmeister.com>, Kevin Goess <cpan@goess.org>
2562
2563 Contributors (in alphabetical order): Ateeq Altaf, Cory Bennett, Jens
2564 Berthold, Jeremy Bopp, Hutton Davidson, Chris R. Donnelly, Matisse
2565 Enzer, Hugh Esco, Anthony Foiani, James FitzGibbon, Carl Franks, Dennis
2566 Gregorovic, Andy Grundman, Paul Harrington, Alexander Hartmaier David
2567 Hull, Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter,
2568 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, Lars
2569 Thegler, David Viner, Mac Yang.
2570
2571
2572
2573perl v5.36.0 2023-01-20 FAQ(3)