33

Is there anyway to force slf4j to use specific logging provider (logback in my case)? As in their docs:

Multiple bindings were found on the class path

SLF4J API is desinged to bind with one and only one underlying logging framework at a time. If more than one binding is present on the class path, SLF4J will emit a warning, listing the location of those bindings. When multiple bindings are available on the class path, select one and only one binding you wish to use, and remove the other bindings. For example, if you have both slf4j->simple-1.6.6.jar and slf4j-nop-1.6.6.jar on the class path and you wish to use the nop (>no-operation) binding, then remove slf4j-simple-1.6.6.jar from the class path. If it is not possible to remove the superflous bindings, SLF4J will still bind with one logging framework/implementation. As of version 1.6.6, SLF4J will name the framework/implementation class it is actually bound to.

NOTE The warning emitted by SLF4J is just that, a warning.

In my case i have log4j.jar, slf4j-log4j12.jar, log4j-over-slf4j.jar and all logback jars in classpath. I know that it is error to have slf4j-log4j12.jar and log4j-over-slf4j.jar together, but my project is very big, and it is not always simple to find and exclude maven dependency. In this case slf4j even did not printed any warning, because we use only logback configs. It took me a day to understand this jar hell.

All i want is to force slf4j use logback via JVM argument, for example, so it can print warnings and i can exclude jars in future.

madhead
  • 31,729
  • 16
  • 153
  • 201
  • 1
    "it is not always simple to find and exclude maven dependency" -- use `mvn dependency:tree -Dincludes='*log4j*'`, etc. – Matthew Read Jun 06 '22 at 17:33

3 Answers3

36

Generally your own code is at the beginning of the classpath. Because of this, one way to do it is to create your own org.slf4j.impl.StaticLoggerBinder class:

package org.slf4j.impl;

import org.slf4j.ILoggerFactory;
import org.slf4j.spi.LoggerFactoryBinder;

/**
 * Force tests to use JDK14 for logging.
 */
@SuppressWarnings("UnusedDeclaration")
public class StaticLoggerBinder implements LoggerFactoryBinder {
    private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

    public static String REQUESTED_API_VERSION = "1.6";

    public static final StaticLoggerBinder getSingleton() {
      return SINGLETON;
    }

    private StaticLoggerBinder() {
    }

    @Override
    public ILoggerFactory getLoggerFactory() {
        return new JDK14LoggerFactory();
    }

    @Override
    public String getLoggerFactoryClassStr() {
        return "org.slf4j.impl.JDK14LoggerFactory";
    }
}
Eric Pabst
  • 536
  • 4
  • 12
18

Other than cleaning up your class path, there is no way to force SLF4J to bind with a given implementation.

Ceki
  • 26,753
  • 7
  • 62
  • 71
3

I believe if you put the logback JAR at the start of your classpath (or before the other JARs containing an slf4j impl), it'll be the one that is used.

However, it would be nice if slf4j supported a JVM arg that specified the JAR containing the impl, and overrode looking in the classpath, so you wouldn't have to deal with sorting the JARs in the classpath to ensure the one you want is used.

Brent212
  • 1,835
  • 4
  • 19
  • 23