1. Introduction
Log4j 2 is a popular, open-source logging framework written in Java. It was introduced to overcome various architectural flaws of Log4j. It’s thread-safe, fast, and provides various improvements over its predecessor. It’s distributed under the open-source Apache Software License.
Log4j 2 is the latest and improved version of the classic Log4j framework that reached the end of its life on August 5, 2015. However, Log4j is still widely used in many Java enterprise applications as a logging framework.
In this tutorial, we’ll learn about Log4j 2, its benefits over Log4j, and how to configure its core components using the log4j2.properties file in Java.
2. Maven Setup
We’ll need the log4j-core dependency in our pom.xml to start with:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
We can find the latest version of log4j-core and log4j-api in the Maven Repository.
3. Log4j 2 Logger
Unlike in Log4j, where we use Logger.getLogger() to get a Logger instance with a specific name, in Log4j 2 we use LogManager.getLogger():
private static final Logger logger = LogManager.getLogger(Log4j2Example.class);
The LogManager reads the initial configuration parameters from a configuration file or a configuration class. A Logger is associated with LoggerConfig, which is associated with Appenders that actually deliver the log events.
If we call LogManager.getLogger() by passing the same (class) name, we’ll always get the reference of the same logger instance.
Both Logger and LoggerConfig are named entities. Each Logger references a LoggerConfig, which can reference its parent, thus achieving the same effect.
A Logger follows a named hierarchy. This means a LoggerConfig named “com.baeldung” is a parent of the LoggerConfig named “com.baeldung.foo“.
4. Log4j 2 Configuration
Unlike Log4j, which supports configuration only through properties and XML formats, we can define the Log4j 2 configurations using JSON, XML, YAML, or properties format. All these formats are functionally equivalent. Therefore, we can easily convert the configuration done in one format to any other.
Moreover, Logj2 supports automatic configuration, which means it’s capable of configuring itself automatically during initialization.
It scans and locates all the ConfigurationFactory plugins at the start and arranges them in weighted order from highest to lowest – the properties file has the highest precedence of the value of 8, followed by YAML, JSON, and XML.
This means if we have logging configurations in the form of both the properties file and the XML file, then the precedence will be given to the properties file.
5. The log4j2.properties File
When Log4j 2 was released, it didn’t have the support for configuration through the properties file. It started supporting the properties file from the release of version 2.4.
The default properties configuration file is always log4j2.properties. The Logger gets the reference of this file from the CLASSPATH.
However, if we need to use a different configuration file name, we can set it using the system property log4j.configurationFile.
The system property may refer to a local file system or may contain a URL. Log4j 2 provides a DefaultConfiguration if it cannot locate a configuration file. In this case, we get the logging output redirected to the console and the root logger level set to ERROR.
6. Syntax of the log4j2.properties File
The syntax of the log4j2.properties file isn’t the same as that of log4j.properties. In the log4j.properties file, every configuration starts with ‘log4j‘, while this has been omitted in the log4j2.properties configuration.
Let’s see the syntax of a general log4j2.properties file:
# The root logger with appender name
rootLogger = DEBUG, STDOUT
# Assign STDOUT a valid appender & define its layout
appender.console.name = STDOUT
appender.console.type = Console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %msg%n
Here, STDOUT is the name of the Appender. As discussed earlier, we can attach multiple appenders to a logger to direct logs to different destinations.
Also, we should define a root logger in every Log4j 2 configuration. Otherwise, a default root LoggerConfig that has an ERROR level and ConsoleAppender is used.
7. Examples
Now, let’s understand the log4j2.properties file configurations for different appenders with the help of some examples.
7.1. Sample Program
Let’s start with an example application that logs some messages:
public class Log4j2ConsoleAndFile {
private static final Logger logger = LogManager.getLogger(Log4j2ConsoleAndFile.class);
public static void main(String[] args) {
logger.info("Hello World!");
logger.debug("Hello World!");
}
}
7.2. Console Logging
The console is the default place for logging messages if no configuration file is located. Let’s create a log4j2.properties configuration for the console Appender with the root logger and also define the logging level for it:
# Root Logger
rootLogger=DEBUG, STDOUT
# Direct log messages to stdout
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
Here, we’ve defined a log4j2.properties file with the following specifications:
- We’ve defined the level of the root logger as DEBUG. This means that we’ll get all the log events with level DEBUG and above. We’ve also defined a name for the appender as STDOUT.
- Since we want to direct the logs to the console, we assigned the Appender type as Console. We should note that the word console in the key name is only a convention and not mandatory.
- Then, we specify the pattern in which we want to print the log messages.
Let’s also understand the meaning of each of the conversion characters in the layout pattern that we’ve used:
- %-5level adds the log-level information to each log statement. It signifies that the priority of the logging event is left-justified to a width of five characters.
- %d adds the timestamp in the defined format.
- %t adds the thread name to the log statement
- %c{1} prints the qualified class name, optionally followed by package names (precision qualifier), that logs the specific log statement.
- %msg prints the actual log message.
- %n adds a new line after every log statement.
Thus, when we run our sample application, we get the following lines printed on the console:
[INFO ] 2023-08-05 23:04:03.255 [main] Log4j2ConsoleAndFile - Hello World!
[DEBUG] 2023-08-05 23:04:03.255 [main] Log4j2ConsoleAndFile - Hello World!
The class PatternLayout explains more about conversion characters that we can use based on our needs.
7.3. Multiple Destinations
As discussed earlier, we can redirect the log events to multiple destinations:
# Root Logger
rootLogger=INFO, STDOUT, LOGFILE
# Direct log messages to STDOUT
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
# Direct to a file
appender.file.type = File
appender.file.name = LOGFILE
appender.file.fileName = baeldung/logs/log4j2.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
appender.file.filter.threshold.type = ThresholdFilter
appender.file.filter.threshold.level = info
Here, we’ve used two appenders to redirect the log messages to both the file and console. We’ve named them STDOUT and LOGFILE. Additionally, we’ve added both appenders to the root logger.
To redirect the log messages to a file, we need to specify the file name with its location.
We’ve also used ThresholdFilter, which filters out the log messages with a certain log level and above. Finally, we’ve specified the threshold.level as INFO. Thus, all the log messages with level INFO or above will be printed to the file.
When we run our sample application, we get only the following line printed on the console as well as the log4j2.log file:
[INFO ] 2023-08-05 23:04:03.255 [main] Log4j2ConsoleAndFile - Hello World!
8. Conclusion
In this article, we explored Log4j 2 and its benefits over Log4j. We’ve also understood the syntax of a log4j2.properties file and some simple examples of configuring a log4j2.properties file.
As always, the examples that accompany the article are available over on GitHub.