Log::Log4perl::FAQ - phpMan

Command: man perldoc info search(apropos)  


Sections
NAME DESCRIPTION SEE ALSO LICENSE AUTHOR
NAME
    Log::Log4perl::FAQ - Frequently Asked Questions on Log::Log4perl

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

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

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

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

    Avoid this costly switch.

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

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

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

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

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

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

        use Log::Log4perl qw(:easy);

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

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

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

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

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

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

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

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

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

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

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

        use Log::Log4perl qw(get_logger);

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

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

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

    This will append something like

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

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

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

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

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

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

        log4perl.logger = ERROR, FileApp

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

        log4perl.logger.Bar.Twix = ERROR, FileApp

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

    Appender settings in the configuration are defined as follows:

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

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

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

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

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

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

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

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

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

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

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

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

    Alternatively you can install it using

        ppm install Log-Log4perl

    if you're using ActiveState perl.

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

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

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

    and run it. It should print something like

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

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

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

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

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

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

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

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

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

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

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

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

        log4perl.logger                    = DEBUG, FileApp

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

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

        log4perl.logger                    = DEBUG, FileApp, ScreenApp

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

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

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

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

    for details. Have fun!

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

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

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

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

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

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

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

        use Log::Log4perl qw(get_logger);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Here's a complete program:

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

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

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

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

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

    This will generate the following output on STDERR:

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

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

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

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

        package LWP::Debug;

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

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

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

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

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

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

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

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

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

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

        log4perl.appender.Logfile.filename = test.log

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    For example, putting the line

        log4perl.threshold = ERROR

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

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

    Therefore, if you keep the line

        log4perl.threshold = OFF

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

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

        log4perl.logger = DEBUG, Screen, File

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

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

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

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

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

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

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

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

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

    Now imagine the following code in your program:

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

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

        WARN - Warning!
        WARN - Warning!

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

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

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

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

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

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

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

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

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

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

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

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

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

        log4perl.oneMessagePerAppender = 1

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

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

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

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

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

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

        log4perl.appender.Mailer.buffered = 0

    to turn buffering off.

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

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

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

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

        package ColorScreenAppender;

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

        log4perl.logger = INFO, ColorApp

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

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

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

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

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

            return $self;
        }

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

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

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

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

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

        use Term::ANSIColor;

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

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

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

        1;

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

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

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

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

        use Class::Prototyped;

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

        use Log::Log4perl qw(:easy);

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

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

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

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

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

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

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

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

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

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

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

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

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

    If you define a root logger like this:

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

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

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

        log4perl.appender.File.Threshold = FATAL

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

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

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

    won't be logged as

        Blah
        Blah
        Blah

    but as

        [3] Blah

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

    Let's define a new appender like

        package TallyAppender;

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

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

            bless $self, $class;

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

            return $self;
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        log4perl.logger = WARN, AppWarn, AppError

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

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

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

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

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

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

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

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

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

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

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

        # *** WRONG! ***

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

        # *** WRONG! ***

    and you're getting the following error message:

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

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

        log4perl.appender.A1.layout =

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

        # *** RIGHT! ***

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

        # *** RIGHT! ***

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

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

        sub some_func {

            INFO("Begin of function");

            # ... Stuff happens here ...

            INFO("End of function");
        }

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

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

        use Log::Log4perl qw(:easy);

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

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

            log4perl.appender.A1.Filter = M1
    EOT

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

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

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

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

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

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

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

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

        1;

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

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

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

        1;

    and the main program is just using the module like in

        use MyMode;
        MyMode::foo();

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

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

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

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

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

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

        Log::Log4perl::initialized()

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

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

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

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

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

          # Guarantees atomic writes

        log4perl.category.Bar.Twix          = WARN, Logfile

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

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

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

        log4perl.category.Bar.Twix          = WARN, Syncer

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

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

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

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

Figure1: Chainsaw receives Log::Log4perl events
    Here's how it works:

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

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

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

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

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

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

        and watch the GUI coming up.

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

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

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

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

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

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

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

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

        without a preceding

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

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

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

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

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

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

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

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

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

    *   Use a different logfile for every process like in

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

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

        use Log::Log4perl qw(:easy);

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

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

    Once done, if your program does something like

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

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

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

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

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

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

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

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

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

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

        1;

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

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

        use Log::Log4perl qw(:easy);

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

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

        1;

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

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

        use Log::Log4perl qw(:easy);

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

        tie *STDERR, "Trapper";

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

    Now, calling

        IgnorantModule::some_method();

    will result in the desired output

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

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

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

        use Log::Log4perl qw(get_logger);

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

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

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

        pp -o mytest mytest.pl

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

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

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

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

    to make sure the appender class gets included.

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

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

        package IndentAppender;

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

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

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

        package main;

        use Log::Log4perl qw(:easy);

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

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

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

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

    As you would expect, this will print

        DEBUG - No indentation
         DEBUG - One more
          DEBUG - Two more
         DEBUG - One less

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

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

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

        use warnings;
        use strict;

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

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

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

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

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

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

        $request_permission &~ $umask

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

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

        use Log::Log4perl;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Alternatively, "binmode" does the trick:

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

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

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

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

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

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

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

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

    appears. Setting STDOUT to UTF-8 mode as in

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

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

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

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

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

    What you want to do instead, is this:

        log4perl.logger                    = DEBUG, FileApp, ScreenApp

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

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

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

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

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

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

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

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

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

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

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

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

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

        log4perl.appender.Logfile.recreate = 1

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

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

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

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

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

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

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

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

    For example, with a newsyslog configuration like

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

    and a call to

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

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

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

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

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

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

        log4perl.appender.Logfile.recreate_check_interval = 0

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

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

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

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

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

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

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

    Two potential solutions come to mind:

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

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

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

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

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

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

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

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

        use Log::Log4perl qw(:easy);

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

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

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

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

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

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

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

        log4perl.utcDateTimes = 1

    in your configuration. Alternatively, you can set

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

    in your program before the first log statement.

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

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

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

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

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

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

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

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

        1;

    Now, if you have a function like

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

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

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

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

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

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

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

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

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

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

    it gets rendered this way:

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

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

        use Log::Log4perl qw(:easy);

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

        DEBUG "some\nmultiline\nmessage";

    and you'll get

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

    instead.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    So, the program above could easily be fixed by putting

        $a->{selfref} = undef;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        use Log::Log4perl qw(:easy);

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

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

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

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

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

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

    What happens in Perl if you have something like

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

    and

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

    is that you get

        second end in main
        end in module
        first end in main

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

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

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

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

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

    which will call the END handlers in the intended order.

SEE ALSO
    Log::Log4perl

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

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

AUTHOR
    Please contribute patches to the project on Github:

        http://github.com/mschilli/log4perl

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

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

    Authors (please contact them via the list above, not directly): Mike
    Schilli <m AT perlmeister.com>, Kevin Goess <cpan AT 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.


Generated by phpMan Author: Che Dong On Apache Under GNU General Public License - MarkDown Format
2026-05-23 06:08 @216.73.217.24 CrawledBy Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Valid XHTML 1.0 TransitionalValid CSS!

^_back to top