Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
FAQ(3)		      User Contributed Perl Documentation		FAQ(3)

NAME
       Log::Log4perl::FAQ - Frequently Asked Questions on Log::Log4perl

DESCRIPTION
       This FAQ	shows a	wide variety of	commonly encountered logging tasks and
       how to solve them in the	most elegant way with Log::Log4perl. Most of
       the time, this will be just a matter of smartly configuring your
       Log::Log4perl configuration files.

   Why use Log::Log4perl instead of any	other logging module on	CPAN?
       That's a	good question. There's dozens of logging modules on CPAN.
       When it comes to	logging, people	typically think: "Aha. Writing out
       debug and error messages. Debug is lower	than error. Easy. I'm gonna
       write my	own." Writing a	logging	module is like a rite of passage for
       every Perl programmer, just like	writing	your own templating system.

       Of course, after	getting	the basics right, features need	to be added.
       You'd like to write a timestamp with every message. Then	timestamps
       with microseconds. Then messages	need to	be written to both the screen
       and a log file.

       And, as your application	grows in size you might	wonder:	Why doesn't my
       logging system scale along with it? You would like to switch on logging
       in selected parts of the	application, and not all across	the board,
       because this kills performance. This is when people turn	to
       Log::Log4perl, because it handles all of	that.

       Avoid this costly switch.

       Use "Log::Log4perl" right from the start. "Log::Log4perl"'s ":easy"
       mode supports easy logging in simple scripts:

	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

	   DEBUG "A low-level message";
	   ERROR "Won't	make it	until level gets increased to ERROR";

       And when	your application inevitably grows, your	logging	system grows
       with it without you having to change any	code.

       Please, don't re-invent logging.	"Log::Log4perl"	is here, it's easy to
       use, it scales, and covers many areas you haven't thought of yet, but
       will enter soon.

   What's the easiest way to use Log4perl?
       If you just want	to get all the comfort of logging, without much
       overhead, use Stealth Loggers. If you use Log::Log4perl in ":easy" mode
       like

	   use Log::Log4perl qw(:easy);

       you'll have the following functions available in	the current package:

	   DEBUG("message");
	   INFO("message");
	   WARN("message");
	   ERROR("message");
	   FATAL("message");

       Just make sure that every package of your code where you're using them
       in pulls	in "use	Log::Log4perl qw(:easy)" first,	then you're set.
       Every stealth logger's category will be equivalent to the name of the
       package it's located in.

       These stealth loggers will be absolutely	silent until you initialize
       Log::Log4perl in	your main program with either

	       # Define	any Log4perl behavior
	   Log::Log4perl->init("foo.conf");

       (using a	full-blown Log4perl config file) or the	super-easy method

	       # Just log to STDERR
	   Log::Log4perl->easy_init($DEBUG);

       or the parameter-style method with a complexity somewhat	in between:

	       # Append	to a log file
	   Log::Log4perl->easy_init( { level   => $DEBUG,
				       file    => ">>test.log" } );

       For more	info, please check out "Stealth	Loggers" in Log::Log4perl.

   How can I simply log	all my ERROR messages to a file?
       After pulling in	the "Log::Log4perl" module, just initialize its
       behavior	by passing in a	configuration to its "init" method as a	string
       reference. Then,	obtain a logger	instance and write out a message with
       its "error()" method:

	   use Log::Log4perl qw(get_logger);

	       # Define	configuration
	   my $conf = q(
	       log4perl.logger			  = ERROR, FileApp
	       log4perl.appender.FileApp	  = Log::Log4perl::Appender::File
	       log4perl.appender.FileApp.filename = test.log
	       log4perl.appender.FileApp.layout	  = PatternLayout
	       log4perl.appender.FileApp.layout.ConversionPattern = %d>	%m%n
	   );

	       # Initialize logging behavior
	   Log::Log4perl->init(	\$conf );

	       # Obtain	a logger instance
	   my $logger =	get_logger("Bar::Twix");
	   $logger->error("Oh my, a dreadful error!");
	   $logger->warn("Oh my, a dreadful warning!");

       This will append	something like

	   2002/10/29 20:11:55>	Oh my, a dreadful error!

       to the log file "test.log". How does this all work?

       While the Log::Log4perl "init()"	method typically takes the name	of a
       configuration file as its input parameter like in

	   Log::Log4perl->init(	"/path/mylog.conf" );

       the example above shows how to pass in a	configuration as text in a
       scalar reference.

       The configuration as shown defines a logger of the root category, which
       has an appender of type "Log::Log4perl::Appender::File" attached. The
       line

	   log4perl.logger = ERROR, FileApp

       doesn't list a category,	defining a root	logger.	Compare	that with

	   log4perl.logger.Bar.Twix = ERROR, FileApp

       which would define a logger for the category "Bar::Twix", showing
       probably	different behavior. "FileApp" on the right side	of the
       assignment is an	arbitrarily defined variable name, which is only used
       to somehow reference an appender	defined	later on.

       Appender	settings in the	configuration are defined as follows:

	   log4perl.appender.FileApp	      =	Log::Log4perl::Appender::File
	   log4perl.appender.FileApp.filename =	test.log

       It selects the file appender of the "Log::Log4perl::Appender"
       hierarchy, which	will append to the file	"test.log" if it already
       exists. If we wanted to overwrite a potentially existing	file, we would
       have to explicitly set the appropriate "Log::Log4perl::Appender::File"
       parameter "mode":

	   log4perl.appender.FileApp	      =	Log::Log4perl::Appender::File
	   log4perl.appender.FileApp.filename =	test.log
	   log4perl.appender.FileApp.mode     =	write

       Also, the configuration defines a PatternLayout format, adding the
       nicely formatted	current	date and time, an arrow	(>) and	a space	before
       the messages, which is then followed by a newline:

	   log4perl.appender.FileApp.layout   =	PatternLayout
	   log4perl.appender.FileApp.layout.ConversionPattern =	%d> %m%n

       Obtaining a logger instance and actually	logging	something is typically
       done in a different system part as the Log::Log4perl initialisation
       section,	but in this example, it's just done right after	init for the
       sake of compactness:

	       # Obtain	a logger instance
	   my $logger =	get_logger("Bar::Twix");
	   $logger->error("Oh my, a dreadful error!");

       This retrieves an instance of the logger	of the category	"Bar::Twix",
       which, as all other categories, inherits	behavior from the root logger
       if no other loggers are defined in the initialization section.

       The "error()" method fires up a message,	which the root logger catches.
       Its priority is equal to	or higher than the root	logger's priority
       (ERROR),	which causes the root logger to	forward	it to its attached
       appender. By contrast, the following

	   $logger->warn("Oh my, a dreadful warning!");

       doesn't make it through,	because	the root logger	sports a higher
       setting (ERROR and up) than the WARN priority of	the message.

   How can I install Log::Log4perl on Microsoft	Windows?
       You can install Log::Log4perl using the CPAN client.

       Alternatively you can install it	using

	   ppm install Log-Log4perl

       if you're using ActiveState perl.

       That's it! Afterwards, just create a Perl script	like

	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

	   my $logger =	get_logger("Twix::Bar");
	   $logger->debug("Watch me!");

       and run it. It should print something like

	   2002/11/06 01:22:05 Watch me!

       If you find that	something doesn't work,	please let us know at
       log4perl-devel@lists.sourceforge.net -- we'll appreciate	it. Have fun!

   How can I include global (thread-specific) data in my log messages?
       Say, you're writing a web application and want all your log messages to
       include the current client's IP address.	Most certainly,	you don't want
       to include it in	each and every log message like	in

	   $logger->debug( $r->connection->remote_ip,
			   " Retrieving	user data from DB" );

       do you? Instead,	you want to set	it in a	global data structure and have
       Log::Log4perl include it	automatically via a PatternLayout setting in
       the configuration file:

	   log4perl.appender.FileApp.layout.ConversionPattern =	%X{ip} %m%n

       The conversion specifier	%X{ip} references an entry under the key "ip"
       in the global "MDC" (mapped diagnostic context) table, which you've set
       once via

	   Log::Log4perl::MDC->put("ip", $r->connection->remote_ip);

       at the start of the request handler. Note that this is a	static (class)
       method, there's no logger object	involved.  You can use this method
       with as many key/value pairs as you like	as long	as you reference them
       under different names.

       The mappings are	stored in a global hash	table within Log::Log4perl.
       Luckily,	because	the thread model in 5.8.0 doesn't share	global
       variables between threads unless	they're	explicitly marked as such,
       there's no problem with multi-threaded environments.

       For more	details	on the MDC, please refer to "Mapped Diagnostic Context
       (MDC)" in Log::Log4perl and Log::Log4perl::MDC.

   My application is already logging to	a file.	How can	I duplicate all
       messages	to also	go to the screen?
       Assuming	that you already have a	Log4perl configuration file like

	   log4perl.logger		      =	DEBUG, FileApp

	   log4perl.appender.FileApp	      =	Log::Log4perl::Appender::File
	   log4perl.appender.FileApp.filename =	test.log
	   log4perl.appender.FileApp.layout   =	PatternLayout
	   log4perl.appender.FileApp.layout.ConversionPattern =	%d> %m%n

       and log statements all over your	code, it's very	easy with Log4perl to
       have the	same messages both printed to the logfile and the screen. No
       reason to change	your code, of course, just add another appender	to the
       configuration file and you're done:

	   log4perl.logger		      =	DEBUG, FileApp,	ScreenApp

	   log4perl.appender.FileApp	      =	Log::Log4perl::Appender::File
	   log4perl.appender.FileApp.filename =	test.log
	   log4perl.appender.FileApp.layout   =	PatternLayout
	   log4perl.appender.FileApp.layout.ConversionPattern =	%d> %m%n

	   log4perl.appender.ScreenApp		= Log::Log4perl::Appender::Screen
	   log4perl.appender.ScreenApp.stderr	= 0
	   log4perl.appender.ScreenApp.layout	= PatternLayout
	   log4perl.appender.ScreenApp.layout.ConversionPattern	= %d> %m%n

       The configuration file above is assuming	that both appenders are	active
       in the same logger hierarchy, in	this case the "root" category.	But
       even if you've got file loggers defined in several parts	of your
       system, belonging to different logger categories, each logging to
       different files,	you can	gobble up all logged messages by defining a
       root logger with	a screen appender, which would duplicate messages from
       all your	file loggers to	the screen due to Log4perl's appender
       inheritance. Check

	   http://www.perl.com/pub/a/2002/09/11/log4perl.html

       for details. Have fun!

   How can I make sure my application logs a message when it dies
       unexpectedly?
       Whenever	you encounter a	fatal error in your application, instead of
       saying something	like

	   open	FILE, "<blah" or die "Can't open blah -- bailing out!";

       just use	Log::Log4perl's	fatal functions	instead:

	   my $log = get_logger("Some::Package");
	   open	FILE, "<blah" or $log->logdie("Can't open blah -- bailing out!");

       This will both log the message with priority FATAL according to your
       current Log::Log4perl configuration and then call Perl's	"die()"
       afterwards to terminate the program. It works the same with stealth
       loggers (see "Stealth Loggers" in Log::Log4perl), all you need to do is
       call

	   use Log::Log4perl qw(:easy);
	   open	FILE, "<blah" or LOGDIE	"Can't open blah -- bailing out!";

       What can	you do if you're using some library which doesn't use
       Log::Log4perl and calls "die()" internally if something goes wrong? Use
       a $SIG{__DIE__} pseudo signal handler

	   use Log::Log4perl qw(get_logger);

	   $SIG{__DIE__} = sub {
	       if($^S) {
		   # We're in an eval {} and don't want	log
		   # this message but catch it later
		   return;
	       }
	       local $Log::Log4perl::caller_depth =
		     $Log::Log4perl::caller_depth + 1;
	       my $logger = get_logger("");
	       $logger->fatal(@_);
	       die @_; # Now terminate really
	   };

       This will catch every "die()"-Exception of your application or the
       modules it uses.	In case	you want to It will fetch a root logger	and
       pass on the "die()"-Message to it.  If you make sure you've configured
       with a root logger like this:

	   Log::Log4perl->init(\q{
	       log4perl.category	 = FATAL, Logfile
	       log4perl.appender.Logfile = Log::Log4perl::Appender::File
	       log4perl.appender.Logfile.filename = fatal_errors.log
	       log4perl.appender.Logfile.layout	= \
			  Log::Log4perl::Layout::PatternLayout
	       log4perl.appender.Logfile.layout.ConversionPattern = %F{1}-%L (%M)> %m%n
	   });

       then all	"die()"	messages will be routed	to a file properly. The	line

	    local $Log::Log4perl::caller_depth =
		  $Log::Log4perl::caller_depth + 1;

       in the pseudo signal handler above merits a more	detailed explanation.
       With the	setup above, if	a module calls "die()" in one of its
       functions, the fatal message will be logged in the signal handler and
       not in the original function -- which will cause	the %F,	%L and %M
       placeholders in the pattern layout to be	replaced by the	filename, the
       line number and the function/method name	of the signal handler, not the
       error-throwing module. To adjust	this, Log::Log4perl has	the
       $caller_depth variable, which defaults to 0, but	can be set to positive
       integer values to offset	the caller level. Increasing it	by one will
       cause it	to log the calling function's parameters, not the ones of the
       signal handler.	See "Using Log::Log4perl from wrapper classes" in
       Log::Log4perl for more details.

   How can I hook up the LWP library with Log::Log4perl?
       Or, to put it more generally: How can you utilize a third-party
       library's embedded logging and debug statements in Log::Log4perl?  How
       can you make them print to configurable appenders, turn them on and
       off, just as if they were regular Log::Log4perl logging statements?

       The easiest solution is to map the third-party library logging
       statements to Log::Log4perl's stealth loggers via a typeglob
       assignment.

       As an example, let's take LWP, one of the most popular Perl modules,
       which makes handling WWW	requests and responses a breeze.  Internally,
       LWP uses	its own	logging	and debugging system, utilizing	the following
       calls inside the	LWP code (from the LWP::Debug man page):

	       # Function tracing
	   LWP::Debug::trace('send()');

	       # High-granular state in	functions
	   LWP::Debug::debug('url ok');

	       # Data going over the wire
	   LWP::Debug::conns("read $n bytes: $data");

       First, let's assign Log::Log4perl priorities to these functions:	I'd
       suggest that "debug()" messages have priority "INFO", "trace()" uses
       "DEBUG" and "conns()" also logs with "DEBUG" -- although	your mileage
       may certainly vary.

       Now, in order to	transparently hook up LWP::Debug with Log::Log4perl,
       all we have to do is say

	   package LWP::Debug;
	   use Log::Log4perl qw(:easy);

	   *trace = *INFO;
	   *conns = *DEBUG;
	   *debug = *DEBUG;

	   package main;
	   # ... go on with your regular program ...

       at the beginning	of our program.	In this	way, every time	the, say,
       "LWP::UserAgent"	module calls "LWP::Debug::trace()", it will implicitly
       call INFO(), which is the "info()" method of a stealth logger defined
       for the Log::Log4perl category "LWP::Debug". Is this cool or what?

       Here's a	complete program:

	   use LWP::UserAgent;
	   use HTTP::Request::Common;
	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->easy_init(
	       { category => "LWP::Debug",
		 level	  => $DEBUG,
		 layout	  => "%r %p %M-%L %m%n",
	       });

	   package LWP::Debug;
	   use Log::Log4perl qw(:easy);
	   *trace = *INFO;
	   *conns = *DEBUG;
	   *debug = *DEBUG;

	   package main;
	   my $ua = LWP::UserAgent->new();
	   my $resp = $ua->request(GET "http://amazon.com");

	   if($resp->is_success()) {
	       print "Success: Received	",
		     length($resp->content()), "\n";
	   } else {
	       print "Error: ",	$resp->code(), "\n";
	   }

       This will generate the following	output on STDERR:

	   174 INFO LWP::UserAgent::new-164 ()
	   208 INFO LWP::UserAgent::request-436	()
	   211 INFO LWP::UserAgent::send_request-294 GET http://amazon.com
	   212 DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
	   405 INFO LWP::Protocol::http::request-122 ()
	   859 DEBUG LWP::Protocol::collect-206	read 233 bytes
	   863 DEBUG LWP::UserAgent::request-443 Simple	response: Found
	   869 INFO LWP::UserAgent::request-436	()
	   871 INFO LWP::UserAgent::send_request-294
	    GET	http://www.amazon.com:80/exec/obidos/gateway_redirect
	   872 DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
	   873 INFO LWP::Protocol::http::request-122 ()
	   1016	DEBUG LWP::UserAgent::request-443 Simple response: Found
	   1020	INFO LWP::UserAgent::request-436 ()
	   1022	INFO LWP::UserAgent::send_request-294
	    GET	http://www.amazon.com/exec/obidos/subst/home/home.html/
	   1023	DEBUG LWP::UserAgent::_need_proxy-1123 Not proxied
	   1024	INFO LWP::Protocol::http::request-122 ()
	   1382	DEBUG LWP::Protocol::collect-206 read 632 bytes
	   ...
	   2605	DEBUG LWP::Protocol::collect-206 read 77 bytes
	   2607	DEBUG LWP::UserAgent::request-443 Simple response: OK
	   Success: Received 42584

       Of course, in this way, the embedded logging and	debug statements
       within LWP can be utilized in any Log::Log4perl way you can think of.
       You can have them sent to different appenders, block them based on the
       category	and everything else Log::Log4perl has to offer.

       Only drawback of	this method: Steering logging behavior via category is
       always based on the "LWP::Debug"	package. Although the logging
       statements reflect the package name of the issuing module properly, the
       stealth loggers in "LWP::Debug" are all of the category "LWP::Debug".
       This implies that you can't control the logging behavior	based on the
       package that's initiating a log request (e.g. LWP::UserAgent) but only
       based on	the package that's actually executing the logging statement,
       "LWP::Debug" in this case.

       To work around this conundrum, we need to write a wrapper function and
       plant it	into the "LWP::Debug" package. It will determine the caller
       and create a logger bound to a category with the	same name as the
       caller's	package:

	   package LWP::Debug;

	   use Log::Log4perl qw(:levels	get_logger);

	   sub l4p_wrapper {
	       my($prio, @message) = @_;
	       $Log::Log4perl::caller_depth += 2;
	       get_logger(scalar caller(1))->log($prio,	@message);
	       $Log::Log4perl::caller_depth -= 2;
	   }

	   no warnings 'redefine';
	   *trace = sub	{ l4p_wrapper($INFO, @_); };
	   *debug = *conns = sub { l4p_wrapper($DEBUG, @_); };

	   package main;
	   # ... go on with your main program ...

       This is less performant than the	previous approach, because every log
       request will request a reference	to a logger first, then	call the
       wrapper,	which will in turn call	the appropriate	log function.

       This hierarchy shift has	to be compensated for by increasing
       $Log::Log4perl::caller_depth by 2 before	calling	the log	function and
       decreasing it by	2 right	afterwards. Also, the "l4p_wrapper" function
       shown above calls caller(1) which determines the	name of	the package
       two levels down the calling hierarchy (and therefore compensates	for
       both the	wrapper	function and the anonymous subroutine calling it).

       "no warnings 'redefine'"	suppresses a warning Perl would	generate
       otherwise upon redefining "LWP::Debug"'s	"trace()", "debug()" and
       "conns()" functions. In case you	use a perl prior to 5.6.x, you need to
       manipulate $^W instead.

       To make things easy for you when	dealing	with LWP, Log::Log4perl	0.47
       introduces "Log::Log4perl->infiltrate_lwp()" which does exactly the
       above.

   What	if I need dynamic values in a static Log4perl configuration file?
       Say, your application uses Log::Log4perl	for logging and	therefore
       comes with a Log4perl configuration file, specifying the	logging
       behavior.  But, you also	want it	to take	command	line parameters	to set
       values like the name of the log file.  How can you have both a static
       Log4perl	configuration file and a dynamic command line interface?

       As of Log::Log4perl 0.28, every value in	the configuration file can be
       specified as a Perl hook. So, instead of	saying

	   log4perl.appender.Logfile.filename =	test.log

       you could just as well have a Perl subroutine deliver the value
       dynamically:

	   log4perl.appender.Logfile.filename =	sub { logfile(); };

       given that "logfile()" is a valid function in your "main" package
       returning a string containing the path to the log file.

       Or, think about using the value of an environment variable:

	   log4perl.appender.DBI.user =	sub { $ENV{USERNAME} };

       When "Log::Log4perl->init()" parses the configuration file, it will
       notice the assignment above because of its "sub {...}" pattern and
       treat it	in a special way: It will evaluate the subroutine (which can
       contain arbitrary Perl code) and	take its return	value as the right
       side of the assignment.

       A typical application would be called like this on the command line:

	   app		      #	log file is "test.log"
	   app -l mylog.txt   #	log file is "mylog.txt"

       Here's some sample code implementing the	command	line interface above:

	   use Log::Log4perl qw(get_logger);
	   use Getopt::Std;

	   getopt('l:',	\our %OPTS);

	   my $conf = q(
	   log4perl.category.Bar.Twix	      =	WARN, Logfile
	   log4perl.appender.Logfile	      =	Log::Log4perl::Appender::File
	   log4perl.appender.Logfile.filename =	sub { logfile(); };
	   log4perl.appender.Logfile.layout   =	SimpleLayout
	   );

	   Log::Log4perl::init(\$conf);

	   my $logger =	get_logger("Bar::Twix");
	   $logger->error("Blah");

	   ###########################################
	   sub logfile {
	   ###########################################
	       if(exists $OPTS{l}) {
		   return $OPTS{l};
	       } else {
		   return "test.log";
	       }
	   }

       Every Perl hook may contain arbitrary perl code,	just make sure to
       fully qualify eventual variable names (e.g. %main::OPTS instead of
       %OPTS).

       SECURITY	NOTE: this feature means arbitrary perl	code can be embedded
       in the config file.  In the rare	case where the people who have access
       to your config file are different from the people who write your	code
       and shouldn't have execute rights, you might want to call

	   $Log::Log4perl::Config->allow_code(0);

       before you call init(). This will prevent Log::Log4perl from executing
       any Perl	code in	the config file	(including code	for custom conversion
       specifiers (see "Custom cspecs" in
       Log::Log4perl::Layout::PatternLayout).

   How can I roll over my logfiles automatically at midnight?
       Long-running applications tend to produce ever-increasing logfiles.
       For backup and cleanup purposes,	however, it is often desirable to move
       the current logfile to a	different location from	time to	time and start
       writing a new one.

       This is a non-trivial task, because it has to happen in sync with the
       logging system in order not to lose any messages	in the process.

       Luckily,	Mark Pfeiffer's	"Log::Dispatch::FileRotate" appender works
       well with Log::Log4perl to rotate your logfiles in a variety of ways.

       Note, however, that having the application deal with rotating a log
       file is not cheap. Among	other things, it requires locking the log file
       with every write	to avoid race conditions.  There are good reasons to
       use external rotators like "newsyslog" instead.	See the	entry "How can
       I rotate	a logfile with newsyslog?" in the FAQ for more information on
       how to configure	it.

       When using "Log::Dispatch::FileRotate", all you have to do is specify
       it in your Log::Log4perl	configuration file and your logfiles will be
       rotated automatically.

       You can choose between rolling based on a maximum size ("roll if
       greater than 10 MB") or based on	a date pattern ("roll everyday at
       midnight").  In both cases, "Log::Dispatch::FileRotate" allows you to
       define a	number "max" of	saved files to keep around until it starts
       overwriting the oldest ones. If you set the "max" parameter to 2	and
       the name	of your	logfile	is "test.log", "Log::Dispatch::FileRotate"
       will move "test.log" to "test.log.1" on the first rollover. On the
       second rollover,	it will	move "test.log.1" to "test.log.2" and then
       "test.log" to "test.log.1". On the third	rollover, it will move
       "test.log.1" to "test.log.2" (therefore discarding the old
       "test.log.2") and "test.log" to "test.log.1". And so forth. This	way,
       there's always going to be a maximum of 2 saved log files around.

       Here's an example of a Log::Log4perl configuration file,	defining a
       daily rollover at midnight (date	pattern	"yyyy-MM-dd"), keeping a
       maximum of 5 saved logfiles around:

	   log4perl.category	     = WARN, Logfile
	   log4perl.appender.Logfile = Log::Dispatch::FileRotate
	   log4perl.appender.Logfile.filename	 = test.log
	   log4perl.appender.Logfile.max	 = 5
	   log4perl.appender.Logfile.DatePattern = yyyy-MM-dd
	   log4perl.appender.Logfile.TZ		 = PST
	   log4perl.appender.Logfile.layout = \
	       Log::Log4perl::Layout::PatternLayout
	   log4perl.appender.Logfile.layout.ConversionPattern =	%d %m %n

       Please see the "Log::Dispatch::FileRotate" documentation	for details.
       "Log::Dispatch::FileRotate" is available	on CPAN.

   What's the easiest way to turn off all logging, even	with a lengthy
       Log4perl	configuration file?
       In addition to category-based levels and	appender thresholds,
       Log::Log4perl supports system-wide logging thresholds. This is the
       minimum level the system	will require of	any logging events in order
       for them	to make	it through to any configured appenders.

       For example, putting the	line

	   log4perl.threshold =	ERROR

       anywhere	in your	configuration file will	limit any output to any
       appender	to events with priority	of ERROR or higher (ERROR or FATAL
       that is).

       However,	in order to suppress all logging entirely, you need to use a
       priority	that's higher than FATAL: It is	simply called "OFF", and it is
       never used by any logger. By definition,	it is higher than the highest
       defined logger level.

       Therefore, if you keep the line

	   log4perl.threshold =	OFF

       somewhere in your Log::Log4perl configuration, the system will be quiet
       as a graveyard. If you deactivate the line (e.g.	by commenting it out),
       the system will,	upon config reload, snap back to normal	operation,
       providing logging messages according to the rest	of the configuration
       file again.

   How can I log DEBUG and above to the	screen and INFO	and above to a file?
       You need	one logger with	two appenders attached to it:

	   log4perl.logger = DEBUG, Screen, File

	   log4perl.appender.Screen   =	Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen.layout = SimpleLayout

	   log4perl.appender.File   = Log::Log4perl::Appender::File
	   log4perl.appender.File.filename = test.log
	   log4perl.appender.File.layout = SimpleLayout
	   log4perl.appender.Screen.Threshold =	INFO

       Since the file logger isn't supposed to get any messages	with a
       priority	less than INFO,	the appender's "Threshold" setting blocks
       those out, although the logger forwards them.

       It's a common mistake to	think you can define two loggers for this, but
       it won't	work unless those two loggers have different categories. If
       you wanted to log all DEBUG and above messages from the Foo::Bar	module
       to a file and all INFO and above	messages from the Quack::Schmack
       module to the screen, then you could have defined two loggers with
       different levels	"log4perl.logger.Foo.Bar" (level INFO) and
       "log4perl.logger.Quack.Schmack" (level DEBUG) and assigned the file
       appender	to the former and the screen appender to the latter. But what
       we wanted to accomplish was to route all	messages, regardless of	which
       module (or category) they came from, to both appenders. The only	way to
       accomplish this is to define the	root logger with the lower level
       (DEBUG),	assign both appenders to it, and block unwanted	messages at
       the file	appender ("Threshold" set to INFO).

   I keep getting duplicate log	messages! What's wrong?
       Having several settings for related categories in the Log4perl
       configuration file sometimes leads to a phenomenon called "message
       duplication". It	can be very confusing at first,	but if thought through
       properly, it turns out that Log4perl behaves as advertised. But,	don't
       despair,	of course there's a number of ways to avoid message
       duplication in your logs.

       Here's a	sample Log4perl	configuration file that	produces the
       phenomenon:

	   log4perl.logger.Cat	      =	ERROR, Screen
	   log4perl.logger.Cat.Subcat =	WARN, Screen

	   log4perl.appender.Screen   =	Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen.layout = SimpleLayout

       It defines two loggers, one for category	"Cat" and one for
       "Cat::Subcat", which is obviously a subcategory of "Cat".  The parent
       logger has a priority setting of	ERROR, the child is set	to the lower
       "WARN" level.

       Now imagine the following code in your program:

	   my $logger =	get_logger("Cat.Subcat");
	   $logger->warn("Warning!");

       What do you think will happen? An unexperienced Log4perl	user might
       think: "Well, the message is being sent with level WARN,	so the
       "Cat::Subcat" logger will accept	it and forward it to the attached
       "Screen"	appender. Then,	the message will percolate up the logger
       hierarchy, find the "Cat" logger, which will suppress the message
       because of its ERROR setting."  But, perhaps surprisingly, what you'll
       get with	the code snippet above is not one but two log messages written
       to the screen:

	   WARN	- Warning!
	   WARN	- Warning!

       What happened? The culprit is that once the logger "Cat::Subcat"
       decides to fire,	it will	forward	the message unconditionally to all
       directly	or indirectly attached appenders. The "Cat" logger will	never
       be asked	if it wants the	message	or not -- the message will just	be
       pushed through to the appender attached to "Cat".

       One way to prevent the message from bubbling up the logger hierarchy is
       to set the "additivity" flag of the subordinate logger to 0:

	   log4perl.logger.Cat		  = ERROR, Screen
	   log4perl.logger.Cat.Subcat	  = WARN, Screen
	   log4perl.additivity.Cat.Subcat = 0

	   log4perl.appender.Screen   =	Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen.layout = SimpleLayout

       The message will	now be accepted	by the "Cat::Subcat" logger, forwarded
       to its appender,	but then "Cat::Subcat" will suppress any further
       action. While this setting avoids duplicate messages as seen before, it
       is often	not the	desired	behavior. Messages percolating up the
       hierarchy are a useful Log4perl feature.

       If you're defining different appenders for the two loggers, one other
       option is to define an appender threshold for the higher-level
       appender. Typically it is set to	be equal to the	logger's level
       setting:

	   log4perl.logger.Cat		 = ERROR, Screen1
	   log4perl.logger.Cat.Subcat	 = WARN, Screen2

	   log4perl.appender.Screen1   = Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen1.layout = SimpleLayout
	   log4perl.appender.Screen1.Threshold = ERROR

	   log4perl.appender.Screen2   = Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen2.layout = SimpleLayout

       Since the "Screen1" appender now	blocks every message with a priority
       less than ERROR,	even if	the logger in charge lets it through, the
       message percolating up the hierarchy is being blocked at	the last
       minute and not appended to "Screen1".

       So far, we've been operating well within	the boundaries of the Log4j
       standard, which Log4perl	adheres	to. However, if	you would really,
       really like to use a single appender and	keep the message percolation
       intact without having to	deal with message duplication, there's a non-
       standard	solution for you:

	   log4perl.logger.Cat	      =	ERROR, Screen
	   log4perl.logger.Cat.Subcat =	WARN, Screen

	   log4perl.appender.Screen   =	Log::Log4perl::Appender::Screen
	   log4perl.appender.Screen.layout = SimpleLayout

	   log4perl.oneMessagePerAppender = 1

       The "oneMessagePerAppender" flag	will suppress duplicate	messages to
       the same	appender. Again, that's	non-standard. But way cool :).

   How can I configure Log::Log4perl to	send me	email if something happens?
       Some incidents require immediate	action.	You can't wait until someone
       checks the log files, you need to get notified on your pager right
       away.

       The easiest way to do that is by	using the
       "Log::Dispatch::Email::MailSend"	module as an appender. It comes	with
       the "Log::Dispatch" bundle and allows you to specify recipient and
       subject of outgoing emails in the Log4perl configuration	file:

	   log4perl.category = FATAL, Mailer
	   log4perl.appender.Mailer	    = Log::Dispatch::Email::MailSend
	   log4perl.appender.Mailer.to	    = drone@pageme.net
	   log4perl.appender.Mailer.subject = Something's broken!
	   log4perl.appender.Mailer.layout  = SimpleLayout

       The message of every log	incident this appender gets will then be
       forwarded to the	given email address. Check the
       "Log::Dispatch::Email::MailSend"	documentation for details. And please
       make sure there's not a flood of	email messages sent out	by your
       application, filling up the recipient's inbox.

       There's one caveat you need to know about: The "Log::Dispatch::Email"
       hierarchy of appenders turns on buffering by default. This means	that
       the appender will not send out messages right away but wait until a
       certain threshold has been reached. If you'd rather have	your alerts
       sent out	immediately, use

	   log4perl.appender.Mailer.buffered = 0

       to turn buffering off.

   How can I write my own appender?
       First off, Log::Log4perl	comes with a set of standard appenders.	Then,
       there's a lot of	Log4perl-compatible appenders already available	on
       CPAN: Just run a	search for "Log::Dispatch" on http://search.cpan.org
       and chances are that what you're	looking	for has	already	been
       developed, debugged and been used successfully in production -- no need
       for you to reinvent the wheel.

       Also, Log::Log4perl ships with a	nifty database appender	named
       Log::Log4perl::Appender::DBI -- check it	out if talking to databases is
       your desire.

       But if you're up	for a truly exotic task, you might have	to write an
       appender	yourself. That's very easy -- it takes no longer than a	couple
       of minutes.

       Say, we wanted to create	an appender of the class
       "ColorScreenAppender", which logs messages to the screen	in a
       configurable color. Just	create a new class in
       "ColorScreenAppender.pm":

	   package ColorScreenAppender;

       Now let's assume	that your Log::Log4perl	configuration file "test.conf"
       looks like this:

	   log4perl.logger = INFO, ColorApp

	   log4perl.appender.ColorApp=ColorScreenAppender
	   log4perl.appender.ColorApp.color=blue

	   log4perl.appender.ColorApp.layout = PatternLayout
	   log4perl.appender.ColorApp.layout.ConversionPattern=%d %m %n

       This will cause Log::Log4perl on	"init()" to look for a class
       ColorScreenAppender and call its	constructor new(). Let's add new() to
       ColorScreenAppender.pm:

	   sub new {
	       my($class, %options) = @_;

	       my $self	= { %options };
	       bless $self, $class;

	       return $self;
	   }

       To initialize this appender, Log::Log4perl will call and	pass all
       attributes of the appender as defined in	the configuration file to the
       constructor as name/value pairs (in this	case just one):

	   ColorScreenAppender->new(color => "blue");

       The new() method	listed above stores the	contents of the	%options hash
       in the object's instance	data hash (referred to by $self).  That's all
       for initializing	a new appender with Log::Log4perl.

       Second, ColorScreenAppender needs to expose a "log()" method, which
       will be called by Log::Log4perl every time it thinks the	appender
       should fire. Along with the object reference (as	usual in Perl's	object
       world), log() will receive a list of name/value pairs, of which only
       the one under the key "message" shall be	of interest for	now since it
       is the message string to	be logged. At this point, Log::Log4perl	has
       already taken care of joining the message to be a single	string.

       For our special appender	ColorScreenAppender, we're using the
       Term::ANSIColor module to colorize the output:

	   use Term::ANSIColor;

	   sub log {
	       my($self, %params) = @_;

	       print colored($params{message},
			     $self->{color});
	   }

       The color (as configured	in the Log::Log4perl configuration file) is
       available as $self->{color} in the appender object. Don't forget	to
       return

	   1;

       at the end of ColorScreenAppender.pm and	you're done. Install the new
       appender	somewhere where	perl can find it and try it with a test	script
       like

	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->init("test.conf");
	   ERROR("blah");

       to see the new colored output. Is this cool or what?

       And it gets even	better:	You can	write dynamically generated appender
       classes using the "Class::Prototyped" module. Here's an example of an
       appender	prepending every outgoing message with a configurable number
       of bullets:

	   use Class::Prototyped;

	   my $class = Class::Prototyped->newPackage(
	     "MyAppenders::Bulletizer",
	     bullets =>	1,
	     log     =>	sub {
	       my($self, %params) = @_;
	       print "*" x $self->bullets(),
		     $params{message};
	     },
	   );

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->init(\ q{
	     log4perl.logger = INFO, Bully

	     log4perl.appender.Bully=MyAppenders::Bulletizer
	     log4perl.appender.Bully.bullets=3

	     log4perl.appender.Bully.layout = PatternLayout
	     log4perl.appender.Bully.layout.ConversionPattern=%m %n
	   });

	       # ... prints: "***Boo!\n";
	   INFO	"Boo!";

   How can I drill down	on references before logging them?
       If you've got a reference to a nested structure or object, then you
       probably	don't want to log it as	"HASH(0x81141d4)" but rather dump it
       as something like

	   $VAR1 = {
		     'a' => 'b',
		     'd' => 'e'
		   };

       via a module like Data::Dumper. While it's syntactically	correct	to say

	   $logger->debug(Data::Dumper::Dumper($ref));

       this call imposes a huge	performance penalty on your application	if the
       message is suppressed by	Log::Log4perl, because Data::Dumper will
       perform its expensive operations	in any case, because it	doesn't	know
       that its	output will be thrown away immediately.

       As of Log::Log4perl 0.28, there's a better way: Use the message output
       filter format as	in

	   $logger->debug( {filter => \&Data::Dumper::Dumper,
			    value  => $ref} );

       and Log::Log4perl won't call the	filter function	unless the message
       really gets written out to an appender. Just make sure to pass the
       whole slew as a reference to a hash specifying a	filter function	(as a
       sub reference) under the	key "filter" and the value to be passed	to the
       filter function in "value").  When it comes to logging, Log::Log4perl
       will call the filter function, pass the "value" as an argument and log
       the return value.  Saves	you serious cycles.

   How can I collect all FATAL messages	in an extra log	file?
       Suppose you have	employed Log4perl all over your	system and you've
       already activated logging in various subsystems.	On top of that,
       without disrupting any other settings, how can you collect all FATAL
       messages	all over the system and	send them to a separate	log file?

       If you define a root logger like	this:

	   log4perl.logger		    = FATAL, File
	   log4perl.appender.File	    = Log::Log4perl::Appender::File
	   log4perl.appender.File.filename  = /tmp/fatal.txt
	   log4perl.appender.File.layout    = PatternLayout
	   log4perl.appender.File.layout.ConversionPattern= %d %m %n
	       # !!! Something's missing ...

       you'll be surprised to not only receive all FATAL messages issued
       anywhere	in the system, but also	everything else	-- gazillions of
       ERROR, WARN, INFO and even DEBUG	messages will end up in	your fatal.txt
       logfile!	 Reason	for this is Log4perl's (or better: Log4j's) appender
       additivity.  Once a lower-level logger decides to fire, the message is
       going to	be forwarded to	all appenders upstream -- without further
       priority	checks with their attached loggers.

       There's a way to	prevent	this, however: If your appender	defines	a
       minimum threshold, only messages	of this	priority or higher are going
       to be logged. So, just add

	   log4perl.appender.File.Threshold = FATAL

       to the configuration above, and you'll get what you wanted in the first
       place: An overall system	FATAL message collector.

   How can I bundle several log	messages into one?
       Would you like to tally the messages arriving at	your appender and dump
       out a summary once they're exceeding a certain threshold?  So that
       something like

	   $logger->error("Blah");
	   $logger->error("Blah");
	   $logger->error("Blah");

       won't be	logged as

	   Blah
	   Blah
	   Blah

       but as

	   [3] Blah

       instead?	If you'd like to hold off on logging a message until it	has
       been sent a couple of times, you	can roll that out by creating a
       buffered	appender.

       Let's define a new appender like

	   package TallyAppender;

	   sub new {
	       my($class, %options) = @_;

	       my $self	= { maxcount =>	5,
			    %options
			  };

	       bless $self, $class;

	       $self->{last_message}	    = "";
	       $self->{last_message_count}  = 0;

	       return $self;
	   }

       with two	additional instance variables "last_message" and
       "last_message_count", storing the content of the	last message sent and
       a counter of how	many times this	has happened. Also, it features	a
       configuration parameter "maxcount" which	defaults to 5 in the snippet
       above but can be	set in the Log4perl configuration file like this:

	   log4perl.logger = INFO, A
	   log4perl.appender.A=TallyAppender
	   log4perl.appender.A.maxcount	= 3

       The main	tallying logic lies in the appender's "log" method, which is
       called every time Log4perl thinks a message needs to get	logged by our
       appender:

	   sub log {
	       my($self, %params) = @_;

		   # Message changed? Print buffer.
	       if($self->{last_message}	and
		  $params{message} ne $self->{last_message}) {
		   print "[$self->{last_message_count}]: " .
			 "$self->{last_message}";
		   $self->{last_message_count} = 1;
		   $self->{last_message} = $params{message};
		   return;
	       }

	       $self->{last_message_count}++;
	       $self->{last_message} = $params{message};

		   # Threshold exceeded? Print,	reset counter
	       if($self->{last_message_count} >=
		  $self->{maxcount}) {
		   print "[$self->{last_message_count}]: " .
			 "$params{message}";
		   $self->{last_message_count} = 0;
		   $self->{last_message}       = "";
		   return;
	       }
	   }

       We basically just check if the oncoming message in $param{message} is
       equal to	what we've saved before	in the "last_message" instance
       variable. If so,	we're increasing "last_message_count".	We print the
       message in two cases: If	the new	message	is different than the buffered
       one, because then we need to dump the old stuff and store the new. Or,
       if the counter exceeds the threshold, as	defined	by the "maxcount"
       configuration parameter.

       Please note that	the appender always gets the fully rendered message
       and just	compares it as a whole -- so if	there's	a date/timestamp in
       there, that might confuse your logic. You can work around this by
       specifying %m %n	as a layout and	add the	date later on in the appender.
       Or, make	the comparison smart enough to omit the	date.

       At last,	don't forget what happens if the program is being shut down.
       If there's still	messages in the	buffer,	they should be printed out at
       that point. That's easy to do in	the appender's DESTROY method, which
       gets called at object destruction time:

	   sub DESTROY {
	       my($self) = @_;

	       if($self->{last_message_count}) {
		   print "[$self->{last_message_count}]: " .
			 "$self->{last_message}";
		   return;
	       }
	   }

       This will ensure	that none of the buffered messages are lost.  Happy
       buffering!

   I want to log ERROR and WARN	messages to different files! How can I do
       that?
       Let's assume you	wanted to have each logging statement written to a
       different file, based on	the statement's	priority. Messages with
       priority	"WARN" are supposed to go to "/tmp/app.warn", events
       prioritized as "ERROR" should end up in "/tmp/app.error".

       Now, if you define two appenders	"AppWarn" and "AppError" and assign
       them both to the	root logger, messages bubbling up from any loggers
       below will be logged by both appenders because of Log4perl's message
       propagation feature. If you limit their exposure	via the	appender
       threshold mechanism and set "AppWarn"'s threshold to "WARN" and
       "AppError"'s to "ERROR",	you'll still get "ERROR" messages in
       "AppWarn", because "AppWarn"'s "WARN" setting will just filter out
       messages	with a lower priority than "WARN" -- "ERROR" is	higher and
       will be allowed to pass through.

       What we need for	this is	a Log4perl Custom Filter, available with
       Log::Log4perl 0.30.

       Both appenders need to verify that the priority of the oncoming
       messages	exactly	matches	the priority the appender is supposed to log
       messages	of. To accomplish this task, let's define two custom filters,
       "MatchError" and	"MatchWarn", which, when attached to their appenders,
       will limit messages passed on to	them to	those matching a given
       priority:

	   log4perl.logger = WARN, AppWarn, AppError

	       # Filter	to match level ERROR
	   log4perl.filter.MatchError =	Log::Log4perl::Filter::LevelMatch
	   log4perl.filter.MatchError.LevelToMatch  = ERROR
	   log4perl.filter.MatchError.AcceptOnMatch = true

	       # Filter	to match level WARN
	   log4perl.filter.MatchWarn  =	Log::Log4perl::Filter::LevelMatch
	   log4perl.filter.MatchWarn.LevelToMatch  = WARN
	   log4perl.filter.MatchWarn.AcceptOnMatch = true

	       # Error appender
	   log4perl.appender.AppError =	Log::Log4perl::Appender::File
	   log4perl.appender.AppError.filename = /tmp/app.err
	   log4perl.appender.AppError.layout   = SimpleLayout
	   log4perl.appender.AppError.Filter   = MatchError

	       # Warning appender
	   log4perl.appender.AppWarn = Log::Log4perl::Appender::File
	   log4perl.appender.AppWarn.filename =	/tmp/app.warn
	   log4perl.appender.AppWarn.layout   =	SimpleLayout
	   log4perl.appender.AppWarn.Filter   =	MatchWarn

       The appenders "AppWarn" and "AppError" defined above are	logging	to
       "/tmp/app.warn" and "/tmp/app.err" respectively and have	the custom
       filters "MatchWarn" and "MatchError" attached.  This setup will direct
       all WARN	messages, issued anywhere in the system, to /tmp/app.warn (and
       ERROR messages to /tmp/app.error) -- without any	overlaps.

   On our server farm, Log::Log4perl configuration files differ	slightly from
       host to host. Can I roll	them all into one?
       You sure	can, because Log::Log4perl allows you to specify attribute
       values dynamically. Let's say that one of your appenders	expects	the
       host's IP address as one	of its attributes. Now,	you could certainly
       roll out	different configuration	files for every	host and specify the
       value like

	   log4perl.appender.MyAppender	   = Log::Log4perl::Appender::SomeAppender
	   log4perl.appender.MyAppender.ip = 10.0.0.127

       but that's a maintenance	nightmare. Instead, you	can have Log::Log4perl
       figure out the IP address at configuration time and set the appender's
       value correctly:

	       # Set the IP address dynamically
	   log4perl.appender.MyAppender	   = Log::Log4perl::Appender::SomeAppender
	   log4perl.appender.MyAppender.ip = sub { \
	      use Sys::Hostname; \
	      use Socket; \
	      return inet_ntoa(scalar gethostbyname hostname); \
	   }

       If Log::Log4perl	detects	that an	attribute value	starts with something
       like "sub {...",	it will	interpret it as	a perl subroutine which	is to
       be executed once	at configuration time (not runtime!) and its return
       value is	to be used as the attribute value. This	comes in handy for
       rolling out applications	where Log::Log4perl configuration files	show
       small host-specific differences,	because	you can	deploy the unmodified
       application distribution	on all instances of the	server farm.

   Log4perl doesn't interpret my backslashes correctly!
       If you're using Log4perl's feature to specify the configuration as a
       string in your program (as opposed to a separate	configuration file),
       chances are that	you've written it like this:

	   # *** WRONG!	***

	   Log::Log4perl->init(	\ <<END_HERE);
	       log4perl.logger = WARN, A1
	       log4perl.appender.A1 = Log::Log4perl::Appender::Screen
	       log4perl.appender.A1.layout = \
		   Log::Log4perl::Layout::PatternLayout
	       log4perl.appender.A1.layout.ConversionPattern = %m%n
	   END_HERE

	   # *** WRONG!	***

       and you're getting the following	error message:

	   Layout not specified	for appender A1	at .../Config.pm line 342.

       What's wrong? The problem is that you're	using a	here-document with
       substitution enabled ("<<END_HERE") and that Perl won't interpret
       backslashes at line-ends	as continuation	characters but will
       essentially throw them out. So, in the code above, the layout line will
       look like

	   log4perl.appender.A1.layout =

       to Log::Log4perl	which causes it	to report an error. To interpret the
       backslash at the	end of the line	correctly as a line-continuation
       character, use the non-interpreting mode	of the here-document like in

	   # *** RIGHT!	***

	   Log::Log4perl->init(	\ <<'END_HERE');
	       log4perl.logger = WARN, A1
	       log4perl.appender.A1 = Log::Log4perl::Appender::Screen
	       log4perl.appender.A1.layout = \
		   Log::Log4perl::Layout::PatternLayout
	       log4perl.appender.A1.layout.ConversionPattern = %m%n
	   END_HERE

	   # *** RIGHT!	***

       (note the single	quotes around 'END_HERE') or use "q{...}" instead of a
       here-document and Perl will treat the backslashes at line-end as
       intended.

   I want to suppress certain messages based on	their content!
       Let's assume you've plastered all your functions	with Log4perl
       statements like

	   sub some_func {

	       INFO("Begin of function");

	       # ... Stuff happens here	...

	       INFO("End of function");
	   }

       to issue	two log	messages, one at the beginning and one at the end of
       each function. Now you want to suppress the message at the beginning
       and only	keep the one at	the end, what can you do? You can't use	the
       category	mechanism, because both	messages are issued from the same
       package.

       Log::Log4perl's custom filters (0.30 or better) provide an interface
       for the Log4perl	user to	step in	right before a message gets logged and
       decide if it should be written out or suppressed, based on the message
       content or other	parameters:

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl::init(	\ <<'EOT' );
	       log4perl.logger		   = INFO, A1
	       log4perl.appender.A1	   = Log::Log4perl::Appender::Screen
	       log4perl.appender.A1.layout = \
		   Log::Log4perl::Layout::PatternLayout
	       log4perl.appender.A1.layout.ConversionPattern = %m%n

	       log4perl.filter.M1 = Log::Log4perl::Filter::StringMatch
	       log4perl.filter.M1.StringToMatch	= Begin
	       log4perl.filter.M1.AcceptOnMatch	= false

	       log4perl.appender.A1.Filter = M1
       EOT

       The last	four statements	in the configuration above are defining	a
       custom filter "M1" of type "Log::Log4perl::Filter::StringMatch",	which
       comes with Log4perl right out of	the box	and allows you to define a
       text pattern to match (as a perl	regular	expression) and	a flag
       "AcceptOnMatch" indicating if a match is	supposed to suppress the
       message or let it pass through.

       The last	line then assigns this filter to the "A1" appender, which will
       call it every time it receives a	message	to be logged and throw all
       messages	out not	matching the regular expression	"Begin".

       Instead of using	the standard "Log::Log4perl::Filter::StringMatch"
       filter, you can define your own,	simply using a perl subroutine:

	   log4perl.filter.ExcludeBegin	 = sub { !/Begin/ }
	   log4perl.appender.A1.Filter	 = ExcludeBegin

       For details on custom filters, check Log::Log4perl::Filter.

   My new module uses Log4perl -- but what happens if the calling program
       didn't configure	it?
       If a Perl module	uses Log::Log4perl, it will typically rely on the
       calling program to initialize it. If it is using	Log::Log4perl in
       ":easy" mode, like in

	   package MyMod;
	   use Log::Log4perl qw(:easy);

	   sub foo {
	       DEBUG("In foo");
	   }

	   1;

       and the calling program doesn't initialize Log::Log4perl	at all (e.g.
       because it has no clue that it's	available), Log::Log4perl will
       silently	ignore all logging messages. However, if the module is using
       Log::Log4perl in	regular	mode like in

	   package MyMod;
	   use Log::Log4perl qw(get_logger);

	   sub foo {
	       my $logger = get_logger("");
	       $logger->debug("blah");
	   }

	   1;

       and the main program is just using the module like in

	   use MyMode;
	   MyMode::foo();

       then Log::Log4perl will also ignore all logging messages	but issue a
       warning like

	   Log4perl: Seems like	no initialization happened.
	   Forgot to call init()?

       (only once!) to remind novice users to not forget to initialize the
       logging system before using it.	However, if you	want to	suppress this
       message,	just add the ":nowarn" target to the module's "use
       Log::Log4perl" call:

	   use Log::Log4perl qw(get_logger :nowarn);

       This will have Log::Log4perl silently ignore all	logging	statements if
       no initialization has taken place. If, instead of using init(), you're
       using Log4perl's	API to define loggers and appenders, the same
       notification happens if no call to add_appenders() is made, i.e.	no
       appenders are defined.

       If the module wants to figure out if some other program part has
       already initialized Log::Log4perl, it can do so by calling

	   Log::Log4perl::initialized()

       which will return a true	value in case Log::Log4perl has	been
       initialized and a false value if	not.

   How can I synchronize access	to an appender?
       If you're using the same	instance of an appender	in multiple processes,
       and each	process	is passing on messages to the appender in parallel,
       you might end up	with overlapping log entries.

       Typical scenarios include a file	appender that you create in the	main
       program,	and which will then be shared between the parent and a forked
       child process. Or two separate processes, each initializing a Log4perl
       file appender on	the same logfile.

       Log::Log4perl won't synchronize access to the shared logfile by
       default.	Depending on your operating system's flush mechanism, buffer
       size and	the size of your messages, there's a small chance of an
       overlap.

       The easiest way to prevent overlapping messages in logfiles written to
       by multiple processes is	setting	the file appender's "syswrite" flag
       along with a file write mode of "append".  This makes sure that
       "Log::Log4perl::Appender::File" uses "syswrite()" (which	is guaranteed
       to run uninterrupted) instead of	"print()" which	might buffer the
       message or get interrupted by the OS while it is	writing. And in
       "append"	mode, the OS kernel ensures that multiple processes share one
       end-of-file marker, ensuring that each process writes to	the real end
       of the file. (The value of "append" for the "mode" parameter is the
       default setting in Log4perl's file appender so you don't	have to	set it
       explicitly.)

	     # Guarantees atomic writes

	   log4perl.category.Bar.Twix	       = WARN, Logfile

	   log4perl.appender.Logfile	       = Log::Log4perl::Appender::File
	   log4perl.appender.Logfile.mode      = append
	   log4perl.appender.Logfile.syswrite  = 1
	   log4perl.appender.Logfile.filename  = test.log
	   log4perl.appender.Logfile.layout    = SimpleLayout

       Another guaranteed way of having	messages separated with	any kind of
       appender	is putting a Log::Log4perl::Appender::Synchronized composite
       appender	in between Log::Log4perl and the real appender.	It will	make
       sure to let messages pass through this virtual gate one by one only.

       Here's a	sample configuration to	synchronize access to a	file appender:

	   log4perl.category.Bar.Twix	       = WARN, Syncer

	   log4perl.appender.Logfile	       = Log::Log4perl::Appender::File
	   log4perl.appender.Logfile.autoflush = 1
	   log4perl.appender.Logfile.filename  = test.log
	   log4perl.appender.Logfile.layout    = SimpleLayout

	   log4perl.appender.Syncer	       = Log::Log4perl::Appender::Synchronized
	   log4perl.appender.Syncer.appender   = Logfile

       "Log::Log4perl::Appender::Synchronized" uses the	"IPC::Shareable"
       module and its semaphores, which	will slow down writing the log
       messages, but ensures sequential	access featuring atomic	checks.	 Check
       Log::Log4perl::Appender::Synchronized for details.

   Can I use Log::Log4perl with	log4j's	Chainsaw?
       Yes, Log::Log4perl can be configured to send its	events to log4j's
       graphical log UI	Chainsaw.

       Here's how it works:

       o   Get Guido Carls' <gcarls@cpan.org> Log::Log4perl extension
	   "Log::Log4perl::Layout::XMLLayout" from CPAN	and install it:

	       perl -MCPAN -eshell
	       cpan> install Log::Log4perl::Layout::XMLLayout

       o   Install and start Chainsaw, which is	part of	the "log4j"
	   distribution	now (see http://jakarta.apache.org/log4j ). Create a
	   configuration file like

	     <log4j:configuration debug="true">
	       <plugin name="XMLSocketReceiver"
		       class="org.apache.log4j.net.XMLSocketReceiver">
		 <param	name="decoder" value="org.apache.log4j.xml.XMLDecoder"/>
		 <param	name="Port" value="4445"/>
	       </plugin>
	       <root> <level value="debug"/> </root>
	     </log4j:configuration>

	   and name it e.g. "config.xml". Then start Chainsaw like

	     java -Dlog4j.debug=true -Dlog4j.configuration=config.xml \
	       -classpath ".:log4j-1.3alpha.jar:log4j-chainsaw-1.3alpha.jar" \
	       org.apache.log4j.chainsaw.LogUI

	   and watch the GUI coming up.

       o   Configure Log::Log4perl to use a socket appender with an XMLLayout,
	   pointing to the host/port where Chainsaw (as	configured above) is
	   waiting with	its XMLSocketReceiver:

	     use Log::Log4perl qw(get_logger);
	     use Log::Log4perl::Layout::XMLLayout;

	     my	$conf =	q(
	       log4perl.category.Bar.Twix	   = WARN, Appender
	       log4perl.appender.Appender	   = Log::Log4perl::Appender::Socket
	       log4perl.appender.Appender.PeerAddr = localhost
	       log4perl.appender.Appender.PeerPort = 4445
	       log4perl.appender.Appender.layout   = Log::Log4perl::Layout::XMLLayout
	     );

	     Log::Log4perl::init(\$conf);

	       # Nasty hack to suppress	encoding header
	     my	$app = Log::Log4perl::appenders->{"Appender"};
	     $app->layout()->{enc_set} = 1;

	     my	$logger	= get_logger("Bar.Twix");
	     $logger->error("One");

	   The nasty hack shown	in the code snippet above is currently
	   (October 2003) necessary, because Chainsaw expects XML messages to
	   arrive in a format like

	     <log4j:event logger="Bar.Twix"
			  timestamp="1066794904310"
			  level="ERROR"
			  thread="10567">
	       <log4j:message><![CDATA[Two]]></log4j:message>
	       <log4j:NDC><![CDATA[undef]]></log4j:NDC>
	       <log4j:locationInfo class="main"
		 method="main"
		 file="./t"
		 line="32">
	       </log4j:locationInfo>
	     </log4j:event>

	   without a preceding

	     <?xml version = "1.0" encoding = "iso8859-1"?>

	   which Log::Log4perl::Layout::XMLLayout applies to the first event
	   sent	over the socket.

       See figure 1 for	a screenshot of	Chainsaw in action, receiving events
       from the	Perl script shown above.

       Many thanks to Chainsaw's Scott Deboy <sdeboy@comotivsystems.com> for
       his support!

   How can I run Log::Log4perl under mod_perl?
       In persistent environments it's important to play by the	rules outlined
       in section "Initialize once and only once" in Log::Log4perl.  If	you
       haven't read this yet, please go	ahead and read it right	now. It's very
       important.

       And no matter if	you use	a startup handler to init() Log::Log4perl or
       use the init_once() strategy (added in 0.42), either way	you're very
       likely to have unsynchronized writes to logfiles.

       If Log::Log4perl	is configured with a log file appender,	and it is
       initialized via the Apache startup handler, the file handle created
       initially will be shared	among all Apache processes. Similarly, with
       the init_once() approach: although every	process	has a separate L4p
       configuration, processes	are gonna share	the appender file names
       instead,	effectively opening several different file handles on the same
       file.

       Now, having several appenders using the same file handle	or having
       several appenders logging to the	same file unsynchronized, this might
       result in overlapping messages. Sometimes, this is acceptable. If it's
       not, here's two strategies:

       o   Use the Log::Log4perl::Appender::Synchronized appender to connect
	   to your file	appenders. Here's the writeup:
	   http://log4perl.sourceforge.net/releases/Log-Log4perl/docs/html/Log/Log4perl/FAQ.html#23804

       o   Use a different logfile for every process like in

		#log4perl.conf
		...
		log4perl.appender.A1.filename =	sub { "mylog.$$.log" }

   My program already uses warn() and die(). How can I switch to Log4perl?
       If your program already uses Perl's "warn()" function to	spew out error
       messages	and you'd like to channel those	into the Log4perl world, just
       define a	"__WARN__" handler where your program or module	resides:

	   use Log::Log4perl qw(:easy);

	   $SIG{__WARN__} = sub	{
	       local $Log::Log4perl::caller_depth =
		   $Log::Log4perl::caller_depth	+ 1;
	       WARN @_;
	   };

       Why the "local" setting of $Log::Log4perl::caller_depth?	 If you	leave
       that out, "PatternLayout" conversion specifiers like %M or %F (printing
       the current function/method and source filename)	will refer to where
       the __WARN__ handler resides, not the environment Perl's	"warn()"
       function	was issued from. Increasing "caller_depth" adjusts for this
       offset. Having it "local", makes	sure the level gets set	back after the
       handler exits.

       Once done, if your program does something like

	   sub some_func {
	       warn "Here's a warning";
	   }

       you'll get (depending on	your Log::Log4perl configuration) something
       like

	   2004/02/19 20:41:02-main::some_func:	Here's a warning at ./t	line 25.

       in the appropriate appender instead of having a screen full of STDERR
       messages. It also works with the	"Carp" module and its "carp()" and
       "cluck()" functions.

       If, on the other	hand, catching "die()" and friends is required,	a
       "__DIE__" handler is appropriate:

	   $SIG{__DIE__} = sub {
	       if($^S) {
		   # We're in an eval {} and don't want	log
		   # this message but catch it later
		   return;
	       }
	       local $Log::Log4perl::caller_depth =
		   $Log::Log4perl::caller_depth	+ 1;
	       LOGDIE @_;
	   };

       This will call Log4perl's "LOGDIE()" function, which will log a fatal
       error and then call die() internally, causing the program to exit.
       Works equally well with "Carp"'s	"croak()" and "confess()" functions.

   Some	module prints messages to STDERR. How can I funnel them	to
       Log::Log4perl?
       If a module you're using	doesn't	use Log::Log4perl but prints logging
       messages	to STDERR instead, like

	   ########################################
	   package IgnorantModule;
	   ########################################

	   sub some_method {
	       print STDERR "Parbleu! An error!\n";
	   }

	   1;

       there's still a way to capture these messages and funnel	them into
       Log::Log4perl, even without touching the	module.	What you need is a
       trapper module like

	   ########################################
	   package Trapper;
	   ########################################

	   use Log::Log4perl qw(:easy);

	   sub TIEHANDLE {
	       my $class = shift;
	       bless [], $class;
	   }

	   sub PRINT {
	       my $self	= shift;
	       $Log::Log4perl::caller_depth++;
	       DEBUG @_;
	       $Log::Log4perl::caller_depth--;
	   }

	   1;

       and a "tie" command in the main program to tie STDERR to	the trapper
       module along with regular Log::Log4perl initialization:

	   ########################################
	   package main;
	   ########################################

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->easy_init(
	       {level  => $DEBUG,
		file   => 'stdout',   #	make sure not to use stderr here!
		layout => "%d %M: %m%n",
	       });

	   tie *STDERR,	"Trapper";

       Make sure not to	use STDERR as Log::Log4perl's file appender here
       (which would be the default in ":easy" mode), because it	would end up
       in an endless recursion.

       Now, calling

	   IgnorantModule::some_method();

       will result in the desired output

	   2004/05/06 11:13:04 IgnorantModule::some_method: Parbleu! An	error!

   How come PAR	(Perl Archive Toolkit) creates executables which then can't
       find their Log::Log4perl	appenders?
       If not instructed otherwise, "Log::Log4perl" dynamically	pulls in
       appender	classes	found in its configuration. If you specify

	   #!/usr/bin/perl
	   # mytest.pl

	   use Log::Log4perl qw(get_logger);

	   my $conf = q(
	     log4perl.category.Bar.Twix	= WARN,	Logfile
	     log4perl.appender.Logfile	= Log::Log4perl::Appender::Screen
	     log4perl.appender.Logfile.layout =	SimpleLayout
	   );

	   Log::Log4perl::init(\$conf);
	   my $logger =	get_logger("Bar::Twix");
	   $logger->error("Blah");

       then "Log::Log4perl::Appender::Screen" will be pulled in	while the
       program runs, not at compile time. If you have PAR compile the script
       above to	an executable binary via

	   pp -o mytest	mytest.pl

       and then	run "mytest" on	a machine without having Log::Log4perl
       installed, you'll get an	error message like

	   ERROR: can't	load appenderclass 'Log::Log4perl::Appender::Screen'
	   Can't locate	Log/Log4perl/Appender/Screen.pm	in @INC	...

       Why? At compile time, "pp" didn't realize that
       "Log::Log4perl::Appender::Screen" would be needed later on and didn't
       wrap it into the	executable created. To avoid this, either say "use
       Log::Log4perl::Appender::Screen"	in the script explicitly or compile it
       with

	   pp -o mytest	-M Log::Log4perl::Appender::Screen mytest.pl

       to make sure the	appender class gets included.

   How can I access a custom appender defined in the configuration?
       Any appender defined in the configuration file or somewhere in the code
       can be accessed later via
       "Log::Log4perl->appender_by_name("appender_name")", which returns a
       reference of the	appender object.

       Once you've got a hold of the object, it	can be queried or modified to
       your liking. For	example, see the custom	"IndentAppender" defined
       below: After calling "init()" to	define the Log4perl settings, the
       appender	object is retrieved to call its	"indent_more()"	and
       "indent_less()" methods to control indentation of messages:

	   package IndentAppender;

	   sub new {
	       bless { indent => 0 }, $_[0];
	   }

	   sub indent_more  { $_[0]->{indent}++	}
	   sub indent_less  { $_[0]->{indent}--	}

	   sub log {
	       my($self, %params) = @_;
	       print " " x $self->{indent}, $params{message};
	   }

	   package main;

	   use Log::Log4perl qw(:easy);

	   my $conf = q(
	   log4perl.category	      =	DEBUG, Indented
	   log4perl.appender.Indented =	IndentAppender
	   log4perl.appender.Indented.layout = Log::Log4perl::Layout::SimpleLayout
	   );

	   Log::Log4perl::init(\$conf);

	   my $appender	= Log::Log4perl->appender_by_name("Indented");

	   DEBUG "No identation";
	   $appender->indent_more();
	   DEBUG "One more";
	   $appender->indent_more();
	   DEBUG "Two more";
	   $appender->indent_less();
	   DEBUG "One less";

       As you would expect, this will print

	   DEBUG - No identation
	    DEBUG - One	more
	     DEBUG - Two more
	    DEBUG - One	less

       because the very	appender used by Log4perl is modified dynamically at
       runtime.

   I don't know	if Log::Log4perl is installed. How can I prepare my script?
       In case your script needs to be prepared	for environments that may or
       may not have Log::Log4perl installed, there's a trick.

       If you put the following	BEGIN blocks at	the top	of the program,	you'll
       be able to use the DEBUG(), INFO(), etc.	macros in Log::Log4perl's
       ":easy" mode.  If Log::Log4perl is installed in the target environment,
       the regular Log::Log4perl rules apply. If not, all of DEBUG(), INFO(),
       etc. are	"stubbed" out, i.e. they turn into no-ops:

	   use warnings;
	   use strict;

	   BEGIN {
	       eval { require Log::Log4perl; };

	       if($@) {
		   print "Log::Log4perl	not installed -	stubbing.\n";
		   no strict qw(refs);
		   *{"main::$_"} = sub { } for qw(DEBUG	INFO WARN ERROR	FATAL);
	       } else {
		   no warnings;
		   print "Log::Log4perl	installed - life is good.\n";
		   require Log::Log4perl::Level;
		   Log::Log4perl::Level->import(__PACKAGE__);
		   Log::Log4perl->import(qw(:easy));
		   Log::Log4perl->easy_init($main::DEBUG);
	       }
	   }

	       # The regular script begins ...
	   DEBUG "Hey now!";

       This snippet will first probe for Log::Log4perl,	and if it can't	be
       found, it will alias DEBUG(), INFO(), with empty	subroutines via
       typeglobs.  If Log::Log4perl is available, its level constants are
       first imported ($DEBUG, $INFO, etc.) and	then "easy_init()" gets	called
       to initialize the logging system.

   Can file appenders create files with	different permissions?
       Typically, when "Log::Log4perl::Appender::File" creates a new file, its
       permissions are set to "rw-r--r--". Why?	Because	your environment's
       umask most likely defaults to 0022, that's the standard setting.

       What's a	umask, you're asking? It's a template that's applied to	the
       permissions of all newly	created	files. While calls like	"open(FILE,
       ">foo")"	will always try	to create files	in "rw-rw-rw- "	mode, the
       system will apply the current umask template to determine the final
       permission setting. umask is a bit mask that's inverted and then
       applied to the requested	permission setting, using a bitwise AND:

	   $request_permission &~ $umask

       So, a umask setting of 0000 (the	leading	0 simply indicates an octal
       value) will create files	in "rw-rw-rw-" mode, a setting of 0277 will
       use "r--------",	and the	standard 0022 will use "rw-r--r--".

       As an example, if you want your log files to be created with
       "rw-r--rw-" permissions,	use a umask of 0020 before calling
       Log::Log4perl->init():

	   use Log::Log4perl;

	   umask 0020;
	       # Creates log.out in rw-r--rw mode
	   Log::Log4perl->init(\ q{
	       log4perl.logger = WARN, File
	       log4perl.appender.File =	Log::Log4perl::Appender::File
	       log4perl.appender.File.filename = log.out
	       log4perl.appender.File.layout = SimpleLayout
	   });

   Using Log4perl in an	END block causes a problem!
       It's not	easy to	get to this error, but if you write something like

	   END { Log::Log4perl::get_logger()->debug("Hey there."); }

	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

       it won't	work. The reason is that "Log::Log4perl" defines an END	block
       that cleans up all loggers. And perl will run END blocks	in the reverse
       order as	they're	encountered in the compile phase, so in	the scenario
       above, the END block will run after Log4perl has	cleaned	up its
       loggers.

       Placing END blocks using	Log4perl after a "use Log::Log4perl" statement
       fixes the problem:

	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

	   END { Log::Log4perl::get_logger()->debug("Hey there."); }

       In this scenario, the shown END block is	executed before	Log4perl
       cleans up and the debug message will be processed properly.

   Help! My appender is	throwing a "Wide character in print" warning!
       This warning shows up when Unicode strings are printed without
       precautions. The	warning	goes away if the complaining appender is set
       to utf-8	mode:

	     # Either in the log4perl configuration file:
	 log4perl.appender.Logfile.filename = test.log
	 log4perl.appender.Logfile.utf8	    = 1

	     # Or, in easy mode:
	 Log::Log4perl->easy_init( {
	   level => $DEBUG,
	   file	 => ":utf8> test.log"
	 } );

       If the complaining appender is a	screen appender, set its "utf8"
       option:

	     log4perl.appender.Screen.stderr = 1
	     log4perl.appender.Screen.utf8   = 1

       Alternatively, "binmode"	does the trick:

	     # Either STDOUT ...
	   binmode(STDOUT, ":utf8);

	     # ... or STDERR.
	   binmode(STDERR, ":utf8);

       Some background on this:	Perl's strings are either byte strings or
       Unicode strings.	"Mike" is a byte string.  "\x{30DE}\x{30A4}\x{30AF}"
       is a Unicode string. Unicode strings are	marked specially and are UTF-8
       encoded internally.

       If you print a byte string to STDOUT, all is well, because STDOUT is by
       default set to byte mode. However, if you print a Unicode string	to
       STDOUT without precautions, "perl" will try to transform	the Unicode
       string back to a	byte string before printing it out. This is
       troublesome if the Unicode string contains 'wide' characters which
       can't be	represented in Latin-1.

       For example, if you create a Unicode string with	three japanese
       Katakana	characters as in

	   perl	-le 'print "\x{30DE}\x{30A4}\x{30AF}"'

       (coincidentally pronounced Ma-i-ku, the japanese	pronunciation of
       "Mike"),	STDOUT is in byte mode and the warning

	   Wide	character in print at ./script.pl line 14.

       appears.	Setting	STDOUT to UTF-8	mode as	in

	   perl	-le 'binmode(STDOUT, ":utf8"); print "\x{30DE}\x{30A4}\x{30AF}"'

       will silently print the Unicode string to STDOUT	in UTF-8. To see the
       characters printed, you'll need a UTF-8 terminal	with a font including
       japanese	Katakana characters.

   How can I send errors to the	screen,	and debug messages to a	file?
       Let's assume you	want to	maintain a detailed DEBUG output in a file and
       only messages of	level ERROR and	higher should be printed on the
       screen. Often times, developers come up with something like this:

	    # Wrong!!!
	   log4perl.logger = DEBUG, FileApp
	   log4perl.logger = ERROR, ScreenApp
	    # Wrong!!!

       This won't work,	however. Logger	definitions aren't additive, and the
       second statement	will overwrite the first one. Log4perl versions	below
       1.04 were silently accepting this, leaving people confused why it
       wouldn't	work as	expected.  As of 1.04, this will throw a fatal error
       to notify the user of the problem.

       What you	want to	do instead, is this:

	   log4perl.logger		      =	DEBUG, FileApp,	ScreenApp

	   log4perl.appender.FileApp	      =	Log::Log4perl::Appender::File
	   log4perl.appender.FileApp.filename =	test.log
	   log4perl.appender.FileApp.layout   =	SimpleLayout

	   log4perl.appender.ScreenApp		= Log::Log4perl::Appender::Screen
	   log4perl.appender.ScreenApp.stderr	= 0
	   log4perl.appender.ScreenApp.layout	= SimpleLayout
	      ### limiting output to ERROR messages
	   log4perl.appender.ScreenApp.Threshold = ERROR
	      ###

       Note that without the second appender's "Threshold" setting, both
       appenders would receive all messages prioritized	DEBUG and higher. With
       the threshold set to ERROR, the second appender will filter the
       messages	as required.

   Where should	I put my logfiles?
       Your log	files may go anywhere you want them, but the effective user id
       of the calling process must have	write access.

       If the log file doesn't exist at	program	start, Log4perl's file
       appender	will create it.	For this, it needs write access	to the
       directory where the new file will be located in.	If the log file
       already exists at startup, the process simply needs write access	to the
       file. Note that it will need write access to the	file's directory if
       you're encountering situations where the	logfile	gets recreated,	e.g.
       during log rotation.

       If Log::Log4perl	is used	by a web server	application (e.g. in a CGI
       script or mod_perl), then the webserver's user (usually "nobody"	or
       "www") must have	the permissions	mentioned above.

       To prepare your web server to use log4perl, we'd	recommend:

	   webserver:~$	su -
	   webserver:~#	mkdir /var/log/cgiapps
	   webserver:~#	chown nobody:root /var/log/cgiapps/
	   webserver:~#	chown nobody:root -R /var/log/cgiapps/
	   webserver:~#	chmod 02755 -R /var/log/cgiapps/

       Then set	your /etc/log4perl.conf	file to	include:

	   log4perl.appender.FileAppndr1.filename =
	       /var/log/cgiapps/<app-name>.log

   How can my file appender deal with disappearing log files?
       The file	appender that comes with Log4perl,
       Log::Log4perl::Appender::File, will open	a specified log	file at
       initialization time and will keep writing to it via a file handle.

       In case the associated file goes	way, messages written by a long-
       running process will still be written to	the file handle. In case the
       file has	been moved to a	different location on the same file system,
       the writer will keep writing to it under	the new	filename. In case the
       file has	been removed from the file system, the log messages will end
       up in nowhere land. This	is not a bug in	Log4perl, this is how Unix
       works. There is no error	message	in this	case, because the writer has
       no idea that the	file handle is not associated with a visible file.

       To prevent the loss of log messages when	log files disappear, the file
       appender's "recreate" option needs to be	set to a true value:

	   log4perl.appender.Logfile.recreate =	1

       This will instruct the file appender to check in	regular	intervals
       (default: 30 seconds) if	the log	file is	still there. If	it finds out
       that the	file is	missing, it will recreate it.

       Continuously checking if	the log	file still exists is fairly expensive.
       For this	reason it is only performed every 30 seconds. To change	this
       interval, the option "recreate_check_interval" can be set to the	number
       of seconds between checks. In the extreme case where the	check should
       be performed before every write,	it can even be set to 0:

	   log4perl.appender.Logfile.recreate =	1
	   log4perl.appender.Logfile.recreate_check_interval = 0

       To avoid	having to check	the file system	so frequently, a signal
       handler can be set up:

	   log4perl.appender.Logfile.recreate =	1
	   log4perl.appender.Logfile.recreate_check_signal = USR1

       This will install a signal handler which	will recreate a	missing	log
       file immediately	when it	receives the defined signal.

       Note that the init_and_watch() method for Log4perl's initialization can
       also be instructed to install a signal handler, usually using the HUP
       signal. Make sure to use	a different signal if you're using both	of
       them at the same	time.

   How can I rotate a logfile with newsyslog?
       Here's a	few things that	need to	be taken care of when using the
       popular log file	rotating utility "newsyslog"
       (http://www.courtesan.com/newsyslog) with Log4perl's file appender in
       long-running processes.

       For example, with a newsyslog configuration like

	   # newsyslog.conf
	   /tmp/test.log 666  12  5  *	B

       and a call to

	   # newsyslog -f /path/to/newsyslog.conf

       "newsyslog" will	take action if "/tmp/test.log" is larger than the
       specified 5K in size. It	will move the current log file "/tmp/test.log"
       to "/tmp/test.log.0" and	create a new and empty "/tmp/test.log" with
       the specified permissions (this is why "newsyslog" needs	to run as
       root).  An already existing "/tmp/test.log.0" would be moved to
       "/tmp/test.log.1", "/tmp/test.log.1" to "/tmp/test.log.2", and so
       forth, for every	one of a max number of 12 archived logfiles that have
       been configured in "newsyslog.conf".

       Although	a new file has been created, from Log4perl's appender's	point
       of view,	this situation is identical to the one described in the
       previous	FAQ entry, labeled "How	can my file appender deal with
       disappearing log	files".

       To make sure that log messages are written to the new log file and not
       to an archived one or end up in nowhere land, the appender's "recreate"
       and "recreate_check_interval" have to be	configured to deal with	the
       'disappearing' log file.

       The situation gets interesting when "newsyslog"'s option	to compress
       archived	log files is enabled. This causes the original log file	not to
       be moved, but to	disappear. If the file appender	isn't configured to
       recreate	the logfile in this situation, log messages will actually be
       lost without warning. This also applies for the short time frame	of
       "recreate_check_interval" seconds in between the	recreator's file
       checks.

       To make sure that no messages get lost, one option is to	set the
       interval	to

	   log4perl.appender.Logfile.recreate_check_interval = 0

       However,	this is	fairly expensive. A better approach is to define a
       signal handler:

	   log4perl.appender.Logfile.recreate =	1
	   log4perl.appender.Logfile.recreate_check_signal  = USR1
	   log4perl.appender.Logfile.recreate_pid_write	= /tmp/myappid

       As a service for	"newsyslog" users, Log4perl's file appender writes the
       current process ID to a PID file	specified by the "recreate_pid_write"
       option.	"newsyslog" then needs to be configured	as in

	   # newsyslog.conf configuration for compressing archive files	and
	   # sending a signal to the Log4perl-enabled application
	   /tmp/test.log 666  12  5  *	B /tmp/myappid 30

       to send the defined signal (30, which is	USR1 on	FreeBSD) to the
       application process at rotation time. Note that the signal number is
       different on Linux, where USR1 denotes as 10. Check "man	signal"	for
       details.

   How can a process under user	id A log to a file under user id B?
       This scenario often occurs in configurations where processes run	under
       various user IDs	but need to write to a log file	under a	fixed, but
       different user id.

       With a traditional file appender, the log file will probably be created
       under one user's	id and appended	to under a different user's id.	With a
       typical umask of	0002, the file will be created with -rw-rw-r--
       permissions. If a user who's not	in the first user's group subsequently
       appends to the log file,	it will	fail because of	a permission problem.

       Two potential solutions come to mind:

       o   Creating the	file with a umask of 0000 will allow all users to
	   append to the log file. Log4perl's file appender
	   "Log::Log4perl::Appender::File" has an "umask" option that can be
	   set to support this:

	       log4perl.appender.File =	Log::Log4perl::Appender::File
	       log4perl.appender.File.umask = sub { 0000 };

	   This	way, the log file will be created with -rw-rw-rw- permissions
	   and therefore has world write permissions. This might open up the
	   logfile for unwanted	manipulations by arbitrary users, though.

       o   Running the process under an	effective user id of "root" will allow
	   it to write to the log file,	no matter who started the process.
	   However, this is not	a good idea, because of	security concerns.

       Luckily,	under Unix, there's the	syslog daemon which runs as root and
       takes log requests from user processes over a socket and	writes them to
       log files as configured in "/etc/syslog.conf".

       By modifying "/etc/syslog.conf" and HUPing the syslog daemon, you can
       configure new log files:

	   # /etc/syslog.conf
	   ...
	   user.* /some/path/file.log

       Using the "Log::Dispatch::Syslog" appender, which comes with the
       "Log::Log4perl" distribution, you can then send messages	via syslog:

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->init(\<<EOT);
	       log4perl.logger = DEBUG,	app
	       log4perl.appender.app=Log::Dispatch::Syslog
	       log4perl.appender.app.Facility=user
	       log4perl.appender.app.layout=SimpleLayout
	   EOT

	       # Writes	to /some/path/file.log
	   ERROR "Message!";

       This way, the syslog daemon will	solve the permission problem.

       Note that while it is possible to use syslog() without Log4perl (syslog
       supports	log levels, too), traditional syslog setups have a significant
       drawback.

       Without Log4perl's ability to activate logging in only specific parts
       of a system, complex systems will trigger log events all	over the place
       and slow	down execution to a crawl at high debug	levels.

       Remote-controlling logging in the hierarchical parts of an application
       via Log4perl's categories is one	of its most distinguished features.
       It allows for enabling high debug levels	in specified areas without
       noticeable performance impact.

   I want to use UTC instead of	the local time!
       If a layout defines a date, Log::Log4perl uses local time to populate
       it.  If you want	UTC instead, set

	   log4perl.utcDateTimes = 1

       in your configuration. Alternatively, you can set

	   $Log::Log4perl::DateFormat::GMTIME =	1;

       in your program before the first	log statement.

   Can Log4perl	intercept messages written to a	filehandle?
       You have	a function that	prints to a filehandle.	You want to tie	into
       that filehandle and forward all arriving	messages to a Log4perl logger.

       First, let's write a package that ties a	file handle and	forwards it to
       a Log4perl logger:

	   package FileHandleLogger;
	   use Log::Log4perl qw(:levels	get_logger);

	   sub TIEHANDLE {
	      my($class, %options) = @_;

	      my $self = {
		  level	   => $DEBUG,
		  category => '',
		  %options
	      };

	      $self->{logger} =	get_logger($self->{category}),
	      bless $self, $class;
	   }

	   sub PRINT {
	       my($self, @rest)	= @_;
	       $Log::Log4perl::caller_depth++;
	       $self->{logger}->log($self->{level}, @rest);
	       $Log::Log4perl::caller_depth--;
	   }

	   sub PRINTF {
	       my($self, $fmt, @rest) =	@_;
	       $Log::Log4perl::caller_depth++;
	       $self->PRINT(sprintf($fmt, @rest));
	       $Log::Log4perl::caller_depth--;
	   }

	   1;

       Now, if you have	a function like

	   sub function_printing_to_fh {
	       my($fh) = @_;
	       printf $fh "Hi there!\n";
	   }

       which takes a filehandle	and prints something to	it, it can be used
       with Log4perl:

	   use Log::Log4perl qw(:easy);
	   usa FileHandleLogger;

	   Log::Log4perl->easy_init($DEBUG);

	   tie *SOMEHANDLE, 'FileHandleLogger' or
	       die "tie	failed ($!)";

	   function_printing_to_fh(*SOMEHANDLE);
	       # prints	"2007/03/22 21:43:30 Hi	there!"

       If you want, you	can even specify a different log level or category:

	   tie *SOMEHANDLE, 'FileHandleLogger',
	       level =>	$INFO, category	=> "Foo::Bar" or die "tie failed ($!)";

   I want multiline messages rendered line-by-line!
       With the	standard "PatternLayout", if you send a	multiline message to
       an appender as in

	   use Log::Log4perl qw(:easy);
	   Log

       it gets rendered	this way:

	   2007/04/04 23:23:39 multi
	   line
	   message

       If you want each	line to	be rendered separately according to the	layout
       use "Log::Log4perl::Layout::PatternLayout::Multiline":

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->init(\<<EOT);
	     log4perl.category	       = DEBUG,	Screen
	     log4perl.appender.Screen =	Log::Log4perl::Appender::Screen
	     log4perl.appender.Screen.layout = \\
	       Log::Log4perl::Layout::PatternLayout::Multiline
	     log4perl.appender.Screen.layout.ConversionPattern = %d %m %n
	   EOT

	   DEBUG "some\nmultiline\nmessage";

       and you'll get

	   2007/04/04 23:23:39 some
	   2007/04/04 23:23:39 multiline
	   2007/04/04 23:23:39 message

       instead.

   I'm on Windows and I'm getting all these 'redefined'	messages!
       If you're on Windows and	are getting warning messages like

	 Constant subroutine Log::Log4perl::_INTERNAL_DEBUG redefined at
	   C:/Programme/Perl/lib/constant.pm line 103.
	 Subroutine import redefined at
	   C:/Programme/Perl/site/lib/Log/Log4Perl.pm line 69.
	 Subroutine initialized	redefined at
	   C:/Programme/Perl/site/lib/Log/Log4Perl.pm line 207.

       then chances are	that you're using 'Log::Log4Perl' (wrong uppercase P)
       instead of the correct 'Log::Log4perl'. Perl on Windows doesn't handle
       this error well and spits out a slew of confusing warning messages. But
       now you know, just use the correct module name and you'll be fine.

   Log4perl complains that no initialization happened during shutdown!
       If you're using Log4perl	log commands in	DESTROY	methods	of your
       objects,	you might see confusing	messages like

	   Log4perl: Seems like	no initialization happened. Forgot to call init()?
	   Use of uninitialized	value in subroutine entry at
	   /home/y/lib/perl5/site_perl/5.6.1/Log/Log4perl.pm line 134 during global
	   destruction.	(in cleanup) Undefined subroutine &main:: called at
	   /home/y/lib/perl5/site_perl/5.6.1/Log/Log4perl.pm line 134 during global
	   destruction.

       when the	program	shuts down. What's going on?

       This phenomenon happens if you have circular references in your
       objects,	which perl can't clean up when an object goes out of scope but
       waits until global destruction instead. At this time, however, Log4perl
       has already shut	down, so you can't use it anymore.

       For example, here's a simple class which	uses a logger in its DESTROY
       method:

	   package A;
	   use Log::Log4perl qw(:easy);
	   sub new { bless {}, shift }
	   sub DESTROY { DEBUG "Waaah!"; }

       Now, if the main	program	creates	a self-referencing object, like	in

	   package main;
	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

	   my $a = A->new();
	   $a->{selfref} = $a;

       then you'll see the error message shown above during global
       destruction.  How to tackle this	problem?

       First, you should clean up your circular	references before global
       destruction. They will not only cause objects to	be destroyed in	an
       order that's hard to predict, but also eat up memory until the program
       shuts down.

       So, the program above could easily be fixed by putting

	   $a->{selfref} = undef;

       at the end or in	an END handler.	If that's hard to do, use weak
       references:

	   package main;
	   use Scalar::Util qw(weaken);
	   use Log::Log4perl qw(:easy);
	   Log::Log4perl->easy_init($DEBUG);

	   my $a = A->new();
	   $a->{selfref} = weaken $a;

       This allows perl	to clean up the	circular reference when	the object
       goes out	of scope, and doesn't wait until global	destruction.

   How can I access POE	heap values from Log4perl's layout?
       POE is a	framework for creating multitasked applications	running	in a
       single process and a single thread. POE's threads equivalents are
       'sessions' and since they run quasi-simultaneously, you can't use
       Log4perl's global NDC/MDC to hold session-specific data.

       However,	POE already maintains a	data store for every session. It is
       called 'heap' and is just a hash	storing	session-specific data in key-
       value pairs.  To	access this per-session	heap data from a Log4perl
       layout, define a	custom cspec and reference it with the newly defined
       pattern in the layout:

	   use strict;
	   use POE;
	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->init(	\ q{
	       log4perl.logger = DEBUG,	Screen
	       log4perl.appender.Screen	= Log::Log4perl::Appender::Screen
	       log4perl.appender.Screen.layout = PatternLayout
	       log4perl.appender.Screen.layout.ConversionPattern = %U %m%n
	       log4perl.PatternLayout.cspec.U =	\
		   sub { POE::Kernel->get_active_session->get_heap()->{	user } }
	   } );

	   for (qw( Huey Lewey Dewey ))	{
	       POE::Session->create(
		   inline_states => {
		       _start	 => sub	{
			   $_[HEAP]->{user} = $_;
			   POE::Kernel->yield('hello');
		       },
		       hello	 => sub	{
			   DEBUG "I'm here now";
		       }
		   }
	       );
	   }

	   POE::Kernel->run();
	   exit;

       The code	snippet	above defines a	new layout placeholder (called 'cspec'
       in Log4perl) %U which calls a subroutine, retrieves the active session,
       gets its	heap and looks up the entry specified ('user').

       Starting	with Log::Log4perl 1.20, cspecs	also support parameters	in
       curly braces, so	you can	say

	   log4perl.appender.Screen.layout.ConversionPattern = %U{user}	%U{id} %m%n
	   log4perl.PatternLayout.cspec.U = \
		   sub { POE::Kernel->get_active_session-> \
			 get_heap()->{ $_[0]->{curlies}	} }

       and print the POE session heap entries 'user' and 'id' with every
       logged message. For more	details	on cpecs, read the PatternLayout
       manual.

   I want to print something unconditionally!
       Sometimes it's a	script that's supposed to log messages regardless if
       Log4perl	has been initialized or	not. Or	there's	a logging statement
       that's not going	to be suppressed under any circumstances -- many
       people want to have the final word, make	the executive decision,
       because it seems	like the only logical choice.

       But think about it: First off, if a messages is supposed	to be printed,
       where is	it supposed to end up at? STDOUT? STDERR? And are you sure you
       want to set in stone that this message needs to be printed, while
       someone else might find it annoying and wants to	get rid	of it?

       The truth is, there's always going to be	someone	who wants to log a
       messages	at all cost, but also another person who wants to suppress it
       with equal vigilance. There's no	good way to serve these	two
       conflicting desires, someone will always	want to	win at the cost	of
       leaving the other party disappointed.

       So, the best Log4perl offers is the ALWAYS level	for a message that
       even fires if the system	log level is set to $OFF:

	   use Log::Log4perl qw(:easy);

	   Log::Log4perl->easy_init( $OFF );
	   ALWAYS "This	gets logged always. Well, almost always";

       The logger won't	fire, though, if Log4perl hasn't been initialized or
       if someone defines a custom log hurdle that's higher than $OFF.

       Bottom line: Leave the setting of the logging level to the initial Perl
       script -- let their owners decided what they want, no matter how
       tempting	it may be to decide it for them.

   Why doesn't my END handler remove my	log file on Win32?
       If you have code	like

	   use Log::Log4perl qw( :easy );
	   Log::Log4perl->easy_init( { level =>	$DEBUG,	file =>	"my.log" } );
	   END { unlink	"my.log" or die	};

       then you	might be in for	a surprise when	you're running it on Windows,
       because the "unlink()" call in the END handler will complain that the
       file is still in	use.

       What happens in Perl if you have	something like

	   END { print "first end in main\n"; }
	   use Module;
	   END { print "second end in main\n"; }

       and

	   package Module;
	   END { print "end in module\n"; }
	   1;

       is that you get

	   second end in main
	   end in module
	   first end in	main

       because perl stacks the END handlers in reverse order in	which it
       encounters them in the compile phase.

       Log4perl	defines	an END handler that cleans up left-over	appenders
       (e.g.  file appenders which still hold files open), because those
       appenders have circular references and therefore	aren't cleaned up
       otherwise.

       Now if you define an END	handler	after "use Log::Log4perl", it'll
       trigger before Log4perl gets a chance to	clean up, which	isn't a
       problem on Unix where you can delete a file even	if some	process	has a
       handle to it open, but it's a problem on	Win32, where the OS won't let
       you do that.

       The solution is easy, just place	the END	handler	before Log4perl	gets
       loaded, like in

	   END { unlink	"my.log" or die	};
	   use Log::Log4perl qw( :easy );
	   Log::Log4perl->easy_init( { level =>	$DEBUG,	file =>	"my.log" } );

       which will call the END handlers	in the intended	order.

SEE ALSO
       Log::Log4perl

LICENSE
       Copyright 2002-2013 by Mike Schilli <m@perlmeister.com> and Kevin Goess
       <cpan@goess.org>.

       This library is free software; you can redistribute it and/or modify it
       under the same terms as Perl itself.

AUTHOR
       Please contribute patches to the	project	on Github:

	   http://github.com/mschilli/log4perl

       Send bug	reports	or requests for	enhancements to	the authors via	our

       MAILING LIST (questions,	bug reports, suggestions/patches):
       log4perl-devel@lists.sourceforge.net

       Authors (please contact them via	the list above,	not directly): Mike
       Schilli <m@perlmeister.com>, Kevin Goess	<cpan@goess.org>

       Contributors (in	alphabetical order): Ateeq Altaf, Cory Bennett,	Jens
       Berthold, Jeremy	Bopp, Hutton Davidson, Chris R.	Donnelly, Matisse
       Enzer, Hugh Esco, Anthony Foiani, James FitzGibbon, Carl	Franks,	Dennis
       Gregorovic, Andy	Grundman, Paul Harrington, Alexander Hartmaier	David
       Hull, Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter,
       Brett Rann, Peter Rabbitson, Erik Selberg, Aaron	Straup Cope, Lars
       Thegler,	David Viner, Mac Yang.

perl v5.32.1			  2020-07-22				FAQ(3)

NAME | DESCRIPTION | SEE ALSO | LICENSE | AUTHOR

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Log::Log4perl::FAQ&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help