
Log::Log4perl::Appender - Log appender class

use Log::Log4perl;
# Define a logger
my $logger = Log::Log4perl->get_logger("abc.def.ghi");
# Define a layout
my $layout = Log::Log4perl::Layout::PatternLayout->new(
"%d (%F:%L)> %m");
# Define an appender
my $appender = Log::Log4perl::Appender->new(
"Log::Log4perl::Appender::Screen",
name => 'dumpy');
# Set the appender's layout
$appender->layout($layout);
$logger->add_appender($appender);

This class is a wrapper around the Log::Log4perl::Appender appender set.
It also supports the <Log::Dispatch::*> collections of appenders. The module hides the idiosyncrasies of Log::Dispatch (e.g. every dispatcher gotta have a name, but there's no accessor to retrieve it) from Log::Log4perl and yet re-uses the extremely useful variety of dispatchers already created and tested in Log::Dispatch.

The constructor new() takes the name of the appender class to be created as a string (!) argument, optionally followed by a number of appender-specific parameters, for example:
# Define an appender
my $appender = Log::Log4perl::Appender->new(
"Log::Log4perl::Appender::File"
filename => 'out.log');
In case of Log::Dispatch appenders, if no name parameter is specified, the appender object will create a unique one (format appNNN), which can be retrieved later via the name() method:
print "The appender's name is ", $appender->name(), "\n";
Other parameters are specific to the appender class being used. In the case above, the filename parameter specifies the name of the Log::Log4perl::Appender::File dispatcher used.
However, if, for instance, you're using a Log::Dispatch::Email dispatcher to send you email, you'll have to specify from and to email addresses. Every dispatcher is different. Please check the Log::Dispatch::* documentation for the appender used for details on specific requirements.
The new() method will just pass these parameters on to a newly created Log::Dispatch::* object of the specified type.
When it comes to logging, the Log::Log4perl::Appender will transparently relay all messages to the Log::Dispatch::* object it carries in its womb.
The layout() method sets the log layout used by the appender to the format specified by the Log::Log4perl::Layout::* object which is passed to it as a reference. Currently there's two layouts available:
Log::Log4perl::Layout::SimpleLayout
Log::Log4perl::Layout::PatternLayout
Please check the Log::Log4perl::Layout::SimpleLayout and Log::Log4perl::Layout::PatternLayout manual pages for details.

Here's the list of appender modules currently available via Log::Dispatch, if not noted otherwise, written by Dave Rolsky:
Log::Dispatch::ApacheLog
Log::Dispatch::DBI (by Tatsuhiko Miyagawa)
Log::Dispatch::Email,
Log::Dispatch::Email::MailSend,
Log::Dispatch::Email::MailSendmail,
Log::Dispatch::Email::MIMELite
Log::Dispatch::File
Log::Dispatch::FileRotate (by Mark Pfeiffer)
Log::Dispatch::Handle
Log::Dispatch::Screen
Log::Dispatch::Syslog
Log::Dispatch::Tk (by Dominique Dumont)
Log4perl doesn't care which ones you use, they're all handled in the same way via the Log::Log4perl::Appender interface. Please check the well-written manual pages of the Log::Dispatch hierarchy on how to use each one of them.

When calling the appender's log()-Funktion, Log::Log4perl will submit a list of key/value pairs. Entries to the following keys are guaranteed to be present:
Text of the rendered message
Name of the category of the logger that triggered the event.
Log::Log4perl level of the event

Since the Log::Dispatch::File appender truncates log files by default, and most of the time this is not what you want, we've instructed Log::Log4perl to change this behaviour by slipping it the mode => append parameter behind the scenes. So, effectively with Log::Log4perl 0.23, a configuration like
log4perl.category = INFO, FileAppndr
log4perl.appender.FileAppndr = Log::Dispatch::File
log4perl.appender.FileAppndr.filename = test.log
log4perl.appender.FileAppndr.layout = Log::Log4perl::Layout::SimpleLayout
will always append to an existing logfile test.log while if you specifically request clobbering like in
log4perl.category = INFO, FileAppndr
log4perl.appender.FileAppndr = Log::Dispatch::File
log4perl.appender.FileAppndr.filename = test.log
log4perl.appender.FileAppndr.mode = write
log4perl.appender.FileAppndr.layout = Log::Log4perl::Layout::SimpleLayout
it will overwrite an existing log file test.log and start from scratch.

Instead of simple strings, certain appenders are expecting multiple fields as log messages. If a statement like
$logger->debug($ip, $user, "signed in");
causes an off-the-shelf Log::Log4perl::Screen appender to fire, the appender will just concatenate the three message chunks passed to it in order to form a single string. The chunks will be separated by a string defined in $Log::Log4perl::JOIN_MSG_ARRAY_CHAR (defaults to the empty string "").
However, different appenders might choose to interpret the message above differently: An appender like Log::Log4perl::Appender::DBI might take the three arguments passed to the logger and put them in three separate rows into the DB.
The warp_message appender option is used to specify the desired behaviour. If no setting for the appender property
# *** Not defined ***
# log4perl.appender.SomeApp.warp_message
is defined in the Log4perl configuration file, the appender referenced by SomeApp will fall back to the standard behaviour and join all message chunks together, separating them by $Log::Log4perl::JOIN_MSG_ARRAY_CHAR.
If, on the other hand, it is set to a false value, like in
log4perl.appender.SomeApp.layout=NoopLayout
log4perl.appender.SomeApp.warp_message = 0
then the message chunks are passed unmodified to the appender as an array reference. Please note that you need to set the appender's layout to Log::Log4perl::Layout::NoopLayout which just leaves the messages chunks alone instead of formatting them or replacing conversion specifiers.
Please note that the standard appenders in the Log::Dispatch hierarchy will choke on a bunch of messages passed to them as an array reference. You can't use warp_message = 0 (or the function name syntax defined below) on them. Only special appenders like Log::Log4perl::Appender::DBI can deal with this.
If (and now we're getting fancy) an appender expects message chunks, but we would like to pre-inspect and probably modify them before they're actually passed to the appender's log method, an inspection subroutine can be defined with the appender's warp_message property:
log4perl.appender.SomeApp.layout=NoopLayout
log4perl.appender.SomeApp.warp_message = sub { \
$#_ = 2 if @_ > 3; \
return @_; }
The inspection subroutine defined by the warp_message property will receive the list of message chunks, like they were passed to the logger and is expected to return a corrected list. The example above simply limits the argument list to a maximum of three by cutting off excess elements and returning the shortened list.
Also, the warp function can be specified by name like in
log4perl.appender.SomeApp.layout=NoopLayout
log4perl.appender.SomeApp.warp_message = main::filter_my_message
In this example, filter_my_message is a function in the main package, defined like this:
my $COUNTER = 0;
sub filter_my_message {
my @chunks = @_;
unshift @chunks, ++$COUNTER;
return @chunks;
}
The subroutine above will add an ever increasing counter as an additional first field to every message passed to the SomeApp appender -- but not to any other appender in the system.


Mike Schilli, <log4perl@perlmeister.com>