If I get rid of my 'multiple SLF4J Bindings' warning the logging stops working

11,028

Solution 1

There is a chapter entitled logging separation in the logback documentaiton which presents one possible solution.

Solution 2

Using the new -Dlogback.debug=true option will show messages from what appears to be slf4j-api looking for its implementations. (Logging looks like a pet peeve in the Java world to me).

09:12:05,472 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
09:12:05,472 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] at [jar:file:/home/FOO/BAR.jar!/logback-test.xml]
09:12:05,487 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@2c8d66b2 - URL [jar:file:/home/FOO/BAR.jar!/logback-test.xml] is not of type file
09:12:05,656 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
09:12:05,662 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
09:12:05,700 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
09:12:05,729 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.mongodb.morphia.mapping.Mapper] to ERROR
09:12:05,729 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.BAZ] to DEBUG
09:12:05,729 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to INFO
09:12:05,730 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
09:12:05,730 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
09:12:05,732 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@58651fd0 - Registering current configuration as safe fallback point
Share:
11,028
ssloan
Author by

ssloan

Updated on June 04, 2022

Comments

  • ssloan
    ssloan almost 2 years

    I've got the following directory structure in tomcat 6:

    tomcat
    |-lib
    |  |- logback-classic.jar
    |  |- logback-core.jar
    |  |- slf4j-api.jar
    |  |- myState.jar
    |-shared
    |  |-lib
    |  |  |- myStateLogback.xml
    |-webapps
    |  |-myApp
    |  |  |-WEB-INF
    |  |  |  |-logback.xml
    |  |  |  |-lib
    |  |  |  |  |-jcl-over-slf4j.jar
    |  |  |  |  |-logback-classic.jar
    |  |  |  |  |-logback-core.jar
    |  |  |  |  |-slf4j-api.jar
    

    myState.jar needs to live in the tomcat/lib directory as it is contains classes needed on tomcat startup as a global resource. It writes it's logging to slf4j so also needs the slf4j and logback jars. It uses a JoranConfigurator to load myStateLogback.xml.

    myApp webapp writes it's logging to commons-logging, but I want it go through slf4j to logback in preparation for moving all our logging to slf4j, so I'm using the jcl-over-slf4j bridge.

    With the above setup, the logging all works, but I get the following warning on startup:

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/D:/tomcat/lib/logback-classic-0.9.29.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/tomcat/webapps/myApp/WEB-INF/lib/logback-classic-0.9.29.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    

    If I take logback-classic out of the webapp's lib dir, I get the following exception:

    Exception in thread "Timer-30" java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/apache/catalina/loader/WebappClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
            at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:284)
            at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:252)
            at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:156)
            at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
            at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:272)
    

    If I remove the 2 logback jars, and the slf4j-api.jar from the webapp's lib directory, I get no warnings and no exceptions, but the logs from my webapp are picked up by the myStateLogback.xml file and go to it's logger, which I don't want. I know I can filter out the statements I don't want, but I want to have separate config files for the webapp and the jar. Is there a way to achieve this?

    I'm using tomcat 6.0.23, logback 0.9.29 and slf4j 1.6.3.

    Thanks, Sarah

  • ssloan
    ssloan over 12 years
    Thanks for that - very interesting and I think it would work in this situation. However, to keep things simple we've decided to use the tomcat juli logging for myState.jar and then put the logback/slf4j jars in each webapp for them to control their own logging.