Usage

Static vs Non-Static Loggers

As with any variable in Java, Loggers may be declared as static variables or class member variables. However, there are a few factors to consider when choosing to declare a logger as static vs non-static. Generally, it is better to declare Loggers as static.

  1. Instantiation of a new Logger is a fairly expensive operation when using the default ContextSelector, ClassLoaderContextSelector. When the Logger is created the ClassLoaderContextSelector will locate the ClassLoader for the Class the Logger is associated with and add the Logger to the LoggerContext associated with that ClassLoader.
  2. Once a Logger is created it will not be deleted until the LoggerContext it is associated with is deleted. Typically, this will only happen when the application is shut down or un-deployed. Each call to getLogger with the same logger name will return the same Logger instance. Thus, there is very little difference between a static or non-static Logger.
  3. There is no behavioral difference between a static and non-static Logger. Both will have the Logger name assigned when they are created, which usually will be the name of the class they are associated with. See the discussion below on logger names vs class names and the example for more information.

Logging the Logger name vs the Class name

The logger name of a Logger is specified when the Logger is created. When a log method is called the class name value in the log event will reflect the name of the class the log method was called from, which is not necessarily the same as the class that created the Logger. The following example illustrations this.

The base class creates a static Logger and a logger variable that is initialized as that same Logger. It has a method that performs logging, but provides access to two Loggers, one that is static and one that can be overridden.

  package org.apache.logging;

  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.Marker;

  /**
  *
  */
  public abstract class Parent {

      // The name of this Logger will be "org.apache.logging.Parent"
      protected static final Logger parentLogger = LogManager.getLogger();

      private Logger logger = parentLogger;

      protected Logger getLogger() {
          return logger;
      }

      protected void setLogger(Logger logger) {
          this.logger = logger;
      }


      public void log(Marker marker) {
          logger.debug(marker,"Parent log message");
      }
  }

This class extends the base class. It provides its own logger and has three methods, one that uses the logger in this class,one that uses the static logger from the base class, and one that where the logger may be set to either the parent or the child.

  package org.apache.logging;

  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.Marker;

  /**
  *
  */
  public class Child extends Parent {

      // The name of this Logge will be "org.apache.logging.Child"
      public Logger childLogger = LogManager.getLogger();

      public void childLog(Marker marker) {
          childLogger.debug(marker,"Child logger message");
      }

      public void logFromChild(Marker marker) {
          getLogger().debug(marker,"Log message from Child");
      }

      public void parentLog(Marker marker) {
          parentLogger.debug(marker,"Parent logger, message from Child");
      }
  }

The application exercises all the logging methods four times. The first two times the Logger in the base class is set to the static Logger. The second two times the Logger in the base class is set to use the Logger in the subclass. In the first and third invocation of each method a null Marker is passed. In the second and fourth a Marker named "CLASS" is passed.

  package org.apache.logging;

  import org.apache.logging.log4j.Marker;
  import org.apache.logging.log4j.MarkerManager;

  public class App {

      public static void main( String[] args ) {
          Marker marker = MarkerManager.getMarker("CLASS");
          Child child = new Child();

          System.out.println("------- Parent Logger ----------");
          child.log(null);
          child.log(marker);
          child.logFromChild(null);
          child.logFromChild(marker);
          child.parentLog(null);
          child.parentLog(marker);

          child.setLogger(child.childLogger);

          System.out.println("------- Parent Logger set to Child Logger ----------");
          child.log(null);
          child.log(marker);
          child.logFromChild(null);
          child.logFromChild(marker);
      }
  }

The configuration takes advantage of Log4j's ability to select a pattern based upon attributes of the log event. In this case %C, the class name pattern, is used when the CLASS Marker is present, and %c, the logger name is used when the CLASS marker is not present.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout>
        <MarkerPatternSelector defaultPattern="%sn. %msg: Logger=%logger%n">
          <PatternMatch key="CLASS" pattern="%sn. %msg: Class=%class%n"/>
        </MarkerPatternSelector>
      </PatternLayout>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="TRACE">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

The output below illustrates the difference between using the Logger name and the Class name in the pattern. All the odd numbered items print the name of the logger (%c) while all the even numbered items print the name of the class that called the logging method (%C). The numbers in the description of the outcomes in the following list match the corresponding numbers shown in the output.

  1. Logging is performed in the parent class using the static logger with the Logger name pattern. The logger name matches the name of the parent class.
  2. Logging is performed in the parent class using the static logger with the Class name pattern. Although the method was called against the Child instance it is implemented in Parent so that is what appears.
  3. Logging is performed in Child using the logger in the parent, so the name of the parent is printed as the logger name.
  4. Logging is performed in Child using the logger in the parent. Since the method calling the logging method is in Child that is the class name that appears.
  5. Logging is performed in Child using the static logger in the parent, so the name of the parent is printed as the logger name.
  6. Logging is performed in Child using the static logger in the parent. Since the method calling the logging method is in Child that is the class name that appears.
  7. Logging is performed in the parent class using the logger of Child. The logger name matches the name of the child and so it is printed.
  8. Logging is performed in the parent class using the logger of the Child. Although the method was called against the Child instance it is implemented in Parent so that is what appears as the class name.
  9. Logging is performed in Child using the logger in the parent which is set to the child logger, so the name of the child is printed as the logger name.
  10. Logging is performed in Child using the logger in the parent, which is set to the child logger. Since the method calling the logging method is in Child that is the class name that appears.
  ------- Parent Logger ----------
  1. Parent log message: Logger=org.apache.logging.Parent
  2. Parent log message: Class=org.apache.logging.Parent
  3. Log message from Child: Logger=org.apache.logging.Parent
  4. Log message from Child: Class=org.apache.logging.Child
  5. Parent logger, message from Child: Logger=org.apache.logging.Parent
  6. Parent logger, message from Child: Class=org.apache.logging.Child
  ------- Parent Logger set to Child Logger ----------
  7. Parent log message: Logger=org.apache.logging.Child
  8. Parent log message: Class=org.apache.logging.Parent
  9. Log message from Child: Logger=org.apache.logging.Child
  10. Log message from Child: Class=org.apache.logging.Child

In the example above there are two Loggers declared. One is static and one is non-static. When looking at the results it is clear that the outcomes would be exactly the same regardless of whether how the loggers are declared. The name of the logger will always originate from the class in which it is created and the Class name in each log event will always reflect the Class from which the logging method was called.

It should be noted that there is a substantial performance penalty for printing the location information (class name, method name, and line number). If the method name and line number are not important it is usually better to make sure that each class has its own Logger so the logger name accurately reflects the class performing the logging.