Spring Boot 3日志记录依赖冲突

Ben*_*een 8 logback slf4j gradle spring-boot

目前我们正在将应用程序升级到 Spring Boot 3,并且在运行时遇到一些记录器工厂冲突的问题。

我们使用 logback 来实现日志记录,但通过 slf4j。

我们正在拉入该spring-boot-starter-logging模块,并且没有在 build.gradle 中指定我们自己的 slf4j 或 logback 版本。

这是一个非常复杂的项目,有很多依赖项,但日志记录依赖项都在这里:

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

Run Code Online (Sandbox Code Playgroud)

我们将以下排除和依赖项应用于多模块构建中的所有模块:

    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'
Run Code Online (Sandbox Code Playgroud)

运行我的集成测试给了我:

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
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这仅影响部分集成测试。其他人正在按预期运行。

我在这里有点不知所措。我不能排除 logback 或 slf4j,因为它们都是必需的。任何帮助,将不胜感激。

编辑我今天早上做了一些调试,似乎正在发生的事情是,在org.slf4j.LoggerFactory初始化时,它返回替代记录器。

Ben*_*een 1

我们的问题已经到了底部。以下是所发生事件的摘要:

  • 在 中LoggerFactory,我们可以看到 SLF4J 正在寻找 Logback 作为提供者,并开始初始化它。
  • 在某些情况下,初始化需要花费一秒钟的时间。
  • 初始化花了一段时间的原因是它正在使用我们的主应用程序logback.xml,并且显然初始化logstash附加程序是一个相当慢的过程。

问题的根本原因似乎是在 slf4j 初始化时,对该方法的任何请求都会LoggerFactory#getProvider返回替代提供程序,此时LogbackLoggingSystem#getLoggerContextSpring Boot 会抛出异常,因为LoggerFactory返回的无效。

我将针对 slf4j 的这种行为提出一个错误。我觉得如果它正在初始化,它不应该只返回一个虚拟实现。