UsageStatic vs Non-Static LoggersAs 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 delare a logger as static vs non-static. Generally, it is better to declare Loggers as static.
Logging the Logger name vs the Class nameThe 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.
------- 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. |