Jetty 9.1+:如何使用log4j / slf4j获取我的webapp日志

时间:2015-12-29 03:26:15

标签: java logging log4j slf4j jetty-9

我在${jetty.base}的Jetty 9.3.6上运行了一个webapp,设置为/opt/mybase/。我的webapp使用slf4j并使用log4j作为实际的日志记录框架,因此我的webapp源中的日志记录语句如下所示:

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");
        }
   }

   ...

}

在我的gradle构建文件中,我这样做了:

dependencies {

 ...
 compile 'org.slf4j:slf4j-api:1.7.12'
 compile 'org.slf4j:slf4j-log4j12:1.7.12'
 compile 'log4j:log4j:1.2.17'
 ...
}

此配置适用于使用相同日志框架的另一个(非Jetty,非webapp)Java项目;我可以使用${project.home}/src/main/resources/log4j.properties来控制日志的输出。

无论如何,当我搬到Jetty时,我按照here的说明进行了操作;但是一旦我这样做,我就点击了multiple-bindings error。为了解决这个问题,我删除了我的gradle构建文件中的slf4j引用,但这导致了错误:

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

然后我删除了对slf4jlog4j的所有引用(注释了我在上面的build.gradle中显示的三行),但我看到的错误仍然是相同的。我究竟做错了什么?

我的/opt/mybase/resources/log4j.properties文件:

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

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

嗯,这对我来说是一个真正令人尴尬的错误。我相信,主要问题不是log4jslf4j或码头配置。我觉得这很好用。此外,尽管有多个绑定,但是jetty服务器实际上选择了Jetty日志中显示的某些

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]

此外,如果一个依赖项已内置日志记录,那么你运气不好,取决于维护得很好,我想你无论如何都会发生冲突。至少,我知道在这种情况下无法阻止这种情况。

嗯,真正的问题是webapp没有自己的log4j.properties(如果你使用gradle,这将在$(projectHome)/src/main/resources/log4j.properties)。我将它添加到我的项目中,我的日志记录生成了更有意义(即,我在/opt/mybase/logs/my-silly-webapp-log.txt)中看到它应该在哪里。

最后,我报告的崩溃是无关的(在12月29日的评论中)并且与Jetty 9.3.6错误有关,这个问题尚未解决,尽管在Jetty bug db 9.3中被调用已解决0.6。让我失望的是,在我最初报告的multiple_bindings错误之后立即出现了日志。看来它们没有关系。在我写这篇文章时,我无法追踪Jetty bug DB中的确切错误,但最后一次检查了该错误(大约一周前),问题出现在 Jetty log4j.properties(在/opt/mybase/resources/log4j.properties)已将rootLogger设置为DEBUG(从该错误的评论中获得)。当Jetty rootLogger中的log4j.properties设置为DEBUG时,我能够重现错误(websocket应用程序本身工作正常,尽管Jetty日志相关崩溃)。通过将 Jetty rootLogger的{​​{1}}移至INFO或更低,我可以确认问题消失了。我将在Jetty的bug DB中提出它。

希望这有助于某人。