18

My java project has dependencies with different SLF4J versions. How do I suppress the annoying warnings?

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:xyz234/lib/slf4j-
log4j12-1.5.8.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: Found binding in [jar:file:xyz123/.m2/repository/org/slf4j/slf4j-log4j12
/1.6.0/slf4j-log4j12-1.6.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

P.S.: This is not the same question as slf4j warning about the same binding being duplicate, the answer there is how to get rid of a false alarm warning, in my case it is a true warning however. P.S.S.: Sorry, I forgot to mention: I use Maven and SLF4J is included in the dependencies of my dependencies.

Community
  • 1
  • 1
Konrad Höffner
  • 11,100
  • 16
  • 60
  • 118
  • 1
    accept an answer if it is useful in solving the problem or if you have solved it yourself you can add your own answer and accept it. – Reddy Feb 27 '12 at 10:58
  • He's not wrong to not select an answer, even 11 years later, slf4j is spamming users because of it's bad design and complete inability to mute a warning outside of a pretty horrific hack. No acceptable answer here. – Bill K Aug 16 '22 at 22:22

6 Answers6

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.

palacsint
  • 28,416
  • 10
  • 82
  • 109
9
    PrintStream filterOut = new PrintStream(System.err) {
        public void println(String l) {
            if (! l.startsWith("SLF4J")) {
                super.println(l);
            }
        }
    };
    System.setErr(filterOut);

et voilà!

dzmanto
  • 216
  • 2
  • 6
ugo
  • 181
  • 1
  • 8
  • This is already discussed in the accepted answer ("A workaround could be to replace the System.err with System.setErr()") from almost three years ago, along with the problems with this approach ("you could lose other important messages if you do that."). – T.C. Jun 20 '14 at 14:21
6

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.

Ceki
  • 26,753
  • 7
  • 62
  • 71
  • As I have written, my project is a Maven project. I know exactly what this warning says, I just cannot control what dependencies my dependencies use in Maven. I know that it is just a warning but it obscures my console output and thus I want to get rid of it. P.S.: Ah sorry I have forgot to mention that I use Maven. – Konrad Höffner Sep 29 '11 at 12:04
  • (Just for posterity) this has nothing to do with maven: you _can_ control dependencies of your dependencies (as shown). Problems can still occur (w/ maven or not) when projects create an ["uber" jar combining multiple jars into one](http://stackoverflow.com/questions/11786265/multiple-slf4j-bindings-error-with-activemq-all-5-6-0-jar). Then you must find and use the original jars instead. If not using maven, you could manually remove the offending classes from the uber jar, but that's a poor work-around. But even w/ maven you could "fix" the original uber jar and upload it to an internal repo. – michael Jan 28 '13 at 22:37
  • Doesn't handle my case. I wrote a wrapper around logback. I really want both bindings in the classpath. Any suggestions? – Micha Berger Dec 24 '18 at 14:35
2

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.

Jack
  • 111
  • 1
  • 6
2

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.

Alex Clark
  • 357
  • 1
  • 3
  • 5
1

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>
Quartz
  • 1,731
  • 1
  • 14
  • 17