0

I migrated my Spring Boot application from Logback to Log4j2, but the application is still printing logs using Logback.

What I did so far:

  1. Added Log4j2 dependencies:

    org.springframework.boot spring-boot-starter-log4j2
  2. Created a log4j2.xml config file in src/main/resources.

  3. Removed my old logback-spring.xml.

But when I start the app, I still see logs with the Logback format, not Log4j2.

Example log output:

2025-09-30 12:45:23.123 INFO 12345 --- [ main] com.example.demo.MyApp : Application started

14:10:57,475 |-WARN in ch.qos.logback.core.model.processor.ImplicitModelHandler - Ignoring unknown property [Properties] in [ch.qos.logback.classic.LoggerContext] 14:10:57,475 |-WARN in ch.qos.logback.core.model.processor.ImplicitModelHandler - Ignoring unknown property [Appenders] in [ch.qos.logback.classic.LoggerContext] 14:10:57,475 |-WARN in ch.qos.logback.core.model.processor.ImplicitModelHandler - Ignoring unknown property [Loggers] in [ch.qos.logback.classic.LoggerContext] 14:10:57,475 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@296bfddb - End of configuration.

Expected:

Logs should follow my log4j2.xml pattern.

Logback should not load at all.

Questions:

Why is Logback still taking precedence even after adding Log4j2?

Do I need to explicitly exclude spring-boot-starter-logging in my build.gradle?

What is the correct way to ensure only Log4j2 is used in Spring Boot?

2
  • ANd you did exclude the logback dependencies? If not that will take precedence. Commented Sep 30 at 8:58
  • Check dependency tree for that package with ./gradlew dependencyInsight --dependency logback and add exclude as needed. Commented Sep 30 at 13:17

2 Answers 2

1

I think you need to exclude it in your build.gradle as Spring Boot uses Logback as default.

Afterwards, you can add log4j2 to your dependencies.

configurations.all {
    exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
    exclude group: "ch.qos.logback"
}
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-log4j2")
}
Sign up to request clarification or add additional context in comments.

3 Comments

The best thing to do would be to print a dependency tree and figure out where logback is being injected. This can be then excluded from that module.
It’s not working.
Can you share the dependency tree?
0

Since the questioner did not provide a complete build.gradle configuration, I used the simplest web starter as the basic configuration.

Project Tree

demo-logging
├── build.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── DemoLoggingApplication.java
        │           └── HelloController.java
        └── resources
            ├── application.properties
            └── log4j2.xml

log4j2.xml

LOG_PATTERN ***** %msg%n, Here use 5 consecutive asterisk characters * as a special mark.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">

    <Properties>
        <Property name="LOG_PATH">logs</Property>
        <Property name="LOG_FILE">app.log</Property>
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} -  ***** %msg%n</Property>
    </Properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}" />
        </Console>

        <RollingFile name="File" fileName="${LOG_PATH}/${LOG_FILE}"
                     filePattern="${LOG_PATH}/app-%d{yyyy-MM-dd}.log.gz">
            <PatternLayout pattern="${LOG_PATTERN}" />
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" />
            </Policies>
            <DefaultRolloverStrategy max="7"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Logger name="org.springframework" level="INFO" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Logger>

        <Logger name="com.example" level="DEBUG" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Logger>

        <Root level="INFO">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Root>
    </Loggers>

</Configuration>

application.properties

default

spring.application.name=demo-logging

DemoLoggingApplication.java

default

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoLoggingApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoLoggingApplication.class, args);
    }

}

HelloController.java

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class HelloController {
    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
        
    @GetMapping("/hello/{name}")
    public String sayHello(
            @PathVariable String name,
            @RequestParam(value = "greeting", defaultValue = "Hello") String greeting) {
            String msg = String.format("%s, %s!", greeting, name);
            logger.info(">>>> Received request with msg: {}", msg);
        return msg;
    }
}

build.gradle - default - logback

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.6'
    id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

bootJar {
    archiveFileName = 'app.jar'
}

Build , Run and Test

Build

gradle clean build

Run

java -jar build/libs/app.jar

Test

curl http://localhost:8080/hello/Marry

Find dependencies - default

gradle dependencies --console=plain --configuration runtimeClasspath

get result: spring-boot-starter-logging <- logback

\--- org.springframework.boot:spring-boot-starter-web -> 3.5.6
     +--- org.springframework.boot:spring-boot-starter:3.5.6
     |    +--- org.springframework.boot:spring-boot:3.5.6
....
     |    +--- org.springframework.boot:spring-boot-starter-logging:3.5.6
     |    |    +--- ch.qos.logback:logback-classic:1.5.18
     |    |    |    +--- ch.qos.logback:logback-core:1.5.18
     |    |    |    \--- org.slf4j:slf4j-api:2.0.17
     |    |    +--- org.apache.logging.log4j:log4j-to-slf4j:2.24.3
     |    |    |    +--- org.apache.logging.log4j:log4j-api:2.24.3
     |    |    |    \--- org.slf4j:slf4j-api:2.0.16 -> 2.0.17
     |    |    \--- org.slf4j:jul-to-slf4j:2.0.17
     |    |         \--- org.slf4j:slf4j-api:2.0.17

link result to build.gradle config: spring-boot-starter-web

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

Exclude logging, add log4j2

  • exclude spring-boot-starter-logging
  • add log4j2 starter spring-boot-starter-log4j2
dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web') {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }

    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
}

build.gradle - log4j2

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.6'
    id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web') {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }

    implementation 'org.springframework.boot:spring-boot-starter-log4j2'

}

bootJar {
    archiveFileName = 'app.jar'
}

Find dependencies - log4j2

gradle dependencies --console=plain --configuration runtimeClasspath

get result: There is no logging or logback in the content, now it shows log4j2.

+--- org.springframework.boot:spring-boot-starter-web -> 3.5.6
|    +--- org.springframework.boot:spring-boot-starter:3.5.6
|    |    +--- org.springframework.boot:spring-boot:3.5.6
...
\--- org.springframework.boot:spring-boot-starter-log4j2 -> 3.5.6
     +--- org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3
     |    +--- org.apache.logging.log4j:log4j-api:2.24.3
     |    +--- org.slf4j:slf4j-api:2.0.16 -> 2.0.17
     |    \--- org.apache.logging.log4j:log4j-core:2.24.3
     |         \--- org.apache.logging.log4j:log4j-api:2.24.3
     +--- org.apache.logging.log4j:log4j-core:2.24.3 (*)
     \--- org.apache.logging.log4j:log4j-jul:2.24.3
          \--- org.apache.logging.log4j:log4j-api:2.24.3

Build , Run and Test

Build

gradle clean build

Run

java -jar build/libs/app.jar

Test

curl http://localhost:8080/hello/Marry

Console Output

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.6)

2025-10-12 12:41:57.458 [main] INFO  com.example.DemoLoggingApplication -  ***** Starting DemoLoggingApplication v0.0.1-SNAPSHOT using Java 17.0.12 with PID 15168 (/home/demo/demo-logging/build/libs/app.jar started by demo in /home/demo/demo-logging)
2025-10-12 12:41:57.466 [main] DEBUG com.example.DemoLoggingApplication -  ***** Running with Spring Boot v3.5.6, Spring v6.2.11
2025-10-12 12:41:57.468 [main] INFO  com.example.DemoLoggingApplication -  ***** No active profile set, falling back to 1 default profile: "default"
2025-10-12 12:41:58.145 [main] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer -  ***** Tomcat initialized with port 8080 (http)
2025-10-12 12:41:58.158 [main] INFO  org.apache.coyote.http11.Http11NioProtocol -  ***** Initializing ProtocolHandler ["http-nio-8080"]
2025-10-12 12:41:58.160 [main] INFO  org.apache.catalina.core.StandardService -  ***** Starting service [Tomcat]
2025-10-12 12:41:58.160 [main] INFO  org.apache.catalina.core.StandardEngine -  ***** Starting Servlet engine: [Apache Tomcat/10.1.46]
2025-10-12 12:41:58.190 [main] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] -  ***** Initializing Spring embedded WebApplicationContext
2025-10-12 12:41:58.192 [main] INFO  org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext -  ***** Root WebApplicationContext: initialization completed in 678 ms
2025-10-12 12:41:58.464 [main] INFO  org.apache.coyote.http11.Http11NioProtocol -  ***** Starting ProtocolHandler ["http-nio-8080"]
2025-10-12 12:41:58.480 [main] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer -  ***** Tomcat started on port 8080 (http) with context path '/'
2025-10-12 12:41:58.487 [main] INFO  com.example.DemoLoggingApplication -  ***** Started DemoLoggingApplication in 1.346 seconds (process running for 2.248)
2025-10-12 12:42:03.832 [http-nio-8080-exec-1] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] -  ***** Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-10-12 12:42:03.834 [http-nio-8080-exec-1] INFO  org.springframework.web.servlet.DispatcherServlet -  ***** Initializing Servlet 'dispatcherServlet'
2025-10-12 12:42:03.841 [http-nio-8080-exec-1] INFO  org.springframework.web.servlet.DispatcherServlet -  ***** Completed initialization in 7 ms
2025-10-12 12:42:03.934 [http-nio-8080-exec-1] INFO  com.example.HelloController -  ***** >>>> Received request with msg: Hello, Marry!

NOTE: log4j2.xml, "***** %msg%n"

<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - ***** %msg%n</Property> </Properties>

you can find out: ***** Tomcat started on port 8080 (http) with context path '/'

This output format can be confirmed to be output through log4j2.

2025-10-12 12:41:58.480 [main] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer -  ***** Tomcat started on port 8080 (http) with context path '/' 

Note that this setup is based on only including spring-boot-starter-web, and then using gradle dependencies --console=plain --configuration runtimeClasspath to find out which module logback (logging) is being used by, and then we exclude it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.