Log4j2 is the latest release of the popular Logging Framework. In this tutorial we will learn how to integrate Log4j2 configuration file in an example Spring Boot web application.
Log4j2 and Spring Boot in action
Log4j2 is a new build of Apache Log4j which derives from the Logback framework featuring improved performance, support for multiple logger API (Log4j, SLF4J, Commons Logging and JUL), advanced filtering, low garbage collector impact and custom log levels.
In order to test Log4j2 in a Spring Boot application, let’s create a template Web application using the Spring Boot Initializr or the spring command line:
spring init -dweb demo-log4j2
From there, we need to refine a bit the configuration. First of all, we will be adding the starter for log4j2 in your pom.xml:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!-- Other dependencies --> </dependencies>
As you can see, from the above configuration we have to exclude the default spring-boot-starter-logging from the top spring-boot-starter.
Adding Log4j2 Configuration to Spring Boot
Next, let’s add a log4j2.xml configuration. The good news is that Spring Boot will automatically configure log4j2 once it finds it’s jar files in classpath. So, it is sufficient to add log4j2.xml or (log4j2.properties) in src/main/resources folder of your Maven project:
Next, here is a sample log4j2.xml configuration:
<Configuration status="DEBUG"> <Appenders> <Console name="LogToConsole" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <File name="LogToFile" fileName="logs/application.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> </File> </Appenders> <Loggers> <Logger name="com.example.demo" level="debug" additivity="false"> <AppenderRef ref="LogToFile"/> <AppenderRef ref="LogToConsole"/> </Logger> <Logger name="org.springframework.boot" level="error" additivity="false"> <AppenderRef ref="LogToConsole"/> </Logger> <Root level="error"> <AppenderRef ref="LogToFile"/> <AppenderRef ref="LogToConsole"/> </Root> </Loggers> </Configuration>
In order to use log4j2, you can use the following minimalist example which shows how to log from a REST Controller:
package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @RestController public class HelloController { private static final Logger logger = LogManager.getLogger(HelloController.class); @GetMapping("/hello") public String hello() { String time = new java.util.Date().toString(); logger.info("It's time : {}", () -> time); logger.debug("It's time : {}", () -> time); return "hello "; } }
Since this Class belongs to the com.example.demo package, it will be captured both by the Console Appender and the File Appender. You can run the example as usual with:
$ mvn install spring-boot:run
Configuring a specific Log4j2 version
In the example we have covered so far, we use the spring-boot-starter-log4j2 to build our application. To have a strict control on the Log4j2 version we are deploying in our applications, the best practice is to use Log4j2 BOM, which is also the best choice if you are using multiple components under the Log4j2 umbrella.
To do that, add to your pom.xml the specific version of log4j-bom you want to use in your application:
<dependencyManagement> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-bom</artifactId> <version>2.23.1</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement>
Then, add the API needed in your application:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> </dependency>
Using a RollingFile Appender
The RollingFileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter and rolls the file over according the TriggeringPolicy and the RolloverPolicy.
Let’s see an example configuration:
<Configuration status="WARN" monitorInterval="30"> <Properties> <Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n</Property> </Properties> <Appenders> <Console name="Console" target="SYSTEM_OUT" follow="true"> <PatternLayout pattern="${LOG_PATTERN}" /> </Console> <RollingFile name="LogToFile" fileName="logs/application.log" filePattern="logs/application-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${LOG_PATTERN}" /> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="100 MB"/> </Policies> <DefaultRolloverStrategy max="1" /> </RollingFile> </Appenders> <Loggers> <Logger name="com.example.demolog4j2" additivity="false"> <AppenderRef ref="LogToFile" /> <AppenderRef ref="Console" /> </Logger> <Root level="debug"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
The above log4j2.xml file will create up to 7 archives on the same day (1-7) to be stored in logs directory based on the current year and month, and will compress each archive using gzip.
Configuring Loggers to be asynchronous
To make all loggers asynchronous, Log4j-2.9 and higher require disruptor-3.3.4.jar or higher on the classpath. Prior to Log4j-2.9, disruptor-3.0.0.jar or higher was required.
Therefore, we will add to our pom.xml file:
<dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>4.0.0</version> </dependency>
To activate asynchronous logging, we also must set the system property log4j2.contextSelector to org.apache.logging.log4j.core.async.AsyncLoggerContextSelector:
mvn clean install -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector spring-boot:run
From the Spring Boot logs, you can verify that the AsyncContext has been activated, so now logs are running asynchronously:
2020-08-16 19:42:06,978 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c 2020-08-16 19:42:06,979 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=AsyncLoggerRingBuffer 2020-08-16 19:42:06,979 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=StatusLogger 2020-08-16 19:42:06,980 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=ContextSelector 2020-08-16 19:42:06,982 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=Loggers,name=org.springframework.boot 2020-08-16 19:42:06,983 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=Loggers,name= 2020-08-16 19:42:06,984 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=Loggers,name=com.example.demolog4j2 2020-08-16 19:42:06,984 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=Appenders,name=LogToConsole 2020-08-16 19:42:06,985 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@4b85612c,component=Appenders,name=LogToFile
Source code for this tutorial: https://github.com/fmarchioni/masterspringboot/tree/master/log/demo-log4j2
ùAn excellent resources about Log4j2 configuration on WildFly is also available on the site mastertheboss.com
Found the article helpful? if so please follow us on Socials