Reputation: 2133
I have a webapp running on Jetty 9.3.6 in ${jetty.base}
which is set to /opt/mybase/
. My webapp uses slf4j
and I use log4j
as the actual logging framework, so the logging statements in my webapp source looks like this:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SillyClass
{
private static final Logger log = LoggerFactory.getLogger (SillyClass.class.getName ());
...
public static void foo ()
{
if (error ())
{
log.error ("ERROR");
}
else
{
log.info ("NOT an error");
}
}
...
}
And in my gradle build file, I did this:
dependencies {
...
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'org.slf4j:slf4j-log4j12:1.7.12'
compile 'log4j:log4j:1.2.17'
...
}
This configuration works quite well for another (non-Jetty, non-webapp) Java project which uses the same logging framework; I can use ${project.home}/src/main/resources/log4j.properties
to control the output of the log.
Anyway, when I moved to Jetty, I followed the instructions here to the dot; but as soon as I did that, I hit the multiple-bindings error. To correct that, I removed the slf4j
references in my gradle build file, but that resulted in the error:
java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/eclipse/jetty/webapp/WebAppClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/eclipse/jetty/start/Classpath$Loader) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
I then removed all references to slf4j
and log4j
(commented out the three lines I show in my build.gradle
above), but the error I see is still the same. What am I doing wrong?
My /opt/mybase/resources/log4j.properties
file:
log4j.rootLogger=TRACE, FILE
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=/opt/mybase/logs/jetty.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern= %d{dd MMM yyyy HH:mm:ss.SSS} %l %m%n
Any help is appreciated.
Upvotes: 1
Views: 3315
Reputation: 2133
Well, this is a genuinely embarrassing error on my part. The main issue was not log4j
or slf4j
or configuration in jetty, I believe. I think that worked just fine. Also, despite multiple bindings, the jetty server actually chooses something shown here in the Jetty logs:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/tmp/jetty-0.0.0.0-443-webapp.war-_webapp-any-8458003046853847474.dir/webapp/WEB-INF/lib/slf4j-log4j12- 1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/mybase/webapp/lib/logging/slf4j-log4j12- 1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
Moreover, if a dependency has logging built in, you are out of luck, depending on how well maintained things are, I think you will have a clash anyway. At least, I know of no way to prevent this in that case.
Well, the real issue was that the webapp did not have its own log4j.properties
(if you are using gradle, this would be in $(projectHome)/src/main/resources/log4j.properties)
. I added that to my project and my logging makes a lot more sense (i.e., I see it where it should be, in /opt/mybase/logs/my-silly-webapp-log.txt
).
Lastly, the crash I reported is unrelated (in the comments, on Dec 29) and has to do with Jetty 9.3.6 bug which is as yet unresolved, it appears, despite being called resolved in the Jetty bug db for 9.3.6. What threw me off was that the logs appeared immediately after the multiple_bindings
error I reported originally. They are not related, it appears. I cannot track down the exact bug in Jetty bug DB as I write this, but the last I checked that bug (about a week ago), the issue was when the Jetty log4j.properties
(in /opt/mybase/resources/log4j.properties
) has set rootLogger
to DEBUG
(got that from the comments on that bug). I am able to reproduce the error (the websocket app itself just works fine, despite the Jetty log related crash) when my rootLogger
in Jetty log4j.properties
is set to DEBUG
. By moving the rootLogger
for Jetty log4j.properties
to INFO or lower, I am able to confirm that the problem goes away. I will raise it in Jetty's bug DB.
Hope this helps someone.
Upvotes: 1