How to suppress SLF4J Warning about multiple bindings?

风格不统一 提交于 2019-12-03 10:44:21

Remove one of the slf4j-log4j12-1.5.8.jar or slf4j-log4j12-1.6.0.jar from the classpath. Your project should not depend on different versions of SLF4J. I suggest you to use just the 1.6.0.

If you're using Maven, you can exclude transitive dependencies. Here is an example:

<dependency>
    <groupId>com.sun.xml.stream</groupId>
    <artifactId>sjsxp</artifactId>
    <version>1.0.1</version>
    <exclusions>
        <exclusion>
            <groupId>javax.xml.stream</groupId>
            <artifactId>stax-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

With the current slf4j-api implementation it is not possible to remove these warnings. The org.slf4j.LoggerFactory class prints the messages:

  ...
  if (implementationSet.size() > 1) {
    Util.report("Class path contains multiple SLF4J bindings.");
    Iterator iterator = implementationSet.iterator();
    while(iterator.hasNext()) {
      URL path = (URL) iterator.next();
      Util.report("Found binding in [" + path + "]");
    }
    Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
  }
  ...

The Util class is the following:

public class Util {

  static final public void report(String msg, Throwable t) {
    System.err.println(msg);
    System.err.println("Reported exception:");
    t.printStackTrace();
  }
  ...

The report method writes directly to System.err. A workaround could be to replace the System.err with System.setErr() before the first LoggerFactory.getLogger() call but you could lose other important messages if you do that.

Of course you can download the source and remove these Util.report calls and use your modified slf4j-api in your project.

Have you read the URL referenced by the warning?

SLF4J: See [http://www.slf4j.org/codes.html#multiple_bindings][1] for an explanation.

Here is what the link states:

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 this happens, select the one and only one binding you wish to use, and remove the other bindings.

For example, if you have both slf4j-simple-1.6.2.jar and slf4j-nop-1.6.2.jar on the class path and you wish to use the nop (no-operation) binding, then remove slf4j-simple-1.6.2.jar from the class path.

Note that the warning emitted by SLF4J is just that, a warning. SLF4J will still bind with the first framework it finds on the class path.

ugo
    PrintStream filterOut = new PrintStream(System.err) {
        public void println(String l) {
            if (! l.startsWith("SLF4J")) {
                super.println(l);
            }
        }
    };
    System.setErr(filterOut);

et voilà!

If using maven always use the command

mvn dependency:tree

This will list all the dependencies added to the project including dependencies to the jars we have included. Here we can pin point multiple version, or multiple copies of jars that come in with other jars which were added. Use

<exclusions><exclusion><groupId></groupId><artifactId></artifactId></exclusion></exclusions>

in <dependency> element to exclude the ones which conflict. Always re-run the maven command above after each exclusion if the issue persist.

Sometimes excluding the 2nd logger from the classpath would require too many contortions, and the warning is incredibly annoying. Masking out the standard error as the very beginning of the program does seem to work, e.g.

    public static void main(String[] args)
    {
        org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.OFF);
        PrintStream old = System.err;
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
        // ... trigger it ...
        System.setErr(old);

        ...

whereby the trigger it part should call some nop function that accesses the logging system and would have otherwise caused the message to be generated.

I wouldn't recommend this for production code, but for skunkworks purposes it should help.

If you're using an old version of Jetty (say Jetty 6), you may need to change the classloading order for the webapp to make it higher priority than the container's. You can do that by adding this line to the container's xml file:

<Set name="parentLoaderPriority">false</Set>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!