summaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
Diffstat (limited to 'README')
-rw-r--r--README2183
1 files changed, 2183 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..52e6602
--- /dev/null
+++ b/README
@@ -0,0 +1,2183 @@
+######################################################################
+ Log::Log4perl 1.46
+######################################################################
+
+NAME
+ Log::Log4perl - Log4j implementation for Perl
+
+SYNOPSIS
+ # Easy mode if you like it simple ...
+ use Log::Log4perl qw(:easy);
+ Log::Log4perl->easy_init($ERROR);
+
+ DEBUG "This doesn't go anywhere";
+ ERROR "This gets logged";
+
+ # ... or standard mode for more features:
+
+ Log::Log4perl::init('/etc/log4perl.conf');
+
+ --or--
+
+ # Check config every 10 secs
+ Log::Log4perl::init_and_watch('/etc/log4perl.conf',10);
+
+ --then--
+
+ $logger = Log::Log4perl->get_logger('house.bedrm.desk.topdrwr');
+
+ $logger->debug('this is a debug message');
+ $logger->info('this is an info message');
+ $logger->warn('etc');
+ $logger->error('..');
+ $logger->fatal('..');
+
+ #####/etc/log4perl.conf###############################
+ log4perl.logger.house = WARN, FileAppndr1
+ log4perl.logger.house.bedroom.desk = DEBUG, FileAppndr1
+
+ log4perl.appender.FileAppndr1 = Log::Log4perl::Appender::File
+ log4perl.appender.FileAppndr1.filename = desk.log
+ log4perl.appender.FileAppndr1.layout = \
+ Log::Log4perl::Layout::SimpleLayout
+ ######################################################
+
+ABSTRACT
+ Log::Log4perl provides a powerful logging API for your application
+
+DESCRIPTION
+ Log::Log4perl lets you remote-control and fine-tune the logging
+ behaviour of your system from the outside. It implements the widely
+ popular (Java-based) Log4j logging package in pure Perl.
+
+ For a detailed tutorial on Log::Log4perl usage, please read
+
+ <http://www.perl.com/pub/a/2002/09/11/log4perl.html>
+
+ Logging beats a debugger if you want to know what's going on in your
+ code during runtime. However, traditional logging packages are too
+ static and generate a flood of log messages in your log files that won't
+ help you.
+
+ "Log::Log4perl" is different. It allows you to control the number of
+ logging messages generated at three different levels:
+
+ * At a central location in your system (either in a configuration file
+ or in the startup code) you specify *which components* (classes,
+ functions) of your system should generate logs.
+
+ * You specify how detailed the logging of these components should be
+ by specifying logging *levels*.
+
+ * You also specify which so-called *appenders* you want to feed your
+ log messages to ("Print it to the screen and also append it to
+ /tmp/my.log") and which format ("Write the date first, then the file
+ name and line number, and then the log message") they should be in.
+
+ This is a very powerful and flexible mechanism. You can turn on and off
+ your logs at any time, specify the level of detail and make that
+ dependent on the subsystem that's currently executed.
+
+ Let me give you an example: You might find out that your system has a
+ problem in the "MySystem::Helpers::ScanDir" component. Turning on
+ detailed debugging logs all over the system would generate a flood of
+ useless log messages and bog your system down beyond recognition. With
+ "Log::Log4perl", however, you can tell the system: "Continue to log only
+ severe errors to the log file. Open a second log file, turn on full
+ debug logs in the "MySystem::Helpers::ScanDir" component and dump all
+ messages originating from there into the new log file". And all this is
+ possible by just changing the parameters in a configuration file, which
+ your system can re-read even while it's running!
+
+How to use it
+ The "Log::Log4perl" package can be initialized in two ways: Either via
+ Perl commands or via a "log4j"-style configuration file.
+
+ Initialize via a configuration file
+ This is the easiest way to prepare your system for using
+ "Log::Log4perl". Use a configuration file like this:
+
+ ############################################################
+ # A simple root logger with a Log::Log4perl::Appender::File
+ # file appender in Perl.
+ ############################################################
+ log4perl.rootLogger=ERROR, LOGFILE
+
+ log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
+ log4perl.appender.LOGFILE.filename=/var/log/myerrs.log
+ log4perl.appender.LOGFILE.mode=append
+
+ log4perl.appender.LOGFILE.layout=PatternLayout
+ log4perl.appender.LOGFILE.layout.ConversionPattern=[%r] %F %L %c - %m%n
+
+ These lines define your standard logger that's appending severe errors
+ to "/var/log/myerrs.log", using the format
+
+ [millisecs] source-filename line-number class - message newline
+
+ Assuming that this configuration file is saved as "log.conf", you need
+ to read it in the startup section of your code, using the following
+ commands:
+
+ use Log::Log4perl;
+ Log::Log4perl->init("log.conf");
+
+ After that's done *somewhere* in the code, you can retrieve logger
+ objects *anywhere* in the code. Note that there's no need to carry any
+ logger references around with your functions and methods. You can get a
+ logger anytime via a singleton mechanism:
+
+ package My::MegaPackage;
+ use Log::Log4perl;
+
+ sub some_method {
+ my($param) = @_;
+
+ my $log = Log::Log4perl->get_logger("My::MegaPackage");
+
+ $log->debug("Debug message");
+ $log->info("Info message");
+ $log->error("Error message");
+
+ ...
+ }
+
+ With the configuration file above, "Log::Log4perl" will write "Error
+ message" to the specified log file, but won't do anything for the
+ "debug()" and "info()" calls, because the log level has been set to
+ "ERROR" for all components in the first line of configuration file shown
+ above.
+
+ Why "Log::Log4perl->get_logger" and not "Log::Log4perl->new"? We don't
+ want to create a new object every time. Usually in OO-Programming, you
+ create an object once and use the reference to it to call its methods.
+ However, this requires that you pass around the object to all functions
+ and the last thing we want is pollute each and every function/method
+ we're using with a handle to the "Logger":
+
+ sub function { # Brrrr!!
+ my($logger, $some, $other, $parameters) = @_;
+ }
+
+ Instead, if a function/method wants a reference to the logger, it just
+ calls the Logger's static "get_logger($category)" method to obtain a
+ reference to the *one and only* possible logger object of a certain
+ category. That's called a *singleton* if you're a Gamma fan.
+
+ How does the logger know which messages it is supposed to log and which
+ ones to suppress? "Log::Log4perl" works with inheritance: The config
+ file above didn't specify anything about "My::MegaPackage". And yet,
+ we've defined a logger of the category "My::MegaPackage". In this case,
+ "Log::Log4perl" will walk up the namespace hierarchy ("My" and then
+ we're at the root) to figure out if a log level is defined somewhere. In
+ the case above, the log level at the root (root *always* defines a log
+ level, but not necessarily an appender) defines that the log level is
+ supposed to be "ERROR" -- meaning that *DEBUG* and *INFO* messages are
+ suppressed. Note that this 'inheritance' is unrelated to Perl's class
+ inheritance, it is merely related to the logger namespace. By the way,
+ if you're ever in doubt about what a logger's category is, use
+ "$logger->category()" to retrieve it.
+
+ Log Levels
+ There are six predefined log levels: "FATAL", "ERROR", "WARN", "INFO",
+ "DEBUG", and "TRACE" (in descending priority). Your configured logging
+ level has to at least match the priority of the logging message.
+
+ If your configured logging level is "WARN", then messages logged with
+ "info()", "debug()", and "trace()" will be suppressed. "fatal()",
+ "error()" and "warn()" will make their way through, because their
+ priority is higher or equal than the configured setting.
+
+ Instead of calling the methods
+
+ $logger->trace("..."); # Log a trace message
+ $logger->debug("..."); # Log a debug message
+ $logger->info("..."); # Log a info message
+ $logger->warn("..."); # Log a warn message
+ $logger->error("..."); # Log a error message
+ $logger->fatal("..."); # Log a fatal message
+
+ you could also call the "log()" method with the appropriate level using
+ the constants defined in "Log::Log4perl::Level":
+
+ use Log::Log4perl::Level;
+
+ $logger->log($TRACE, "...");
+ $logger->log($DEBUG, "...");
+ $logger->log($INFO, "...");
+ $logger->log($WARN, "...");
+ $logger->log($ERROR, "...");
+ $logger->log($FATAL, "...");
+
+ This form is rarely used, but it comes in handy if you want to log at
+ different levels depending on an exit code of a function:
+
+ $logger->log( $exit_level{ $rc }, "...");
+
+ As for needing more logging levels than these predefined ones: It's
+ usually best to steer your logging behaviour via the category mechanism
+ instead.
+
+ If you need to find out if the currently configured logging level would
+ allow a logger's logging statement to go through, use the logger's
+ "is_*level*()" methods:
+
+ $logger->is_trace() # True if trace messages would go through
+ $logger->is_debug() # True if debug messages would go through
+ $logger->is_info() # True if info messages would go through
+ $logger->is_warn() # True if warn messages would go through
+ $logger->is_error() # True if error messages would go through
+ $logger->is_fatal() # True if fatal messages would go through
+
+ Example: "$logger->is_warn()" returns true if the logger's current
+ level, as derived from either the logger's category (or, in absence of
+ that, one of the logger's parent's level setting) is $WARN, $ERROR or
+ $FATAL.
+
+ Also available are a series of more Java-esque functions which return
+ the same values. These are of the format "is*Level*Enabled()", so
+ "$logger->isDebugEnabled()" is synonymous to "$logger->is_debug()".
+
+ These level checking functions will come in handy later, when we want to
+ block unnecessary expensive parameter construction in case the logging
+ level is too low to log the statement anyway, like in:
+
+ if($logger->is_error()) {
+ $logger->error("Erroneous array: @super_long_array");
+ }
+
+ If we had just written
+
+ $logger->error("Erroneous array: @super_long_array");
+
+ then Perl would have interpolated @super_long_array into the string via
+ an expensive operation only to figure out shortly after that the string
+ can be ignored entirely because the configured logging level is lower
+ than $ERROR.
+
+ The to-be-logged message passed to all of the functions described above
+ can consist of an arbitrary number of arguments, which the logging
+ functions just chain together to a single string. Therefore
+
+ $logger->debug("Hello ", "World", "!"); # and
+ $logger->debug("Hello World!");
+
+ are identical.
+
+ Note that even if one of the methods above returns true, it doesn't
+ necessarily mean that the message will actually get logged. What
+ is_debug() checks is that the logger used is configured to let a message
+ of the given priority (DEBUG) through. But after this check, Log4perl
+ will eventually apply custom filters and forward the message to one or
+ more appenders. None of this gets checked by is_xxx(), for the simple
+ reason that it's impossible to know what a custom filter does with a
+ message without having the actual message or what an appender does to a
+ message without actually having it log it.
+
+ Log and die or warn
+ Often, when you croak / carp / warn / die, you want to log those
+ messages. Rather than doing the following:
+
+ $logger->fatal($err) && die($err);
+
+ you can use the following:
+
+ $logger->logdie($err);
+
+ And if instead of using
+
+ warn($message);
+ $logger->warn($message);
+
+ to both issue a warning via Perl's warn() mechanism and make sure you
+ have the same message in the log file as well, use:
+
+ $logger->logwarn($message);
+
+ Since there is an ERROR level between WARN and FATAL, there are two
+ additional helper functions in case you'd like to use ERROR for either
+ warn() or die():
+
+ $logger->error_warn();
+ $logger->error_die();
+
+ Finally, there's the Carp functions that, in addition to logging, also
+ pass the stringified message to their companions in the Carp package:
+
+ $logger->logcarp(); # warn w/ 1-level stack trace
+ $logger->logcluck(); # warn w/ full stack trace
+ $logger->logcroak(); # die w/ 1-level stack trace
+ $logger->logconfess(); # die w/ full stack trace
+
+ Appenders
+ If you don't define any appenders, nothing will happen. Appenders will
+ be triggered whenever the configured logging level requires a message to
+ be logged and not suppressed.
+
+ "Log::Log4perl" doesn't define any appenders by default, not even the
+ root logger has one.
+
+ "Log::Log4perl" already comes with a standard set of appenders:
+
+ Log::Log4perl::Appender::Screen
+ Log::Log4perl::Appender::ScreenColoredLevels
+ Log::Log4perl::Appender::File
+ Log::Log4perl::Appender::Socket
+ Log::Log4perl::Appender::DBI
+ Log::Log4perl::Appender::Synchronized
+ Log::Log4perl::Appender::RRDs
+
+ to log to the screen, to files and to databases.
+
+ On CPAN, you can find additional appenders like
+
+ Log::Log4perl::Layout::XMLLayout
+
+ by Guido Carls <gcarls@cpan.org>. It allows for hooking up Log::Log4perl
+ with the graphical Log Analyzer Chainsaw (see "Can I use Log::Log4perl
+ with log4j's Chainsaw?" in Log::Log4perl::FAQ).
+
+ Additional Appenders via Log::Dispatch
+ "Log::Log4perl" also supports *Dave Rolskys* excellent "Log::Dispatch"
+ framework which implements a wide variety of different appenders.
+
+ Here's the list of appender modules currently available via
+ "Log::Dispatch":
+
+ 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)
+
+ Please note that in order to use any of these additional appenders, you
+ have to fetch Log::Dispatch from CPAN and install it. Also the
+ particular appender you're using might require installing the particular
+ module.
+
+ For additional information on appenders, please check the
+ Log::Log4perl::Appender manual page.
+
+ Appender Example
+ Now let's assume that we want to log "info()" or higher prioritized
+ messages in the "Foo::Bar" category to both STDOUT and to a log file,
+ say "test.log". In the initialization section of your system, just
+ define two appenders using the readily available
+ "Log::Log4perl::Appender::File" and "Log::Log4perl::Appender::Screen"
+ modules:
+
+ use Log::Log4perl;
+
+ # Configuration in a string ...
+ my $conf = q(
+ log4perl.category.Foo.Bar = INFO, Logfile, Screen
+
+ log4perl.appender.Logfile = Log::Log4perl::Appender::File
+ log4perl.appender.Logfile.filename = test.log
+ log4perl.appender.Logfile.layout = Log::Log4perl::Layout::PatternLayout
+ log4perl.appender.Logfile.layout.ConversionPattern = [%r] %F %L %m%n
+
+ log4perl.appender.Screen = Log::Log4perl::Appender::Screen
+ log4perl.appender.Screen.stderr = 0
+ log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
+ );
+
+ # ... passed as a reference to init()
+ Log::Log4perl::init( \$conf );
+
+ Once the initialization shown above has happened once, typically in the
+ startup code of your system, just use the defined logger anywhere in
+ your system:
+
+ ##########################
+ # ... in some function ...
+ ##########################
+ my $log = Log::Log4perl::get_logger("Foo::Bar");
+
+ # Logs both to STDOUT and to the file test.log
+ $log->info("Important Info!");
+
+ The "layout" settings specified in the configuration section define the
+ format in which the message is going to be logged by the specified
+ appender. The format shown for the file appender is logging not only the
+ message but also the number of milliseconds since the program has
+ started (%r), the name of the file the call to the logger has happened
+ and the line number there (%F and %L), the message itself (%m) and a
+ OS-specific newline character (%n):
+
+ [187] ./myscript.pl 27 Important Info!
+
+ The screen appender above, on the other hand, uses a "SimpleLayout",
+ which logs the debug level, a hyphen (-) and the log message:
+
+ INFO - Important Info!
+
+ For more detailed info on layout formats, see "Log Layouts".
+
+ In the configuration sample above, we chose to define a *category*
+ logger ("Foo::Bar"). This will cause only messages originating from this
+ specific category logger to be logged in the defined format and
+ locations.
+
+ Logging newlines
+ There's some controversy between different logging systems as to when
+ and where newlines are supposed to be added to logged messages.
+
+ The Log4perl way is that a logging statement *should not* contain a
+ newline:
+
+ $logger->info("Some message");
+ $logger->info("Another message");
+
+ If this is supposed to end up in a log file like
+
+ Some message
+ Another message
+
+ then an appropriate appender layout like "%m%n" will take care of adding
+ a newline at the end of each message to make sure every message is
+ printed on its own line.
+
+ Other logging systems, Log::Dispatch in particular, recommend adding the
+ newline to the log statement. This doesn't work well, however, if you,
+ say, replace your file appender by a database appender, and all of a
+ sudden those newlines scattered around the code don't make sense
+ anymore.
+
+ Assigning matching layouts to different appenders and leaving newlines
+ out of the code solves this problem. If you inherited code that has
+ logging statements with newlines and want to make it work with Log4perl,
+ read the Log::Log4perl::Layout::PatternLayout documentation on how to
+ accomplish that.
+
+ Configuration files
+ As shown above, you can define "Log::Log4perl" loggers both from within
+ your Perl code or from configuration files. The latter have the
+ unbeatable advantage that you can modify your system's logging behaviour
+ without interfering with the code at all. So even if your code is being
+ run by somebody who's totally oblivious to Perl, they still can adapt
+ the module's logging behaviour to their needs.
+
+ "Log::Log4perl" has been designed to understand "Log4j" configuration
+ files -- as used by the original Java implementation. Instead of
+ reiterating the format description in [2], let me just list three
+ examples (also derived from [2]), which should also illustrate how it
+ works:
+
+ log4j.rootLogger=DEBUG, A1
+ log4j.appender.A1=org.apache.log4j.ConsoleAppender
+ log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+ log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c %x - %m%n
+
+ This enables messages of priority "DEBUG" or higher in the root
+ hierarchy and has the system write them to the console.
+ "ConsoleAppender" is a Java appender, but "Log::Log4perl" jumps through
+ a significant number of hoops internally to map these to their
+ corresponding Perl classes, "Log::Log4perl::Appender::Screen" in this
+ case.
+
+ Second example:
+
+ log4perl.rootLogger=DEBUG, A1
+ log4perl.appender.A1=Log::Log4perl::Appender::Screen
+ log4perl.appender.A1.layout=PatternLayout
+ log4perl.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n
+ log4perl.logger.com.foo=WARN
+
+ This defines two loggers: The root logger and the "com.foo" logger. The
+ root logger is easily triggered by debug-messages, but the "com.foo"
+ logger makes sure that messages issued within the "Com::Foo" component
+ and below are only forwarded to the appender if they're of priority
+ *warning* or higher.
+
+ Note that the "com.foo" logger doesn't define an appender. Therefore, it
+ will just propagate the message up the hierarchy until the root logger
+ picks it up and forwards it to the one and only appender of the root
+ category, using the format defined for it.
+
+ Third example:
+
+ log4j.rootLogger=DEBUG, stdout, R
+ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+ log4j.appender.stdout.layout.ConversionPattern=%5p (%F:%L) - %m%n
+ log4j.appender.R=org.apache.log4j.RollingFileAppender
+ log4j.appender.R.File=example.log
+ log4j.appender.R.layout=org.apache.log4j.PatternLayout
+ log4j.appender.R.layout.ConversionPattern=%p %c - %m%n
+
+ The root logger defines two appenders here: "stdout", which uses
+ "org.apache.log4j.ConsoleAppender" (ultimately mapped by "Log::Log4perl"
+ to Log::Log4perl::Appender::Screen) to write to the screen. And "R", a
+ "org.apache.log4j.RollingFileAppender" (mapped by "Log::Log4perl" to
+ Log::Dispatch::FileRotate with the "File" attribute specifying the log
+ file.
+
+ See Log::Log4perl::Config for more examples and syntax explanations.
+
+ Log Layouts
+ If the logging engine passes a message to an appender, because it thinks
+ it should be logged, the appender doesn't just write it out haphazardly.
+ There's ways to tell the appender how to format the message and add all
+ sorts of interesting data to it: The date and time when the event
+ happened, the file, the line number, the debug level of the logger and
+ others.
+
+ There's currently two layouts defined in "Log::Log4perl":
+ "Log::Log4perl::Layout::SimpleLayout" and
+ "Log::Log4perl::Layout::PatternLayout":
+
+ "Log::Log4perl::SimpleLayout"
+ formats a message in a simple way and just prepends it by the debug
+ level and a hyphen: ""$level - $message", for example "FATAL - Can't
+ open password file".
+
+ "Log::Log4perl::Layout::PatternLayout"
+ on the other hand is very powerful and allows for a very flexible
+ format in "printf"-style. The format string can contain a number of
+ placeholders which will be replaced by the logging engine when it's
+ time to log the message:
+
+ %c Category of the logging event.
+ %C Fully qualified package (or class) name of the caller
+ %d Current date in yyyy/MM/dd hh:mm:ss format
+ %F File where the logging event occurred
+ %H Hostname (if Sys::Hostname is available)
+ %l Fully qualified name of the calling method followed by the
+ callers source the file name and line number between
+ parentheses.
+ %L Line number within the file where the log statement was issued
+ %m The message to be logged
+ %m{chomp} The message to be logged, stripped off a trailing newline
+ %M Method or function where the logging request was issued
+ %n Newline (OS-independent)
+ %p Priority of the logging event
+ %P pid of the current process
+ %r Number of milliseconds elapsed from program start to logging
+ event
+ %R Number of milliseconds elapsed from last logging event to
+ current logging event
+ %T A stack trace of functions called
+ %x The topmost NDC (see below)
+ %X{key} The entry 'key' of the MDC (see below)
+ %% A literal percent (%) sign
+
+ NDC and MDC are explained in "Nested Diagnostic Context (NDC)" and
+ "Mapped Diagnostic Context (MDC)".
+
+ Also, %d can be fine-tuned to display only certain characteristics
+ of a date, according to the SimpleDateFormat in the Java World
+ (<http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.h
+ tml>)
+
+ In this way, %d{HH:mm} displays only hours and minutes of the
+ current date, while %d{yy, EEEE} displays a two-digit year, followed
+ by a spelled-out (like "Wednesday").
+
+ Similar options are available for shrinking the displayed category
+ or limit file/path components, %F{1} only displays the source file
+ *name* without any path components while %F logs the full path.
+ %c{2} only logs the last two components of the current category,
+ "Foo::Bar::Baz" becomes "Bar::Baz" and saves space.
+
+ If those placeholders aren't enough, then you can define your own
+ right in the config file like this:
+
+ log4perl.PatternLayout.cspec.U = sub { return "UID $<" }
+
+ See Log::Log4perl::Layout::PatternLayout for further details on
+ customized specifiers.
+
+ Please note that the subroutines you're defining in this way are
+ going to be run in the "main" namespace, so be sure to fully qualify
+ functions and variables if they're located in different packages.
+
+ 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(). Alternatively you can supply a restricted
+ set of Perl opcodes that can be embedded in the config file as
+ described in "Restricting what Opcodes can be in a Perl Hook".
+
+ All placeholders are quantifiable, just like in *printf*. Following this
+ tradition, "%-20c" will reserve 20 chars for the category and
+ left-justify it.
+
+ For more details on logging and how to use the flexible and the simple
+ format, check out the original "log4j" website under
+
+ SimpleLayout
+ <http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/SimpleLayo
+ ut.html> and PatternLayout
+ <http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLay
+ out.html>
+
+ Penalties
+ Logging comes with a price tag. "Log::Log4perl" has been optimized to
+ allow for maximum performance, both with logging enabled and disabled.
+
+ But you need to be aware that there's a small hit every time your code
+ encounters a log statement -- no matter if logging is enabled or not.
+ "Log::Log4perl" has been designed to keep this so low that it will be
+ unnoticeable to most applications.
+
+ Here's a couple of tricks which help "Log::Log4perl" to avoid
+ unnecessary delays:
+
+ You can save serious time if you're logging something like
+
+ # Expensive in non-debug mode!
+ for (@super_long_array) {
+ $logger->debug("Element: $_");
+ }
+
+ and @super_long_array is fairly big, so looping through it is pretty
+ expensive. Only you, the programmer, knows that going through that "for"
+ loop can be skipped entirely if the current logging level for the actual
+ component is higher than "debug". In this case, use this instead:
+
+ # Cheap in non-debug mode!
+ if($logger->is_debug()) {
+ for (@super_long_array) {
+ $logger->debug("Element: $_");
+ }
+ }
+
+ If you're afraid that generating the parameters to the logging function
+ is fairly expensive, use closures:
+
+ # Passed as subroutine ref
+ use Data::Dumper;
+ $logger->debug(sub { Dumper($data) } );
+
+ This won't unravel $data via Dumper() unless it's actually needed
+ because it's logged.
+
+ Also, Log::Log4perl lets you specify arguments to logger functions in
+ *message output filter syntax*:
+
+ $logger->debug("Structure: ",
+ { filter => \&Dumper,
+ value => $someref });
+
+ In this way, shortly before Log::Log4perl sending the message out to any
+ appenders, it will be searching all arguments for hash references and
+ treat them in a special way:
+
+ It will invoke the function given as a reference with the "filter" key
+ ("Data::Dumper::Dumper()") and pass it the value that came with the key
+ named "value" as an argument. The anonymous hash in the call above will
+ be replaced by the return value of the filter function.
+
+Categories
+ Categories are also called "Loggers" in Log4perl, both refer to the same
+ thing and these terms are used interchangeably. "Log::Log4perl" uses
+ *categories* to determine if a log statement in a component should be
+ executed or suppressed at the current logging level. Most of the time,
+ these categories are just the classes the log statements are located in:
+
+ package Candy::Twix;
+
+ sub new {
+ my $logger = Log::Log4perl->get_logger("Candy::Twix");
+ $logger->debug("Creating a new Twix bar");
+ bless {}, shift;
+ }
+
+ # ...
+
+ package Candy::Snickers;
+
+ sub new {
+ my $logger = Log::Log4perl->get_logger("Candy.Snickers");
+ $logger->debug("Creating a new Snickers bar");
+ bless {}, shift;
+ }
+
+ # ...
+
+ package main;
+ Log::Log4perl->init("mylogdefs.conf");
+
+ # => "LOG> Creating a new Snickers bar"
+ my $first = Candy::Snickers->new();
+ # => "LOG> Creating a new Twix bar"
+ my $second = Candy::Twix->new();
+
+ Note that you can separate your category hierarchy levels using either
+ dots like in Java (.) or double-colons (::) like in Perl. Both notations
+ are equivalent and are handled the same way internally.
+
+ However, categories are just there to make use of inheritance: if you
+ invoke a logger in a sub-category, it will bubble up the hierarchy and
+ call the appropriate appenders. Internally, categories are not related
+ to the class hierarchy of the program at all -- they're purely virtual.
+ You can use arbitrary categories -- for example in the following
+ program, which isn't oo-style, but procedural:
+
+ sub print_portfolio {
+
+ my $log = Log::Log4perl->get_logger("user.portfolio");
+ $log->debug("Quotes requested: @_");
+
+ for(@_) {
+ print "$_: ", get_quote($_), "\n";
+ }
+ }
+
+ sub get_quote {
+
+ my $log = Log::Log4perl->get_logger("internet.quotesystem");
+ $log->debug("Fetching quote: $_[0]");
+
+ return yahoo_quote($_[0]);
+ }
+
+ The logger in first function, "print_portfolio", is assigned the
+ (virtual) "user.portfolio" category. Depending on the "Log4perl"
+ configuration, this will either call a "user.portfolio" appender, a
+ "user" appender, or an appender assigned to root -- without
+ "user.portfolio" having any relevance to the class system used in the
+ program. The logger in the second function adheres to the
+ "internet.quotesystem" category -- again, maybe because it's bundled
+ with other Internet functions, but not because there would be a class of
+ this name somewhere.
+
+ However, be careful, don't go overboard: if you're developing a system
+ in object-oriented style, using the class hierarchy is usually your best
+ choice. Think about the people taking over your code one day: The class
+ hierarchy is probably what they know right up front, so it's easy for
+ them to tune the logging to their needs.
+
+ Turn off a component
+ "Log4perl" doesn't only allow you to selectively switch *on* a category
+ of log messages, you can also use the mechanism to selectively *disable*
+ logging in certain components whereas logging is kept turned on in
+ higher-level categories. This mechanism comes in handy if you find that
+ while bumping up the logging level of a high-level (i. e. close to root)
+ category, that one component logs more than it should,
+
+ Here's how it works:
+
+ ############################################################
+ # Turn off logging in a lower-level category while keeping
+ # it active in higher-level categories.
+ ############################################################
+ log4perl.rootLogger=DEBUG, LOGFILE
+ log4perl.logger.deep.down.the.hierarchy = ERROR, LOGFILE
+
+ # ... Define appenders ...
+
+ This way, log messages issued from within "Deep::Down::The::Hierarchy"
+ and below will be logged only if they're "ERROR" or worse, while in all
+ other system components even "DEBUG" messages will be logged.
+
+ Return Values
+ All logging methods return values indicating if their message actually
+ reached one or more appenders. If the message has been suppressed
+ because of level constraints, "undef" is returned.
+
+ For example,
+
+ my $ret = $logger->info("Message");
+
+ will return "undef" if the system debug level for the current category
+ is not "INFO" or more permissive. If Log::Log4perl forwarded the message
+ to one or more appenders, the number of appenders is returned.
+
+ If appenders decide to veto on the message with an appender threshold,
+ the log method's return value will have them excluded. This means that
+ if you've got one appender holding an appender threshold and you're
+ logging a message which passes the system's log level hurdle but not the
+ appender threshold, 0 will be returned by the log function.
+
+ The bottom line is: Logging functions will return a *true* value if the
+ message made it through to one or more appenders and a *false* value if
+ it didn't. This allows for constructs like
+
+ $logger->fatal("@_") or print STDERR "@_\n";
+
+ which will ensure that the fatal message isn't lost if the current level
+ is lower than FATAL or printed twice if the level is acceptable but an
+ appender already points to STDERR.
+
+ Pitfalls with Categories
+ Be careful with just blindly reusing the system's packages as
+ categories. If you do, you'll get into trouble with inherited methods.
+ Imagine the following class setup:
+
+ use Log::Log4perl;
+
+ ###########################################
+ package Bar;
+ ###########################################
+ sub new {
+ my($class) = @_;
+ my $logger = Log::Log4perl::get_logger(__PACKAGE__);
+ $logger->debug("Creating instance");
+ bless {}, $class;
+ }
+ ###########################################
+ package Bar::Twix;
+ ###########################################
+ our @ISA = qw(Bar);
+
+ ###########################################
+ package main;
+ ###########################################
+ Log::Log4perl->init(\ qq{
+ log4perl.category.Bar.Twix = DEBUG, Screen
+ log4perl.appender.Screen = Log::Log4perl::Appender::Screen
+ log4perl.appender.Screen.layout = SimpleLayout
+ });
+
+ my $bar = Bar::Twix->new();
+
+ "Bar::Twix" just inherits everything from "Bar", including the
+ constructor "new()". Contrary to what you might be thinking at first,
+ this won't log anything. Reason for this is the "get_logger()" call in
+ package "Bar", which will always get a logger of the "Bar" category,
+ even if we call "new()" via the "Bar::Twix" package, which will make
+ perl go up the inheritance tree to actually execute "Bar::new()". Since
+ we've only defined logging behaviour for "Bar::Twix" in the
+ configuration file, nothing will happen.
+
+ This can be fixed by changing the "get_logger()" method in "Bar::new()"
+ to obtain a logger of the category matching the *actual* class of the
+ object, like in
+
+ # ... in Bar::new() ...
+ my $logger = Log::Log4perl::get_logger( $class );
+
+ In a method other than the constructor, the class name of the actual
+ object can be obtained by calling "ref()" on the object reference, so
+
+ package BaseClass;
+ use Log::Log4perl qw( get_logger );
+
+ sub new {
+ bless {}, shift;
+ }
+
+ sub method {
+ my( $self ) = @_;
+
+ get_logger( ref $self )->debug( "message" );
+ }
+
+ package SubClass;
+ our @ISA = qw(BaseClass);
+
+ is the recommended pattern to make sure that
+
+ my $sub = SubClass->new();
+ $sub->meth();
+
+ starts logging if the "SubClass" category (and not the "BaseClass"
+ category has logging enabled at the DEBUG level.
+
+ Initialize once and only once
+ It's important to realize that Log::Log4perl gets initialized once and
+ only once, typically at the start of a program or system. Calling
+ "init()" more than once will cause it to clobber the existing
+ configuration and *replace* it by the new one.
+
+ If you're in a traditional CGI environment, where every request is
+ handled by a new process, calling "init()" every time is fine. In
+ persistent environments like "mod_perl", however, Log::Log4perl should
+ be initialized either at system startup time (Apache offers startup
+ handlers for that) or via
+
+ # Init or skip if already done
+ Log::Log4perl->init_once($conf_file);
+
+ "init_once()" is identical to "init()", just with the exception that it
+ will leave a potentially existing configuration alone and will only call
+ "init()" if Log::Log4perl hasn't been initialized yet.
+
+ If you're just curious if Log::Log4perl has been initialized yet, the
+ check
+
+ if(Log::Log4perl->initialized()) {
+ # Yes, Log::Log4perl has already been initialized
+ } else {
+ # No, not initialized yet ...
+ }
+
+ can be used.
+
+ If you're afraid that the components of your system are stepping on each
+ other's toes or if you are thinking that different components should
+ initialize Log::Log4perl separately, try to consolidate your system to
+ use a centralized Log4perl configuration file and use Log4perl's
+ *categories* to separate your components.
+
+ Custom Filters
+ Log4perl allows the use of customized filters in its appenders to
+ control the output of messages. These filters might grep for certain
+ text chunks in a message, verify that its priority matches or exceeds a
+ certain level or that this is the 10th time the same message has been
+ submitted -- and come to a log/no log decision based upon these
+ circumstantial facts.
+
+ Check out Log::Log4perl::Filter for detailed instructions on how to use
+ them.
+
+ Performance
+ The performance of Log::Log4perl calls obviously depends on a lot of
+ things. But to give you a general idea, here's some rough numbers:
+
+ On a Pentium 4 Linux box at 2.4 GHz, you'll get through
+
+ * 500,000 suppressed log statements per second
+
+ * 30,000 logged messages per second (using an in-memory appender)
+
+ * init_and_watch delay mode: 300,000 suppressed, 30,000 logged.
+ init_and_watch signal mode: 450,000 suppressed, 30,000 logged.
+
+ Numbers depend on the complexity of the Log::Log4perl configuration. For
+ a more detailed benchmark test, check the "docs/benchmark.results.txt"
+ document in the Log::Log4perl distribution.
+
+Cool Tricks
+ Here's a collection of useful tricks for the advanced "Log::Log4perl"
+ user. For more, check the FAQ, either in the distribution
+ (Log::Log4perl::FAQ) or on <http://log4perl.sourceforge.net>.
+
+ Shortcuts
+ When getting an instance of a logger, instead of saying
+
+ use Log::Log4perl;
+ my $logger = Log::Log4perl->get_logger();
+
+ it's often more convenient to import the "get_logger" method from
+ "Log::Log4perl" into the current namespace:
+
+ use Log::Log4perl qw(get_logger);
+ my $logger = get_logger();
+
+ Please note this difference: To obtain the root logger, please use
+ "get_logger("")", call it without parameters ("get_logger()"), you'll
+ get the logger of a category named after the current package.
+ "get_logger()" is equivalent to "get_logger(__PACKAGE__)".
+
+ Alternative initialization
+ Instead of having "init()" read in a configuration file by specifying a
+ file name or passing it a reference to an open filehandle
+ ("Log::Log4perl->init( \*FILE )"), you can also pass in a reference to a
+ string, containing the content of the file:
+
+ Log::Log4perl->init( \$config_text );
+
+ Also, if you've got the "name=value" pairs of the configuration in a
+ hash, you can just as well initialize "Log::Log4perl" with a reference
+ to it:
+
+ my %key_value_pairs = (
+ "log4perl.rootLogger" => "ERROR, LOGFILE",
+ "log4perl.appender.LOGFILE" => "Log::Log4perl::Appender::File",
+ ...
+ );
+
+ Log::Log4perl->init( \%key_value_pairs );
+
+ Or also you can use a URL, see below:
+
+ Using LWP to parse URLs
+ (This section borrowed from XML::DOM::Parser by T.J. Mather).
+
+ The init() function now also supports URLs, e.g.
+ *http://www.erols.com/enno/xsa.xml*. It uses LWP to download the file
+ and then calls parse() on the resulting string. By default it will use a
+ LWP::UserAgent that is created as follows:
+
+ use LWP::UserAgent;
+ $LWP_USER_AGENT = LWP::UserAgent->new;
+ $LWP_USER_AGENT->env_proxy;
+
+ Note that env_proxy reads proxy settings from environment variables,
+ which is what I need to do to get thru our firewall. If you want to use
+ a different LWP::UserAgent, you can set it with
+
+ Log::Log4perl::Config::set_LWP_UserAgent($my_agent);
+
+ Currently, LWP is used when the filename (passed to parsefile) starts
+ with one of the following URL schemes: http, https, ftp, wais, gopher,
+ or file (followed by a colon.)
+
+ Don't use this feature with init_and_watch().
+
+ Automatic reloading of changed configuration files
+ Instead of just statically initializing Log::Log4perl via
+
+ Log::Log4perl->init($conf_file);
+
+ there's a way to have Log::Log4perl periodically check for changes in
+ the configuration and reload it if necessary:
+
+ Log::Log4perl->init_and_watch($conf_file, $delay);
+
+ In this mode, Log::Log4perl will examine the configuration file
+ $conf_file every $delay seconds for changes via the file's last
+ modification timestamp. If the file has been updated, it will be
+ reloaded and replace the current Log::Log4perl configuration.
+
+ The way this works is that with every logger function called (debug(),
+ is_debug(), etc.), Log::Log4perl will check if the delay interval has
+ expired. If so, it will run a -M file check on the configuration file.
+ If its timestamp has been modified, the current configuration will be
+ dumped and new content of the file will be loaded.
+
+ This convenience comes at a price, though: Calling time() with every
+ logging function call, especially the ones that are "suppressed" (!),
+ will slow down these Log4perl calls by about 40%.
+
+ To alleviate this performance hit a bit, "init_and_watch()" can be
+ configured to listen for a Unix signal to reload the configuration
+ instead:
+
+ Log::Log4perl->init_and_watch($conf_file, 'HUP');
+
+ This will set up a signal handler for SIGHUP and reload the
+ configuration if the application receives this signal, e.g. via the
+ "kill" command:
+
+ kill -HUP pid
+
+ where "pid" is the process ID of the application. This will bring you
+ back to about 85% of Log::Log4perl's normal execution speed for
+ suppressed statements. For details, check out "Performance". For more
+ info on the signal handler, look for "SIGNAL MODE" in
+ Log::Log4perl::Config::Watch.
+
+ If you have a somewhat long delay set between physical config file
+ checks or don't want to use the signal associated with the config file
+ watcher, you can trigger a configuration reload at the next possible
+ time by calling "Log::Log4perl::Config->watcher->force_next_check()".
+
+ One thing to watch out for: If the configuration file contains a syntax
+ or other fatal error, a running application will stop with "die" if this
+ damaged configuration will be loaded during runtime, triggered either by
+ a signal or if the delay period expired and the change is detected. This
+ behaviour might change in the future.
+
+ To allow the application to intercept and control a configuration reload
+ in init_and_watch mode, a callback can be specified:
+
+ Log::Log4perl->init_and_watch($conf_file, 10, {
+ preinit_callback => \&callback });
+
+ If Log4perl determines that the configuration needs to be reloaded, it
+ will call the "preinit_callback" function without parameters. If the
+ callback returns a true value, Log4perl will proceed and reload the
+ configuration. If the callback returns a false value, Log4perl will keep
+ the old configuration and skip reloading it until the next time around.
+ Inside the callback, an application can run all kinds of checks,
+ including accessing the configuration file, which is available via
+ "Log::Log4perl::Config->watcher()->file()".
+
+ Variable Substitution
+ To avoid having to retype the same expressions over and over again,
+ Log::Log4perl's configuration files support simple variable
+ substitution. New variables are defined simply by adding
+
+ varname = value
+
+ lines to the configuration file before using
+
+ ${varname}
+
+ afterwards to recall the assigned values. Here's an example:
+
+ layout_class = Log::Log4perl::Layout::PatternLayout
+ layout_pattern = %d %F{1} %L> %m %n
+
+ log4perl.category.Bar.Twix = WARN, Logfile, Screen
+
+ log4perl.appender.Logfile = Log::Log4perl::Appender::File
+ log4perl.appender.Logfile.filename = test.log
+ log4perl.appender.Logfile.layout = ${layout_class}
+ log4perl.appender.Logfile.layout.ConversionPattern = ${layout_pattern}
+
+ log4perl.appender.Screen = Log::Log4perl::Appender::Screen
+ log4perl.appender.Screen.layout = ${layout_class}
+ log4perl.appender.Screen.layout.ConversionPattern = ${layout_pattern}
+
+ This is a convenient way to define two appenders with the same layout
+ without having to retype the pattern definitions.
+
+ Variable substitution via "${varname}" will first try to find an
+ explicitly defined variable. If that fails, it will check your shell's
+ environment for a variable of that name. If that also fails, the program
+ will "die()".
+
+ Perl Hooks in the Configuration File
+ If some of the values used in the Log4perl configuration file need to be
+ dynamically modified by the program, use Perl hooks:
+
+ log4perl.appender.File.filename = \
+ sub { return getLogfileName(); }
+
+ Each value starting with the string "sub {..." is interpreted as Perl
+ code to be executed at the time the application parses the configuration
+ via "Log::Log4perl::init()". The return value of the subroutine is used
+ by Log::Log4perl as the configuration value.
+
+ The Perl code is executed in the "main" package, functions in other
+ packages have to be called in fully-qualified notation.
+
+ Here's another example, utilizing an environment variable as a username
+ for a DBI appender:
+
+ log4perl.appender.DB.username = \
+ sub { $ENV{DB_USER_NAME } }
+
+ However, please note the difference between these code snippets and
+ those used for user-defined conversion specifiers as discussed in
+ Log::Log4perl::Layout::PatternLayout: While the snippets above are run
+ *once* when "Log::Log4perl::init()" is called, the conversion specifier
+ snippets are executed *each time* a message is rendered according to the
+ PatternLayout.
+
+ 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::Config->allow_code(0);
+
+ before you call init(). Alternatively you can supply a restricted set of
+ Perl opcodes that can be embedded in the config file as described in
+ "Restricting what Opcodes can be in a Perl Hook".
+
+ Restricting what Opcodes can be in a Perl Hook
+ The value you pass to Log::Log4perl::Config->allow_code() determines
+ whether the code that is embedded in the config file is eval'd
+ unrestricted, or eval'd in a Safe compartment. By default, a value of
+ '1' is assumed, which does a normal 'eval' without any restrictions. A
+ value of '0' however prevents any embedded code from being evaluated.
+
+ If you would like fine-grained control over what can and cannot be
+ included in embedded code, then please utilize the following methods:
+
+ Log::Log4perl::Config->allow_code( $allow );
+ Log::Log4perl::Config->allowed_code_ops($op1, $op2, ... );
+ Log::Log4perl::Config->vars_shared_with_safe_compartment( [ \%vars | $package, \@vars ] );
+ Log::Log4perl::Config->allowed_code_ops_convenience_map( [ \%map | $name, \@mask ] );
+
+ Log::Log4perl::Config->allowed_code_ops() takes a list of opcode masks
+ that are allowed to run in the compartment. The opcode masks must be
+ specified as described in Opcode:
+
+ Log::Log4perl::Config->allowed_code_ops(':subprocess');
+
+ This example would allow Perl operations like backticks, system, fork,
+ and waitpid to be executed in the compartment. Of course, you probably
+ don't want to use this mask -- it would allow exactly what the Safe
+ compartment is designed to prevent.
+
+ Log::Log4perl::Config->vars_shared_with_safe_compartment() takes the
+ symbols which should be exported into the Safe compartment before the
+ code is evaluated. The keys of this hash are the package names that the
+ symbols are in, and the values are array references to the literal
+ symbol names. For convenience, the default settings export the '%ENV'
+ hash from the 'main' package into the compartment:
+
+ Log::Log4perl::Config->vars_shared_with_safe_compartment(
+ main => [ '%ENV' ],
+ );
+
+ Log::Log4perl::Config->allowed_code_ops_convenience_map() is an accessor
+ method to a map of convenience names to opcode masks. At present, the
+ following convenience names are defined:
+
+ safe = [ ':browse' ]
+ restrictive = [ ':default' ]
+
+ For convenience, if Log::Log4perl::Config->allow_code() is called with a
+ value which is a key of the map previously defined with
+ Log::Log4perl::Config->allowed_code_ops_convenience_map(), then the
+ allowed opcodes are set according to the value defined in the map. If
+ this is confusing, consider the following:
+
+ use Log::Log4perl;
+
+ my $config = <<'END';
+ log4perl.logger = INFO, Main
+ log4perl.appender.Main = Log::Log4perl::Appender::File
+ log4perl.appender.Main.filename = \
+ sub { "example" . getpwuid($<) . ".log" }
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::SimpleLayout
+ END
+
+ $Log::Log4perl::Config->allow_code('restrictive');
+ Log::Log4perl->init( \$config ); # will fail
+ $Log::Log4perl::Config->allow_code('safe');
+ Log::Log4perl->init( \$config ); # will succeed
+
+ The reason that the first call to ->init() fails is because the
+ 'restrictive' name maps to an opcode mask of ':default'. getpwuid() is
+ not part of ':default', so ->init() fails. The 'safe' name maps to an
+ opcode mask of ':browse', which allows getpwuid() to run, so ->init()
+ succeeds.
+
+ allowed_code_ops_convenience_map() can be invoked in several ways:
+
+ allowed_code_ops_convenience_map()
+ Returns the entire convenience name map as a hash reference in
+ scalar context or a hash in list context.
+
+ allowed_code_ops_convenience_map( \%map )
+ Replaces the entire convenience name map with the supplied hash
+ reference.
+
+ allowed_code_ops_convenience_map( $name )
+ Returns the opcode mask for the given convenience name, or undef if
+ no such name is defined in the map.
+
+ allowed_code_ops_convenience_map( $name, \@mask )
+ Adds the given name/mask pair to the convenience name map. If the
+ name already exists in the map, it's value is replaced with the new
+ mask.
+
+ as can vars_shared_with_safe_compartment():
+
+ vars_shared_with_safe_compartment()
+ Return the entire map of packages to variables as a hash reference
+ in scalar context or a hash in list context.
+
+ vars_shared_with_safe_compartment( \%packages )
+ Replaces the entire map of packages to variables with the supplied
+ hash reference.
+
+ vars_shared_with_safe_compartment( $package )
+ Returns the arrayref of variables to be shared for a specific
+ package.
+
+ vars_shared_with_safe_compartment( $package, \@vars )
+ Adds the given package / varlist pair to the map. If the package
+ already exists in the map, it's value is replaced with the new
+ arrayref of variable names.
+
+ For more information on opcodes and Safe Compartments, see Opcode and
+ Safe.
+
+ Changing the Log Level on a Logger
+ Log4perl provides some internal functions for quickly adjusting the log
+ level from within a running Perl program.
+
+ Now, some people might argue that you should adjust your levels from
+ within an external Log4perl configuration file, but Log4perl is
+ everybody's darling.
+
+ Typically run-time adjusting of levels is done at the beginning, or in
+ response to some external input (like a "more logging" runtime command
+ for diagnostics).
+
+ You get the log level from a logger object with:
+
+ $current_level = $logger->level();
+
+ and you may set it with the same method, provided you first imported the
+ log level constants, with:
+
+ use Log::Log4perl::Level;
+
+ Then you can set the level on a logger to one of the constants,
+
+ $logger->level($ERROR); # one of DEBUG, INFO, WARN, ERROR, FATAL
+
+ To increase the level of logging currently being done, use:
+
+ $logger->more_logging($delta);
+
+ and to decrease it, use:
+
+ $logger->less_logging($delta);
+
+ $delta must be a positive integer (for now, we may fix this later ;).
+
+ There are also two equivalent functions:
+
+ $logger->inc_level($delta);
+ $logger->dec_level($delta);
+
+ They're included to allow you a choice in readability. Some folks will
+ prefer more/less_logging, as they're fairly clear in what they do, and
+ allow the programmer not to worry too much about what a Level is and
+ whether a higher Level means more or less logging. However, other folks
+ who do understand and have lots of code that deals with levels will
+ probably prefer the inc_level() and dec_level() methods as they want to
+ work with Levels and not worry about whether that means more or less
+ logging. :)
+
+ That diatribe aside, typically you'll use more_logging() or inc_level()
+ as such:
+
+ my $v = 0; # default level of verbosity.
+
+ GetOptions("v+" => \$v, ...);
+
+ if( $v ) {
+ $logger->more_logging($v); # inc logging level once for each -v in ARGV
+ }
+
+ Custom Log Levels
+ First off, let me tell you that creating custom levels is heavily
+ deprecated by the log4j folks. Indeed, instead of creating additional
+ levels on top of the predefined DEBUG, INFO, WARN, ERROR and FATAL, you
+ should use categories to control the amount of logging smartly, based on
+ the location of the log-active code in the system.
+
+ Nevertheless, Log4perl provides a nice way to create custom levels via
+ the create_custom_level() routine function. However, this must be done
+ before the first call to init() or get_logger(). Say you want to create
+ a NOTIFY logging level that comes after WARN (and thus before INFO).
+ You'd do such as follows:
+
+ use Log::Log4perl;
+ use Log::Log4perl::Level;
+
+ Log::Log4perl::Logger::create_custom_level("NOTIFY", "WARN");
+
+ And that's it! create_custom_level() creates the following functions /
+ variables for level FOO:
+
+ $FOO_INT # integer to use in L4p::Level::to_level()
+ $logger->foo() # log function to log if level = FOO
+ $logger->is_foo() # true if current level is >= FOO
+
+ These levels can also be used in your config file, but note that your
+ config file probably won't be portable to another log4perl or log4j
+ environment unless you've made the appropriate mods there too.
+
+ Since Log4perl translates log levels to syslog and Log::Dispatch if
+ their appenders are used, you may add mappings for custom levels as
+ well:
+
+ Log::Log4perl::Level::add_priority("NOTIFY", "WARN",
+ $syslog_equiv, $log_dispatch_level);
+
+ For example, if your new custom "NOTIFY" level is supposed to map to
+ syslog level 2 ("LOG_NOTICE") and Log::Dispatch level 2 ("notice"), use:
+
+ Log::Log4perl::Logger::create_custom_level("NOTIFY", "WARN", 2, 2);
+
+ System-wide log levels
+ As a fairly drastic measure to decrease (or increase) the logging level
+ all over the system with one single configuration option, use the
+ "threshold" keyword in the Log4perl configuration file:
+
+ log4perl.threshold = ERROR
+
+ sets the system-wide (or hierarchy-wide according to the log4j
+ documentation) to ERROR and therefore deprives every logger in the
+ system of the right to log lower-prio messages.
+
+ Easy Mode
+ For teaching purposes (especially for [1]), I've put ":easy" mode into
+ "Log::Log4perl", which just initializes a single root logger with a
+ defined priority and a screen appender including some nice standard
+ layout:
+
+ ### Initialization Section
+ use Log::Log4perl qw(:easy);
+ Log::Log4perl->easy_init($ERROR); # Set priority of root logger to ERROR
+
+ ### Application Section
+ my $logger = get_logger();
+ $logger->fatal("This will get logged.");
+ $logger->debug("This won't.");
+
+ This will dump something like
+
+ 2002/08/04 11:43:09 ERROR> script.pl:16 main::function - This will get logged.
+
+ to the screen. While this has been proven to work well familiarizing
+ people with "Log::Logperl" slowly, effectively avoiding to clobber them
+ over the head with a plethora of different knobs to fiddle with
+ (categories, appenders, levels, layout), the overall mission of
+ "Log::Log4perl" is to let people use categories right from the start to
+ get used to the concept. So, let's keep this one fairly hidden in the
+ man page (congrats on reading this far :).
+
+ Stealth loggers
+ Sometimes, people are lazy. If you're whipping up a 50-line script and
+ want the comfort of Log::Log4perl without having the burden of carrying
+ a separate log4perl.conf file or a 5-liner defining that you want to
+ append your log statements to a file, you can use the following
+ features:
+
+ use Log::Log4perl qw(:easy);
+
+ Log::Log4perl->easy_init( { level => $DEBUG,
+ file => ">>test.log" } );
+
+ # Logs to test.log via stealth logger
+ DEBUG("Debug this!");
+ INFO("Info this!");
+ WARN("Warn this!");
+ ERROR("Error this!");
+
+ some_function();
+
+ sub some_function {
+ # Same here
+ FATAL("Fatal this!");
+ }
+
+ In ":easy" mode, "Log::Log4perl" will instantiate a *stealth logger* and
+ introduce the convenience functions "TRACE", "DEBUG()", "INFO()",
+ "WARN()", "ERROR()", "FATAL()", and "ALWAYS" into the package namespace.
+ These functions simply take messages as arguments and forward them to
+ the stealth loggers methods ("debug()", "info()", and so on).
+
+ If a message should never be blocked, regardless of the log level, use
+ the "ALWAYS" function which corresponds to a log level of "OFF":
+
+ ALWAYS "This will be printed regardless of the log level";
+
+ The "easy_init" method can be called with a single level value to create
+ a STDERR appender and a root logger as in
+
+ Log::Log4perl->easy_init($DEBUG);
+
+ or, as shown below (and in the example above) with a reference to a
+ hash, specifying values for "level" (the logger's priority), "file" (the
+ appender's data sink), "category" (the logger's category and "layout"
+ for the appender's pattern layout specification. All key-value pairs are
+ optional, they default to $DEBUG for "level", "STDERR" for "file", ""
+ (root category) for "category" and "%d %m%n" for "layout":
+
+ Log::Log4perl->easy_init( { level => $DEBUG,
+ file => ">test.log",
+ utf8 => 1,
+ category => "Bar::Twix",
+ layout => '%F{1}-%L-%M: %m%n' } );
+
+ The "file" parameter takes file names preceded by ">" (overwrite) and
+ ">>" (append) as arguments. This will cause
+ "Log::Log4perl::Appender::File" appenders to be created behind the
+ scenes. Also the keywords "STDOUT" and "STDERR" (no ">" or ">>") are
+ recognized, which will utilize and configure
+ "Log::Log4perl::Appender::Screen" appropriately. The "utf8" flag, if set
+ to a true value, runs a "binmode" command on the file handle to
+ establish a utf8 line discipline on the file, otherwise you'll get a
+ 'wide character in print' warning message and probably not what you'd
+ expect as output.
+
+ The stealth loggers can be used in different packages, you just need to
+ make sure you're calling the "use" function in every package you're
+ using "Log::Log4perl"'s easy services:
+
+ package Bar::Twix;
+ use Log::Log4perl qw(:easy);
+ sub eat { DEBUG("Twix mjam"); }
+
+ package Bar::Mars;
+ use Log::Log4perl qw(:easy);
+ sub eat { INFO("Mars mjam"); }
+
+ package main;
+
+ use Log::Log4perl qw(:easy);
+
+ Log::Log4perl->easy_init( { level => $DEBUG,
+ file => ">>test.log",
+ category => "Bar::Twix",
+ layout => '%F{1}-%L-%M: %m%n' },
+ { level => $DEBUG,
+ file => "STDOUT",
+ category => "Bar::Mars",
+ layout => '%m%n' },
+ );
+ Bar::Twix::eat();
+ Bar::Mars::eat();
+
+ As shown above, "easy_init()" will take any number of different logger
+ definitions as hash references.
+
+ Also, stealth loggers feature the functions "LOGWARN()", "LOGDIE()", and
+ "LOGEXIT()", combining a logging request with a subsequent Perl warn()
+ or die() or exit() statement. So, for example
+
+ if($all_is_lost) {
+ LOGDIE("Terrible Problem");
+ }
+
+ will log the message if the package's logger is at least "FATAL" but
+ "die()" (including the traditional output to STDERR) in any case
+ afterwards.
+
+ See "Log and die or warn" for the similar "logdie()" and "logwarn()"
+ functions of regular (i.e non-stealth) loggers.
+
+ Similarily, "LOGCARP()", "LOGCLUCK()", "LOGCROAK()", and "LOGCONFESS()"
+ are provided in ":easy" mode, facilitating the use of "logcarp()",
+ "logcluck()", "logcroak()", and "logconfess()" with stealth loggers.
+
+ When using Log::Log4perl in easy mode, please make sure you understand
+ the implications of "Pitfalls with Categories".
+
+ By the way, these convenience functions perform exactly as fast as the
+ standard Log::Log4perl logger methods, there's *no* performance penalty
+ whatsoever.
+
+ Nested Diagnostic Context (NDC)
+ If you find that your application could use a global (thread-specific)
+ data stack which your loggers throughout the system have easy access to,
+ use Nested Diagnostic Contexts (NDCs). Also check out "Mapped Diagnostic
+ Context (MDC)", this might turn out to be even more useful.
+
+ For example, when handling a request of a web client, it's probably
+ useful to have the user's IP address available in all log statements
+ within code dealing with this particular request. Instead of passing
+ this piece of data around between your application functions, you can
+ just use the global (but thread-specific) NDC mechanism. It allows you
+ to push data pieces (scalars usually) onto its stack via
+
+ Log::Log4perl::NDC->push("San");
+ Log::Log4perl::NDC->push("Francisco");
+
+ and have your loggers retrieve them again via the "%x" placeholder in
+ the PatternLayout. With the stack values above and a PatternLayout
+ format like "%x %m%n", the call
+
+ $logger->debug("rocks");
+
+ will end up as
+
+ San Francisco rocks
+
+ in the log appender.
+
+ The stack mechanism allows for nested structures. Just make sure that at
+ the end of the request, you either decrease the stack one by one by
+ calling
+
+ Log::Log4perl::NDC->pop();
+ Log::Log4perl::NDC->pop();
+
+ or clear out the entire NDC stack by calling
+
+ Log::Log4perl::NDC->remove();
+
+ Even if you should forget to do that, "Log::Log4perl" won't grow the
+ stack indefinitely, but limit it to a maximum, defined in
+ "Log::Log4perl::NDC" (currently 5). A call to "push()" on a full stack
+ will just replace the topmost element by the new value.
+
+ Again, the stack is always available via the "%x" placeholder in the
+ Log::Log4perl::Layout::PatternLayout class whenever a logger fires. It
+ will replace "%x" by the blank-separated list of the values on the
+ stack. It does that by just calling
+
+ Log::Log4perl::NDC->get();
+
+ internally. See details on how this standard log4j feature is
+ implemented in Log::Log4perl::NDC.
+
+ Mapped Diagnostic Context (MDC)
+ Just like the previously discussed NDC stores thread-specific
+ information in a stack structure, the MDC implements a hash table to
+ store key/value pairs in.
+
+ The static method
+
+ Log::Log4perl::MDC->put($key, $value);
+
+ stores $value under a key $key, with which it can be retrieved later
+ (possibly in a totally different part of the system) by calling the
+ "get" method:
+
+ my $value = Log::Log4perl::MDC->get($key);
+
+ If no value has been stored previously under $key, the "get" method will
+ return "undef".
+
+ Typically, MDC values are retrieved later on via the "%X{...}"
+ placeholder in "Log::Log4perl::Layout::PatternLayout". If the "get()"
+ method returns "undef", the placeholder will expand to the string
+ "[undef]".
+
+ An application taking a web request might store the remote host like
+
+ Log::Log4perl::MDC->put("remote_host", $r->headers("HOST"));
+
+ at its beginning and if the appender's layout looks something like
+
+ log4perl.appender.Logfile.layout.ConversionPattern = %X{remote_host}: %m%n
+
+ then a log statement like
+
+ DEBUG("Content delivered");
+
+ will log something like
+
+ adsl-63.dsl.snf.pacbell.net: Content delivered
+
+ later on in the program.
+
+ For details, please check Log::Log4perl::MDC.
+
+ Resurrecting hidden Log4perl Statements
+ Sometimes scripts need to be deployed in environments without having
+ Log::Log4perl installed yet. On the other hand, you don't want to live
+ without your Log4perl statements -- they're gonna come in handy later.
+
+ So, just deploy your script with Log4perl statements commented out with
+ the pattern "###l4p", like in
+
+ ###l4p DEBUG "It works!";
+ # ...
+ ###l4p INFO "Really!";
+
+ If Log::Log4perl is available, use the ":resurrect" tag to have Log4perl
+ resurrect those buried statements before the script starts running:
+
+ use Log::Log4perl qw(:resurrect :easy);
+
+ ###l4p Log::Log4perl->easy_init($DEBUG);
+ ###l4p DEBUG "It works!";
+ # ...
+ ###l4p INFO "Really!";
+
+ This will have a source filter kick in and indeed print
+
+ 2004/11/18 22:08:46 It works!
+ 2004/11/18 22:08:46 Really!
+
+ In environments lacking Log::Log4perl, just comment out the first line
+ and the script will run nevertheless (but of course without logging):
+
+ # use Log::Log4perl qw(:resurrect :easy);
+
+ ###l4p Log::Log4perl->easy_init($DEBUG);
+ ###l4p DEBUG "It works!";
+ # ...
+ ###l4p INFO "Really!";
+
+ because everything's a regular comment now. Alternatively, put the magic
+ Log::Log4perl comment resurrection line into your shell's PERL5OPT
+ environment variable, e.g. for bash:
+
+ set PERL5OPT=-MLog::Log4perl=:resurrect,:easy
+ export PERL5OPT
+
+ This will awaken the giant within an otherwise silent script like the
+ following:
+
+ #!/usr/bin/perl
+
+ ###l4p Log::Log4perl->easy_init($DEBUG);
+ ###l4p DEBUG "It works!";
+
+ As of "Log::Log4perl" 1.12, you can even force *all* modules loaded by a
+ script to have their hidden Log4perl statements resurrected. For this to
+ happen, load "Log::Log4perl::Resurrector" *before* loading any modules:
+
+ use Log::Log4perl qw(:easy);
+ use Log::Log4perl::Resurrector;
+
+ use Foobar; # All hidden Log4perl statements in here will
+ # be uncommented before Foobar gets loaded.
+
+ Log::Log4perl->easy_init($DEBUG);
+ ...
+
+ Check the "Log::Log4perl::Resurrector" manpage for more details.
+
+ Access defined appenders
+ All appenders defined in the configuration file or via Perl code can be
+ retrieved by the "appender_by_name()" class method. This comes in handy
+ if you want to manipulate or query appender properties after the
+ Log4perl configuration has been loaded via "init()".
+
+ Note that internally, Log::Log4perl uses the "Log::Log4perl::Appender"
+ wrapper class to control the real appenders (like
+ "Log::Log4perl::Appender::File" or "Log::Dispatch::FileRotate"). The
+ "Log::Log4perl::Appender" class has an "appender" attribute, pointing to
+ the real appender.
+
+ The reason for this is that external appenders like
+ "Log::Dispatch::FileRotate" don't support all of Log::Log4perl's
+ appender control mechanisms (like appender thresholds).
+
+ The previously mentioned method "appender_by_name()" returns a reference
+ to the *real* appender object. If you want access to the wrapper class
+ (e.g. if you want to modify the appender's threshold), use the hash
+ $Log::Log4perl::Logger::APPENDER_BY_NAME{...} instead, which holds
+ references to all appender wrapper objects.
+
+ Modify appender thresholds
+ To set an appender's threshold, use its "threshold()" method:
+
+ $app->threshold( $FATAL );
+
+ To conveniently adjust *all* appender thresholds (e.g. because a script
+ uses more_logging()), use
+
+ # decrease thresholds of all appenders
+ Log::Log4perl->appender_thresholds_adjust(-1);
+
+ This will decrease the thresholds of all appenders in the system by one
+ level, i.e. WARN becomes INFO, INFO becomes DEBUG, etc. To only modify
+ selected ones, use
+
+ # decrease thresholds of all appenders
+ Log::Log4perl->appender_thresholds_adjust(-1, ['AppName1', ...]);
+
+ and pass the names of affected appenders in a ref to an array.
+
+Advanced configuration within Perl
+ Initializing Log::Log4perl can certainly also be done from within Perl.
+ At last, this is what "Log::Log4perl::Config" does behind the scenes.
+ Log::Log4perl's configuration file parsers are using a publically
+ available API to set up Log::Log4perl's categories, appenders and
+ layouts.
+
+ Here's an example on how to configure two appenders with the same layout
+ in Perl, without using a configuration file at all:
+
+ ########################
+ # Initialization section
+ ########################
+ use Log::Log4perl;
+ use Log::Log4perl::Layout;
+ use Log::Log4perl::Level;
+
+ # Define a category logger
+ my $log = Log::Log4perl->get_logger("Foo::Bar");
+
+ # Define a layout
+ my $layout = Log::Log4perl::Layout::PatternLayout->new("[%r] %F %L %m%n");
+
+ # Define a file appender
+ my $file_appender = Log::Log4perl::Appender->new(
+ "Log::Log4perl::Appender::File",
+ name => "filelog",
+ filename => "/tmp/my.log");
+
+ # Define a stdout appender
+ my $stdout_appender = Log::Log4perl::Appender->new(
+ "Log::Log4perl::Appender::Screen",
+ name => "screenlog",
+ stderr => 0);
+
+ # Have both appenders use the same layout (could be different)
+ $stdout_appender->layout($layout);
+ $file_appender->layout($layout);
+
+ $log->add_appender($stdout_appender);
+ $log->add_appender($file_appender);
+ $log->level($INFO);
+
+ Please note the class of the appender object is passed as a *string* to
+ "Log::Log4perl::Appender" in the *first* argument. Behind the scenes,
+ "Log::Log4perl::Appender" will create the necessary
+ "Log::Log4perl::Appender::*" (or "Log::Dispatch::*") object and pass
+ along the name value pairs we provided to
+ "Log::Log4perl::Appender->new()" after the first argument.
+
+ The "name" value is optional and if you don't provide one,
+ "Log::Log4perl::Appender->new()" will create a unique one for you. The
+ names and values of additional parameters are dependent on the
+ requirements of the particular appender class and can be looked up in
+ their manual pages.
+
+ A side note: In case you're wondering if
+ "Log::Log4perl::Appender->new()" will also take care of the "min_level"
+ argument to the "Log::Dispatch::*" constructors called behind the scenes
+ -- yes, it does. This is because we want the "Log::Dispatch" objects to
+ blindly log everything we send them ("debug" is their lowest setting)
+ because *we* in "Log::Log4perl" want to call the shots and decide on
+ when and what to log.
+
+ The call to the appender's *layout()* method specifies the format (as a
+ previously created "Log::Log4perl::Layout::PatternLayout" object) in
+ which the message is being logged in the specified appender. If you
+ don't specify a layout, the logger will fall back to
+ "Log::Log4perl::SimpleLayout", which logs the debug level, a hyphen (-)
+ and the log message.
+
+ Layouts are objects, here's how you create them:
+
+ # Create a simple layout
+ my $simple = Log::Log4perl::SimpleLayout();
+
+ # create a flexible layout:
+ # ("yyyy/MM/dd hh:mm:ss (file:lineno)> message\n")
+ my $pattern = Log::Log4perl::Layout::PatternLayout("%d (%F:%L)> %m%n");
+
+ Every appender has exactly one layout assigned to it. You assign the
+ layout to the appender using the appender's "layout()" object:
+
+ my $app = Log::Log4perl::Appender->new(
+ "Log::Log4perl::Appender::Screen",
+ name => "screenlog",
+ stderr => 0);
+
+ # Assign the previously defined flexible layout
+ $app->layout($pattern);
+
+ # Add the appender to a previously defined logger
+ $logger->add_appender($app);
+
+ # ... and you're good to go!
+ $logger->debug("Blah");
+ # => "2002/07/10 23:55:35 (test.pl:207)> Blah\n"
+
+ It's also possible to remove appenders from a logger:
+
+ $logger->remove_appender($appender_name);
+
+ will remove an appender, specified by name, from a given logger. Please
+ note that this does *not* remove an appender from the system.
+
+ To eradicate an appender from the system, you need to call
+ "Log::Log4perl->eradicate_appender($appender_name)" which will first
+ remove the appender from every logger in the system and then will delete
+ all references Log4perl holds to it.
+
+ To remove a logger from the system, use
+ "Log::Log4perl->remove_logger($logger)". After the remaining reference
+ $logger goes away, the logger will self-destruct. If the logger in
+ question is a stealth logger, all of its convenience shortcuts (DEBUG,
+ INFO, etc) will turn into no-ops.
+
+How about Log::Dispatch::Config?
+ Tatsuhiko Miyagawa's "Log::Dispatch::Config" is a very clever simplified
+ logger implementation, covering some of the *log4j* functionality. Among
+ the things that "Log::Log4perl" can but "Log::Dispatch::Config" can't
+ are:
+
+ * You can't assign categories to loggers. For small systems that's
+ fine, but if you can't turn off and on detailed logging in only a
+ tiny subsystem of your environment, you're missing out on a majorly
+ useful log4j feature.
+
+ * Defining appender thresholds. Important if you want to solve
+ problems like "log all messages of level FATAL to STDERR, plus log
+ all DEBUG messages in "Foo::Bar" to a log file". If you don't have
+ appenders thresholds, there's no way to prevent cluttering STDERR
+ with DEBUG messages.
+
+ * PatternLayout specifications in accordance with the standard (e.g.
+ "%d{HH:mm}").
+
+ Bottom line: Log::Dispatch::Config is fine for small systems with simple
+ logging requirements. However, if you're designing a system with lots of
+ subsystems which you need to control independently, you'll love the
+ features of "Log::Log4perl", which is equally easy to use.
+
+Using Log::Log4perl with wrapper functions and classes
+ If you don't use "Log::Log4perl" as described above, but from a wrapper
+ function, the pattern layout will generate wrong data for %F, %C, %L,
+ and the like. Reason for this is that "Log::Log4perl"'s loggers assume a
+ static caller depth to the application that's using them.
+
+ If you're using one (or more) wrapper functions, "Log::Log4perl" will
+ indicate where your logger function called the loggers, not where your
+ application called your wrapper:
+
+ use Log::Log4perl qw(:easy);
+ Log::Log4perl->easy_init({ level => $DEBUG,
+ layout => "%M %m%n" });
+
+ sub mylog {
+ my($message) = @_;
+
+ DEBUG $message;
+ }
+
+ sub func {
+ mylog "Hello";
+ }
+
+ func();
+
+ prints
+
+ main::mylog Hello
+
+ but that's probably not what your application expects. Rather, you'd
+ want
+
+ main::func Hello
+
+ because the "func" function called your logging function.
+
+ But don't despair, there's a solution: Just register your wrapper
+ package with Log4perl beforehand. If Log4perl then finds that it's being
+ called from a registered wrapper, it will automatically step up to the
+ next call frame.
+
+ Log::Log4perl->wrapper_register(__PACKAGE__);
+
+ sub mylog {
+ my($message) = @_;
+
+ DEBUG $message;
+ }
+
+ Alternatively, you can increase the value of the global variable
+ $Log::Log4perl::caller_depth (defaults to 0) by one for every wrapper
+ that's in between your application and "Log::Log4perl", then
+ "Log::Log4perl" will compensate for the difference:
+
+ sub mylog {
+ my($message) = @_;
+
+ local $Log::Log4perl::caller_depth =
+ $Log::Log4perl::caller_depth + 1;
+ DEBUG $message;
+ }
+
+ Also, note that if you're writing a subclass of Log4perl, like
+
+ package MyL4pWrapper;
+ use Log::Log4perl;
+ our @ISA = qw(Log::Log4perl);
+
+ and you want to call get_logger() in your code, like
+
+ use MyL4pWrapper;
+
+ sub get_logger {
+ my $logger = Log::Log4perl->get_logger();
+ }
+
+ then the get_logger() call will get a logger for the "MyL4pWrapper"
+ category, not for the package calling the wrapper class as in
+
+ package UserPackage;
+ my $logger = MyL4pWrapper->get_logger();
+
+ To have the above call to get_logger return a logger for the
+ "UserPackage" category, you need to tell Log4perl that "MyL4pWrapper" is
+ a Log4perl wrapper class:
+
+ use MyL4pWrapper;
+ Log::Log4perl->wrapper_register(__PACKAGE__);
+
+ sub get_logger {
+ # Now gets a logger for the category of the calling package
+ my $logger = Log::Log4perl->get_logger();
+ }
+
+ This feature works both for Log4perl-relaying classes like the wrapper
+ described above, and for wrappers that inherit from Log4perl use
+ Log4perl's get_logger function via inheritance, alike.
+
+Access to Internals
+ The following methods are only of use if you want to peek/poke in the
+ internals of Log::Log4perl. Be careful not to disrupt its inner
+ workings.
+
+ "Log::Log4perl->appenders()"
+ To find out which appenders are currently defined (not only for a
+ particular logger, but overall), a "appenders()" method is available
+ to return a reference to a hash mapping appender names to their
+ Log::Log4perl::Appender object references.
+
+Dirty Tricks
+ infiltrate_lwp()
+ The famous LWP::UserAgent module isn't Log::Log4perl-enabled. Often,
+ though, especially when tracing Web-related problems, it would be
+ helpful to get some insight on what's happening inside
+ LWP::UserAgent. Ideally, LWP::UserAgent would even play along in the
+ Log::Log4perl framework.
+
+ A call to "Log::Log4perl->infiltrate_lwp()" does exactly this. In a
+ very rude way, it pulls the rug from under LWP::UserAgent and
+ transforms its "debug/conn" messages into "debug()" calls of loggers
+ of the category "LWP::UserAgent". Similarily, "LWP::UserAgent"'s
+ "trace" messages are turned into "Log::Log4perl"'s "info()" method
+ calls. Note that this only works for LWP::UserAgent versions <
+ 5.822, because this (and probably later) versions miss debugging
+ functions entirely.
+
+ Suppressing 'duplicate' LOGDIE messages
+ If a script with a simple Log4perl configuration uses logdie() to
+ catch errors and stop processing, as in
+
+ use Log::Log4perl qw(:easy) ;
+ Log::Log4perl->easy_init($DEBUG);
+
+ shaky_function() or LOGDIE "It failed!";
+
+ there's a cosmetic problem: The message gets printed twice:
+
+ 2005/07/10 18:37:14 It failed!
+ It failed! at ./t line 12
+
+ The obvious solution is to use LOGEXIT() instead of LOGDIE(), but
+ there's also a special tag for Log4perl that suppresses the second
+ message:
+
+ use Log::Log4perl qw(:no_extra_logdie_message);
+
+ This causes logdie() and logcroak() to call exit() instead of die().
+ To modify the script exit code in these occasions, set the variable
+ $Log::Log4perl::LOGEXIT_CODE to the desired value, the default is 1.
+
+ Redefine values without causing errors
+ Log4perl's configuration file parser has a few basic safety
+ mechanisms to make sure configurations are more or less sane.
+
+ One of these safety measures is catching redefined values. For
+ example, if you first write
+
+ log4perl.category = WARN, Logfile
+
+ and then a couple of lines later
+
+ log4perl.category = TRACE, Logfile
+
+ then you might have unintentionally overwritten the first value and
+ Log4perl will die on this with an error (suspicious configurations
+ always throw an error). Now, there's a chance that this is
+ intentional, for example when you're lumping together several
+ configuration files and actually *want* the first value to overwrite
+ the second. In this case use
+
+ use Log::Log4perl qw(:nostrict);
+
+ to put Log4perl in a more permissive mode.
+
+ Prevent croak/confess from stringifying
+ The logcroak/logconfess functions stringify their arguments before
+ they pass them to Carp's croak/confess functions. This can get in
+ the way if you want to throw an object or a hashref as an exception,
+ in this case use:
+
+ $Log::Log4perl::STRINGIFY_DIE_MESSAGE = 0;
+
+ eval {
+ # throws { foo => "bar" }
+ # without stringification
+ $logger->logcroak( { foo => "bar" } );
+ };
+
+EXAMPLE
+ A simple example to cut-and-paste and get started:
+
+ use Log::Log4perl qw(get_logger);
+
+ my $conf = q(
+ log4perl.category.Bar.Twix = WARN, Logfile
+ log4perl.appender.Logfile = Log::Log4perl::Appender::File
+ log4perl.appender.Logfile.filename = test.log
+ log4perl.appender.Logfile.layout = \
+ Log::Log4perl::Layout::PatternLayout
+ log4perl.appender.Logfile.layout.ConversionPattern = %d %F{1} %L> %m %n
+ );
+
+ Log::Log4perl::init(\$conf);
+
+ my $logger = get_logger("Bar::Twix");
+ $logger->error("Blah");
+
+ This will log something like
+
+ 2002/09/19 23:48:15 t1 25> Blah
+
+ to the log file "test.log", which Log4perl will append to or create it
+ if it doesn't exist already.
+
+INSTALLATION
+ If you want to use external appenders provided with "Log::Dispatch", you
+ need to install "Log::Dispatch" (2.00 or better) from CPAN, which itself
+ depends on "Attribute-Handlers" and "Params-Validate". And a lot of
+ other modules, that's the reason why we're now shipping Log::Log4perl
+ with its own standard appenders and only if you wish to use additional
+ ones, you'll have to go through the "Log::Dispatch" installation
+ process.
+
+ Log::Log4perl needs "Test::More", "Test::Harness" and "File::Spec", but
+ they already come with fairly recent versions of perl. If not,
+ everything's automatically fetched from CPAN if you're using the CPAN
+ shell (CPAN.pm), because they're listed as dependencies.
+
+ "Time::HiRes" (1.20 or better) is required only if you need the
+ fine-grained time stamps of the %r parameter in
+ "Log::Log4perl::Layout::PatternLayout".
+
+ Manual installation works as usual with
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEVELOPMENT
+ Log::Log4perl is still being actively developed. We will always make
+ sure the test suite (approx. 500 cases) will pass, but there might still
+ be bugs. please check <http://github.com/mschilli/log4perl> for the
+ latest release. The api has reached a mature state, we will not change
+ it unless for a good reason.
+
+ Bug reports and feedback are always welcome, just email them to our
+ mailing list shown in the AUTHORS section. We're usually addressing them
+ immediately.
+
+REFERENCES
+ [1] Michael Schilli, "Retire your debugger, log smartly with
+ Log::Log4perl!", Tutorial on perl.com, 09/2002,
+ <http://www.perl.com/pub/a/2002/09/11/log4perl.html>
+
+ [2] Ceki Gülcü, "Short introduction to log4j",
+ <http://logging.apache.org/log4j/1.2/manual.html>
+
+ [3] Vipan Singla, "Don't Use System.out.println! Use Log4j.",
+ <http://www.vipan.com/htdocs/log4jhelp.html>
+
+ [4] The Log::Log4perl project home page: <http://log4perl.com>
+
+SEE ALSO
+ Log::Log4perl::Config, Log::Log4perl::Appender,
+ Log::Log4perl::Layout::PatternLayout,
+ Log::Log4perl::Layout::SimpleLayout, Log::Log4perl::Level,
+ Log::Log4perl::JavaMap Log::Log4perl::NDC,
+
+AUTHORS
+ 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.
+
+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.
+