Spring boot 3 logging dependency conflict
Asked Answered
W

2

8

We're in the process of upgrading to spring boot 3 in our application at the moment and we're getting some issues at runtime with logger factories clashing.

We use logback for our logging implementation, but via slf4j.

We're pulling in the spring-boot-starter-logging module, and not specifying our own versions of slf4j or logback in our build.gradle.

It's a really complicated project with lots of dependencies, but the logging dependencies are all here:

integrationTestRuntimeClasspath - Runtime classpath of source set 'integration test'.
+--- net.logstash.logback:logstash-logback-encoder:6.6
|    \--- com.fasterxml.jackson.core:jackson-databind:2.12.0 -> 2.14.2
|         +--- com.fasterxml.jackson.core:jackson-annotations:2.14.2
|         |    \--- com.fasterxml.jackson:jackson-bom:2.14.2
|         |         +--- com.fasterxml.jackson.core:jackson-annotations:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.core:jackson-core:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.core:jackson-databind:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.datatype:jackson-datatype-guava:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.2 (c)
|         |         +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2 (c)
|         |         \--- com.fasterxml.jackson.datatype:jackson-datatype-joda:2.14.2 (c)
|         +--- com.fasterxml.jackson.core:jackson-core:2.14.2
|         |    \--- com.fasterxml.jackson:jackson-bom:2.14.2 (*)
|         \--- com.fasterxml.jackson:jackson-bom:2.14.2 (*)
+--- org.springframework.boot:spring-boot-starter-logging -> 3.0.5
|    \--- ch.qos.logback:logback-classic:1.4.6
|         +--- ch.qos.logback:logback-core:1.4.6
|         \--- org.slf4j:slf4j-api:2.0.4 -> 2.0.7
+--- org.springframework:spring-context -> 6.0.7
|    +--- org.springframework:spring-aop:6.0.7
|    |    +--- org.springframework:spring-beans:6.0.7
|    |    |    \--- org.springframework:spring-core:6.0.7
|    |    |         \--- org.springframework:spring-jcl:6.0.7
|    |    \--- org.springframework:spring-core:6.0.7 (*)
|    +--- org.springframework:spring-beans:6.0.7 (*)
|    +--- org.springframework:spring-core:6.0.7 (*)
|    \--- org.springframework:spring-expression:6.0.7
|         \--- org.springframework:spring-core:6.0.7 (*)
+--- org.springframework:spring-beans -> 6.0.7 (*)
+--- com.fasterxml.jackson.core:jackson-databind:{strictly 2.14.2} -> 2.14.2 (*)
+--- com.fasterxml.jackson.core:jackson-annotations:{strictly 2.14.2} -> 2.14.2 (*)
+--- org.apache.tomcat.embed:tomcat-embed-core:9.0.69
|    \--- org.apache.tomcat:tomcat-annotations-api:9.0.69 -> 10.1.7
+--- commons-logging:commons-logging:1.1.3 -> 1.2

We apply the following exclusions and dependencies to all modules in the multimodule build:

    configurations.all {
        // Short version cache so we don't accidentally use old versions
        resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
        exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'
        exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
        exclude group: 'org.slf4j', module: 'jul-to-slf4j'
        exclude group: 'org.slf4j', module: 'slf4j-log4j'
        exclude group: 'org.slf4j', module: 'slf4j-log4j12'
    }

    dependencies {
        implementation 'net.logstash.logback:logstash-logback-encoder:6.6'
        implementation 'org.springframework.boot:spring-boot-starter-logging'

Running my integration tests gives me:

Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.helpers.SubstituteLoggerFactory loaded from file: .../.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/2.0.7/41eb7184ea9d556f23e18b5cb99cad1f8581fc00/slf4j-api-2.0.7.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.helpers.SubstituteLoggerFactory

Strangely, this is only effecting some of the integration tests. Others are running as expected.

I'm at a bit of a loss here. I can't exclude logback or slf4j, as both of them are required. Any help would be appreciated.

EDIT I've done some debugging this morning and what seems to be happening is that whilst the org.slf4j.LoggerFactory is being initialised, it returns the substitute logger.

Worldling answered 29/3, 2023 at 13:8 Comment(6)
You shouldn't need spring-boot-starter-logging as that is included by default. Please add your dependencies to the question.Patricia
I'm going to struggle to include all of my dependencies to be honest. It's a pretty huge list. I'll see if I can replicate in a sample project.Worldling
@M.Deinum i've added some more dependencies & global exclude detailsWorldling
The logstash-logback-encoder you included is for Logback 1.2 which is SLF4J 1.7. I also wonder why commons-logging is on the classpath, that shouldn't be there. Finally you included an incompatible version of org.apache.tomcat.embed:tomcat-embed-core (version 9, whereas Spring BOot 3 needs version 10).Patricia
I am experiencing this exact problem as well after migrating to spring boot 3.0.5. i.e. Same exception. During tests. Some tests run and others fail.Wineshop
I've added an edit explaining what I think is happening. I'm still not totally sure why it's happening, but that seems to be what is happening.Worldling
W
2

We've got to the bottom of our issue here. Here's a summary of what was going on:

  • In the LoggerFactory, we could see that SLF4J was finding Logback as the provider, and started initialising it.
  • That initialisation took up to a second in some cases.
  • The reason the initialisation took a while was because it was using our main application logback.xml and apparently initialising the logstash appender is a fairly slow process.

The root cause of the problem seems to be that whilst slf4j is initialising, any requests to the LoggerFactory#getProvider method return the substitute provider, at which point the LogbackLoggingSystem#getLoggerContext in spring boot throws an exception, as the LoggerFactory returned is not valid.

I'm going to raise a bug against slf4j for this behaviour. It feels to me that if it's initialising, it shouldn't just return a dummy implementation.

Worldling answered 30/3, 2023 at 11:0 Comment(0)
A
0

I'm also facing this problem. For me solution is to change logback to 1.4.7:

<dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.7</version>
</dependency>

And override version of SLF4J that is included in spring to

<slf4j.version>2.0.12</slf4j.version>

Actually I'm using spring-boot-starter-parent 3.2.2

Hope that helps.

Arrears answered 11/2, 2024 at 16:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.