While running unit test SLF4J: Class path contains multiple SLF4J bindings

I am trying to run a unit test and getting the following warning, and as a result I am not able to log anything during the test:

SLF4J: Found binding in [jar:file:/C:/Users/Puiu/.gradle/caches/8.14.2/generated-gradle-jars/gradle-api-8.14.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/Puiu/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.12/485f77901840cf4e8bf852f2abb9b723eb8ec29/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Actual binding is of type [org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext]

It appears that there is a clash between the gradle api and my dependency.

In my dependecies I explicitly include SLF4J. I also include the gradleApi as I am using some hamcrest functionality (org.gradle.internal.impldep.org.hamcrest.BaseMatcher):

dependencies {
...
    implementation("org.slf4j:slf4j-log4j12:1.7.12")
    testImplementation(gradleApi())
}

Running ‘dependencies’ produces the following output. Notice that no conflict is reported.

testRuntimeClasspath - Runtime classpath of source set 'test'.
...
+--- org.slf4j:slf4j-log4j12:1.7.12
|    +--- org.slf4j:slf4j-api:1.7.12
|    \--- log4j:log4j:1.2.17
...

I assume that I would need to exclude the SLF4J artifact from the gradleApi dependency but the usual way of exclusion does not compile:

    testImplementation(gradleApi()) {
        exclude(group = "org.slf4j", module = "slf4j-log4j12")
    }

Any suggestions?

Thanks,
Vladimir

The exclude and conflict do not work, as the gradleApi() dependency does not depend on slf4j but provides an slf4j implementation.

The question is why you depend on slf4j-log4j12 and gradleApi() in your project.

Besides that you should probably not use Gradle internal classes like the one you mentioned, what do you develop? A Gradle plugin? Then you should not add an SLF4J implementation like slf4j-log4j12 as dependency.

Only end-products like an application you write or Gradle should provide logging facade implementations like slf4j-log4j12 to redirect the facade users to the actual logging backend provided by the end-product.

If you just want to log from your Gradle plugin you need to do it like for any other library that wants to log using SLF4J, use just sfl4j-api.

If you are are not developing build logic, then the gradleApi() dependency is highly questionable anyway.

Thanks Bjorn for the speedy reply.

I am developing an application and I need to log behavior (slf4j-log4j12) and need to test behavior via unit tests (hence using hamcrest).

You are right, I should use the standalone hamcrest library rather than the derivative bundled with gradle.

1 Like