Welcome to the Log::Log4perl recipe of the week. Today:
============================================================
Log::Log4perl Recipe of the Week (#8):
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 behaviour. 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::Dispatch::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 set
$Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE = 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).
Have fun! Until next week.
-- Mike
###################################
# Mike Schilli #
# log...@pe... #
# http://perlmeister.com #
# http://log4perl.sourceforge.net #
###################################
|