Spring Boot
log4j2
application setup
Java
logging framework

How to set up Spring Boot and log4j2 properly?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Spring Boot uses Logback as its default logging framework. To switch to Log4j2, you must exclude the spring-boot-starter-logging dependency and add spring-boot-starter-log4j2. Log4j2 offers better performance (async logging with LMAX Disruptor), more flexible configuration (XML, YAML, JSON, properties), and advanced features like garbage-free logging. Configuration goes in log4j2.xml (or log4j2-spring.xml for Spring-aware features) in src/main/resources.

Step 1: Update Dependencies (Maven)

xml
1<!-- pom.xml -->
2<dependencies>
3    <dependency>
4        <groupId>org.springframework.boot</groupId>
5        <artifactId>spring-boot-starter-web</artifactId>
6        <exclusions>
7            <!-- Exclude default Logback -->
8            <exclusion>
9                <groupId>org.springframework.boot</groupId>
10                <artifactId>spring-boot-starter-logging</artifactId>
11            </exclusion>
12        </exclusions>
13    </dependency>
14
15    <!-- Add Log4j2 -->
16    <dependency>
17        <groupId>org.springframework.boot</groupId>
18        <artifactId>spring-boot-starter-log4j2</artifactId>
19    </dependency>
20
21    <!-- Optional: YAML configuration support -->
22    <dependency>
23        <groupId>com.fasterxml.jackson.dataformat</groupId>
24        <artifactId>jackson-dataformat-yaml</artifactId>
25    </dependency>
26</dependencies>

Step 1 (Gradle)

groovy
1// build.gradle
2configurations.all {
3    exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
4}
5
6dependencies {
7    implementation 'org.springframework.boot:spring-boot-starter-web'
8    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
9}

Step 2: Create log4j2-spring.xml

xml
1<!-- src/main/resources/log4j2-spring.xml -->
2<?xml version="1.0" encoding="UTF-8"?>
3<Configuration status="WARN">
4    <Properties>
5        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
6        <Property name="LOG_DIR">logs</Property>
7    </Properties>
8
9    <Appenders>
10        <!-- Console output -->
11        <Console name="Console" target="SYSTEM_OUT">
12            <PatternLayout pattern="${LOG_PATTERN}" />
13        </Console>
14
15        <!-- Rolling file -->
16        <RollingFile name="File" fileName="${LOG_DIR}/app.log"
17                     filePattern="${LOG_DIR}/app-%d{yyyy-MM-dd}-%i.log.gz">
18            <PatternLayout pattern="${LOG_PATTERN}" />
19            <Policies>
20                <SizeBasedTriggeringPolicy size="10MB" />
21                <TimeBasedTriggeringPolicy interval="1" />
22            </Policies>
23            <DefaultRolloverStrategy max="30" />
24        </RollingFile>
25    </Appenders>
26
27    <Loggers>
28        <!-- Application logger -->
29        <Logger name="com.myapp" level="DEBUG" additivity="false">
30            <AppenderRef ref="Console" />
31            <AppenderRef ref="File" />
32        </Logger>
33
34        <!-- Spring framework -->
35        <Logger name="org.springframework" level="INFO" additivity="false">
36            <AppenderRef ref="Console" />
37        </Logger>
38
39        <!-- Root logger -->
40        <Root level="WARN">
41            <AppenderRef ref="Console" />
42            <AppenderRef ref="File" />
43        </Root>
44    </Loggers>
45</Configuration>

Use log4j2-spring.xml (not log4j2.xml) to enable Spring Boot's profile-aware logging with <SpringProfile> tags.

Step 3: Use SLF4J in Code

java
1import org.slf4j.Logger;
2import org.slf4j.LoggerFactory;
3import org.springframework.web.bind.annotation.*;
4
5@RestController
6@RequestMapping("/api")
7public class UserController {
8    private static final Logger log = LoggerFactory.getLogger(UserController.class);
9
10    @GetMapping("/users/{id}")
11    public User getUser(@PathVariable Long id) {
12        log.info("Fetching user with id: {}", id);
13
14        try {
15            User user = userService.findById(id);
16            log.debug("Found user: {}", user.getName());
17            return user;
18        } catch (Exception e) {
19            log.error("Failed to fetch user {}: {}", id, e.getMessage(), e);
20            throw e;
21        }
22    }
23}

Always use SLF4J (org.slf4j.Logger) as the logging facade, not Log4j2's API directly. This keeps your code framework-agnostic.

Async Logging (High Performance)

xml
1<!-- Add LMAX Disruptor dependency -->
2<!-- pom.xml -->
3<dependency>
4    <groupId>com.lmax</groupId>
5    <artifactId>disruptor</artifactId>
6    <version>3.4.4</version>
7</dependency>
xml
1<!-- log4j2-spring.xml with async loggers -->
2<Configuration status="WARN">
3    <Appenders>
4        <Console name="Console" target="SYSTEM_OUT">
5            <PatternLayout pattern="%d [%t] %-5level %logger{36} - %msg%n" />
6        </Console>
7    </Appenders>
8
9    <Loggers>
10        <!-- AsyncLogger for high-throughput logging -->
11        <AsyncLogger name="com.myapp" level="DEBUG" additivity="false">
12            <AppenderRef ref="Console" />
13        </AsyncLogger>
14
15        <Root level="WARN">
16            <AppenderRef ref="Console" />
17        </Root>
18    </Loggers>
19</Configuration>

Async logging with LMAX Disruptor writes log events to a ring buffer instead of directly to appenders, dramatically reducing logging latency in high-throughput applications.

Profile-Specific Configuration

xml
1<!-- log4j2-spring.xml — Spring profiles -->
2<Configuration>
3    <Appenders>
4        <Console name="Console" target="SYSTEM_OUT">
5            <PatternLayout pattern="%d %-5level %logger{36} - %msg%n" />
6        </Console>
7    </Appenders>
8
9    <Loggers>
10        <!-- Different levels per Spring profile -->
11        <SpringProfile name="dev">
12            <Logger name="com.myapp" level="DEBUG" additivity="false">
13                <AppenderRef ref="Console" />
14            </Logger>
15        </SpringProfile>
16
17        <SpringProfile name="prod">
18            <Logger name="com.myapp" level="INFO" additivity="false">
19                <AppenderRef ref="Console" />
20            </Logger>
21        </SpringProfile>
22
23        <Root level="WARN">
24            <AppenderRef ref="Console" />
25        </Root>
26    </Loggers>
27</Configuration>

<SpringProfile> tags only work in log4j2-spring.xml, not log4j2.xml.

Common Pitfalls

  • Not excluding spring-boot-starter-logging: If Logback remains on the classpath alongside Log4j2, SLF4J cannot determine which binding to use, causing startup warnings or errors. Exclude spring-boot-starter-logging from all starter dependencies.
  • Using log4j2.xml instead of log4j2-spring.xml: Spring Boot's <SpringProfile> and <SpringProperty> tags only work in files named log4j2-spring.xml. Plain log4j2.xml is loaded before Spring initializes.
  • additivity="true" causing duplicate log entries: If a logger has additivity="true" (default), log events propagate to the root logger and get printed twice. Set additivity="false" on non-root loggers.
  • Missing jackson-dataformat-yaml for YAML config: If using log4j2.yaml or log4j2.yml format, the Jackson YAML module must be on the classpath. Without it, Log4j2 silently falls back to default configuration.
  • Log4j2 security vulnerabilities: The Log4Shell vulnerability (CVE-2021-44228) affected Log4j2 versions before 2.17.0. Always use the latest patched version and disable JNDI lookups if not needed.

Summary

  • Exclude spring-boot-starter-logging and add spring-boot-starter-log4j2 in dependencies
  • Place configuration in src/main/resources/log4j2-spring.xml for Spring profile support
  • Use SLF4J (LoggerFactory.getLogger()) in application code, not Log4j2 API directly
  • Add LMAX Disruptor + AsyncLogger for high-performance async logging
  • Set additivity="false" on non-root loggers to prevent duplicate log entries
  • Always use the latest Log4j2 version to avoid known security vulnerabilities

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.