blob: 76f1629b17c264033860e088d02230ba20e8c8db [file] [log] [blame]
////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
= Usage
[#Static_vs_Non_Static]
== 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,
link:../log4j-core/apidocs/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html[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 two methods that perform logging, once that uses the static logger and one that uses a Logger that
can be overridden.
[source]
----
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.
[source]
----
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.
[source]
----
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.
[source,xml]
----
<?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.
[source]
----
------- 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.