【问题标题】:How to control logging by 3rd-party components in webapp in Tomcat 5.5?如何在 Tomcat 5.5 的 webapp 中控制第三方组件的日志记录?
【发布时间】:2011-03-29 21:43:47
【问题描述】:

我们在 Linux 上使用 Tomcat 5.5。我们的 web 应用程序使用 log4j 进行日志记录(基于功能且记录器不多),并有意将记录器的可加性设置为 false。我们的记录器记录到我们自己的日志文件中。他们都没有登录到控制台。

我们遇到的一个问题是,当我们的记录器级别设置为 DEBUG 时,我们开始在 catalina.out 中从 3rd 方组件(尤其是 oscache)获取大量调试日志记录。

在 .../common/classes 中有一个最小的 log4j.properties 文件:

log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout

# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

.../webapps/ourapp/WEB-INF/classes 中没有 log4g.properties 文件。

我尝试的第一件事是更改为log4j.rootLogger=ERROR, A1,但这并没有什么不同。

接下来我尝试创建一个包含单行的 .../webapps/ourapp/WEB-INF/classes/log4j.properties 文件

log4j.logger.com.opensymphony.oscache=ERROR

看看这是否会停止 oscache 日志记录。它确实做到了,但令人惊讶的是(对我来说)它停止了所有不需要的日志记录,而不仅仅是 oscache 日志记录。所以我评论了这条线并再次尝试。仍然没有任何不需要的日志记录。我将文件移到一边,现在不需要的日志记录又回来了。我创建了一个长度为零的 log4j.properties,所有不需要的日志记录又消失了(!)虽然这是我想要的短期内容,但它让我想知道还有哪些其他日志记录被丢弃(以及为什么!)。因此,仅仅依靠它我会感到不舒服。

Tomcat 5.5 文档中的“日志”一章只是说您可以通过将属性文件放在 WEB-INF/classes 中来进行每个应用程序的配置,但没有(至少我找不到)谈论如何与 common/classes 中指定的配置交互。

所以:

  • 第 3 方组件如何首先记录到 catalina.out?我猜他们的日志记录可能会冒泡到根记录器,但是为什么即使根记录器级别设置为错误,他们仍然会记录?
  • 为什么将记录器上的记录器级别设置为 DEBUG 会启动此记录?我们的记录器有我们自己的名称,因此 oscache 和其他东西不可能是我们记录器的祖先。
  • 为什么即使是零长度的 WEB-INF/classes/log4j.properties 文件也会停止一大堆日志记录?
  • 如何以“正确”的方式执行此操作并以有意义的方式限制日志记录,而不是依靠一些奇怪的(对我而言)副作用来关闭它?


好奇者和好奇者。我尝试了马特关于打开调试的建议。我还为 webapp 制作了一个更广泛的 log4j.properties 文件:

log4j.rootLogger=INFO, SSOA1
log4j.appender.SSOA1=org.apache.log4j.ConsoleAppender
log4j.appender.SSOA1.layout=org.apache.log4j.PatternLayout

# Print the date in ISO 8601 format
log4j.appender.SSOA1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

log4j.logger.com.opensymphony.oscache=ERROR
#log4j.additivity.com.opensymphony.oscache=false

tomcat 启动时我看到:

log4j: Using URL [file:/srv/www/tomcat5/base/webapps/myapp/WEB-INF/classes/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/srv/www/tomcat5/base/webapps/myapp/WEB-INF/classes/log4j.properties
log4j: Parsing for [root] with value=[INFO, SSOA1].
log4j: Level token is [INFO].
log4j: Category root set to INFO
log4j: Parsing appender named "SSOA1".
log4j: Parsing layout options for "SSOA1".
log4j: Setting property [conversionPattern] to [%d [%t] %-5p %c - %m%n].
log4j: End of parsing for "SSOA1".
log4j: Parsed "SSOA1" options.
log4j: Parsing for [com.opensymphony.oscache] with value=[ERROR].
log4j: Level token is [ERROR].
log4j: Category com.opensymphony.oscache set to ERROR
log4j: Handling log4j.additivity.com.opensymphony.oscache=[null]
log4j: Finished configuring.

但尽管 oscache 记录器的级别设置为错误,但我仍然在日志中看到类似这样的内容:

2011-03-30 14:53:22,076 [main] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache - get called (key=AUDIT_KEY_OLDEST_TIMSTAMP)

如果我强制将 oscache 记录器级别设置为 ERROR(log4j 调试输出显示我是),那么为什么要发送这条 DEBUG 消息?子记录器覆盖代码中的级别?

我注意到的是,如果我在 webapp 的 log4j.properties 文件中取消注释掉 oscache 记录器的“可加性”行,那么记录确实会消失。因此,似乎 oscache 日志记录依赖于祖先附加程序,而不是它自己的。但更奇怪的是,将 oscache 记录器级别设置为 ERROR 并没有阻止这些事情。

【问题讨论】:

  • 将 -Dlog4j.debug 添加到 Tomcat 的环境变量中,让 log4j 打印出一大堆关于正在读取哪个配置文件的诊断信息
  • 谢谢!明天早上我肯定会尝试第一件事。
  • 我试过设置调试属性。结果已编辑到原始问题中。

标签: java tomcat log4j tomcat5.5 oscache


【解决方案1】:

您可以配置 log4j.properties 以仅获取您的代码日志,如下所示,并将其放入与 catalina.out 不同的文件中。

handlers = org.apache.juli.FileHandler

org.apache.juli.FileHandler.level=ALL org.apache.juli.FileHandler.directory=${catalina.base}/logs org.apache.juli.FileHandler.prefix=yourapp-name.

com.yourproject.module.package.level=ALL

【讨论】:

    【解决方案2】:

    我已经弄清楚到底发生了什么。问题在于,隐藏在 webapp 另一部分内部的是以下代码,该代码在该组件进入调试模式时运行:

    public static synchronized void setDebugOn(boolean debugOn) {
        if (isAllDebugOn() ^ debugOn) {
            setAllDebugOn(debugOn);
            Enumeration en = LogManager.getCurrentLoggers();
            while (en.hasMoreElements()) {
                setDebugOn((Logger) en.nextElement(), debugOn);
            }
            setDebugOn(LogManager.getRootLogger(), debugOn);
        }
    }
    
    public static void setDebugOn(String name, boolean debugOn) {
        setDebugOn(getLogger(name), debugOn);
    }
    
    private static void setDebugOn(Logger logger, boolean debugOn) {
        logger.setLevel(debugOn ? Level.DEBUG : Level.INFO);
    }
    

    换句话说,当这个组件进入调试模式时,它也会把 WEBAPP 中的每个 LOG4J LOGGER 都置于调试模式(我已经通过更改代码打印出这三个方法中最后一个方法中每个记录器的名称。所以 blammo - 所有碰巧使用 log4j 的第 3 方的东西都开始记录其调试输出,而不管 log4j.properties 说什么。叹息。

    当我使用该循环更改方法以仅处理与该组件相关的特定记录器的级别时,我的 log4j.properties 配置开始按预期工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      • 2012-03-12
      • 2011-06-24
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      相关资源
      最近更新 更多