«    »

Tips for Using Log4j

Log4j is a logging framework for Java, part of Apache's suite of logging frameworks for various languages. While using log4j on various applications, I have had to figure out how to do certain things that were not clearly documented, possibly because the full manual for log4j is only available commercially. Before showing what I have learned, I will start with a simple example of logging with log4j:

package com.basilv.examples.logging;
import org.apache.log4j.Logger;
public class LogExample
{
  private static Logger logger = Logger
    .getLogger(LogExample.class);

  void doWork() {
    logger.debug("Debugging message");
    try {
      logger.info("Info message");
    } catch (RuntimeException e) {
      logger.error(
        "Error message with exception included.", e);
    }
  }
}

Logging is quite useful, but one problem with sending log output to a file is that if a problem occurs with the application that no user reports, the maintenance team would have to manually check the log file to find out. A better solution is to have log output for serious problems also emailed to the maintenance team. The following example provides a subset of a log4j configuration properties file to do just that.

# Send output to a logfile appender (not shown)
# and an email appender shown below.
log4j.rootLogger=WARN,logfile,email

# Email appender
log4j.appender.email=org.apache.log4j.net.SMTPAppender
log4j.appender.email.BufferSize=25
log4j.appender.email.SMTPHost=mail-sending-host@domain.com
log4j.appender.email.From=maintenance-team@domain.com
log4j.appender.email.To=maintenance-team@domain.com
log4j.appender.email.Subject=Application Error - Production
log4j.appender.email.layout=org.apache.log4j.PatternLayout
log4j.appender.email.layout.ConversionPattern=
    %d{DATE} %-5p %m - %c{3} [%t] [%r ms]%n%n
# Send emails for level ERROR or above only.
log4j.appender.email.threshold=ERROR

Email can be sent to a team email address, multiple team members, or both. I prefer to have email sent in all environments, not just production. To avoid confusion when receiving the email over which environment the problem occurred in, I specify the environment in the subject of the email. To do this, however, requires a slightly different log4j file for each environment.

There is a way to eliminate this difference and maintain a single log4j properties file for all environments. The solution is to use substitution variables in the form ${variable-name}. The java system property with the same name will have its value substituted for this text. For the above example, the parametrized email subject would become

log4j.appender.email.Subject=Application Error - ${app.environment}

The system property app.environment can be initialized at application startup on the command-line or within the application server.

One great thing about log4j is that you can maintain detailed logging statements (at the DEBUG level) within your application code, but leave this level of logging turned off in production to avoid overly large log files or a performance impact. The disadvantage of doing this is that when a problem does occur, it may be quite useful to have these detailed logging information available. One partial solution to this problem is to provide a mechanism to re-initialize log4j at runtime from its configuration file. You can then modify your log4j configuration file to enable DEBUG-level logging, trigger this mechanism, and then immediately start receiving detailed logging information.

To figure out how to implement this mechanism I had to study the log4j initialization code. I could not find a clean API for doing what I wanted, so my resulting code uses more of the internals of log4j than I like, and assumes that log4j is entirely configured via the standard property file (log4j.properties).

URL url = Loader.getResource(
    LogManager.DEFAULT_CONFIGURATION_FILE);
new PropertyConfigurator().doConfigure(url, 
    LogManager.getLoggerRepository());

It is easy to change this code to use a log4j XML configuration file instead.

I hope you have found at least one of these tips useful. If you have any of your own, please share them via a comment.

The source code listed in this article is provided in the Java Examples project which can be downloaded from the Software page.

If you find this article helpful, please make a donation.

7 Comments on “Tips for Using Log4j”

  1. Rob Williams says:

    Please note that Log4j can be configured via a file (Java properties or XML) and then watch that file for changes, with automatic reloading/reconfiguring. Check the javadocs for the *Watch methods in the API.

  2. Great tip, Rob. I wonder if this watch mechanism is suitable for use within Java EE containers?

  3. Sharada Vittal says:

    Could you please add an example JAVA code to show how to use these properties?

  4. Thabet says:

    Hey,

    What if SMTP server require authentication. Where to define the user name and password?

  5. @Thabet, good question. I don’t know the answer, sorry.

  6. Total Log4Cplus Fan says:

    The ${variable-name} construct only works in the properties file, obviously. But how do I set that variable in Java, so it gets filled with something useable?

  7. Java system properties can be set programmatically via System.setProperty() or more commonly can be set via the java command-line option “-Dproperty=value”.

«    »