【问题标题】:log4j rootLogger seems to inherit log level of other logger. Why?log4j rootLogger 似乎继承了其他记录器的日志级别。为什么?
【发布时间】:2011-01-28 00:32:39
【问题描述】:

我有一个 log4J 设置,其中根记录器应该将错误级别及以上的消息记录到控制台,而另一个记录器将所有内容记录到 syslog。

log4j.properties 是:

# Root logger option
log4j.rootLogger=ERROR,R

log4j.appender.R=org.apache.log4j.ConsoleAppender
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d %p %t %c - %m%n

log4j.logger.SGSearch=DEBUG,SGSearch
log4j.appender.SGSearch=org.apache.log4j.net.SyslogAppender
log4j.appender.SGSearch.SyslogHost=localhost
log4j.appender.SGSearch.Facility=LOCAL6
log4j.appender.SGSearch.layout=org.apache.log4j.PatternLayout
log4j.appender.SGSearch.layout.ConversionPattern=[%-5p] %m%n

在我做的代码中

private static final Logger logger = Logger.getLogger("SGSearch");
.
.
.
logger.info("Commencing snapshot index [" + args[1] + " -> " + args[2] + "]");

发生的事情是我得到了所有日志级别的控制台日志。似乎正在发生的事情是 SGSearch 的级别以某种方式覆盖了为根记录器设置的级别。我想不通。

我已经确认 Log4J 正在读取我认为是的属性文件,而不是其他(通过 -Dlog4j.debug 选项)

【问题讨论】:

标签: java log4j


【解决方案1】:

在每个附加程序的基础上设置阈值是关键:

log4j.appender.SGSearch.Threshold=DEBUG

log4j.appender.R.Threshold=ERROR

这是一个比禁用“可加性”的建议更好的解决方案 - 问题是你想要 multiple 附加器处理的任何东西都会被它打败 - 所以你不能,例如, 如果您将可加性设置为 false...

【讨论】:

    【解决方案2】:

    Log4j 链接的工作方式有点违反直觉(至少对我而言)。见the log4j manual。如果请求级别等于或高于最具体匹配记录器的阈值,则接受它。一旦请求被接受,它就会被完整的祖先链处理,无论它们的阈值如何!

    要抑制链接行为,请添加:

    log4j.additivity.SGSearch=false
    

    这将导致记录器 SGSearch 处理的请求不再向上传递。

    另一个建议:不要将您的 logger 和 appender 命名为相同的名称,因为在将来的某个时候,您或同事会将它们混淆。记录器名称应指示处理哪种类型的日志记录,附加程序名称应指定日志记录的位置。所以在这种情况下,我认为“SGSearch”可能是记录器名称,而附加程序应该被称为“LocalSysLog”。

    顺便说一句:在我看来,您通过使用高阈值限制根记录器并针对特定记录器降低它来做正确的事情。这避免了嘈杂的库造成的混乱(Apache 有一些臭名昭著的库)。

    【讨论】:

    • 令我惊讶的是,Log4j 并没有独立于子记录器应用父记录器(其中根记录器是最顶层的父记录器)的日志事件阈值。
    • 谢谢!你的回答很有帮助。我在stackoverflow.com/questions/3023690/… 的回答中参考了您对stackoverflow.com/questions/3023690/… 的类似问题的回答。
    • "一旦请求被接受,它就会被完整的祖先链处理,不管它们的阈值如何!"如果这是真的,那么这不是 Log4j 中的错误吗?如此违反直觉的行为一定是错误的。
    • 我认为这与最小化每个日志事件需要完成的工作量有关。但正如我在回复开头所说的那样,一开始有点反直觉。
    • 我现在更好地理解了 loggers 是如何继承 appender 的,虽然起初这种行为对我来说确实很奇怪,但我同意这不是一个错误,但实际上是减少 appender 数量的有用方法需要与一系列记录器关联。
    【解决方案3】:

    关卡快速信息

    Log4J 级别

    记录器可能被分配级别。这 一组可能的级别,即 DEBUG, INFO、WARN、ERROR 和 FATAL 是 在 org.apache.log4j.Level 中定义 类。

    如果给定的记录器未分配 级别,然后它从它的继承一个 有指定的最近的祖先 级别。

    根记录器位于 记录器层次结构。它永远存在 并且总是有一个指定的级别。

    我已将您的示例 log4j 配置更改为以这种方式工作:

    # Root logger option
    log4j.rootLogger=ALL,R
    
    log4j.appender.R=org.apache.log4j.ConsoleAppender
    log4j.appender.R.Target=System.out
    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%d %p %t %c - %m%n
    log4j.appender.R.Threshold=ERROR
    
    log4j.appender.SGSearch=org.apache.log4j.net.SyslogAppender
    log4j.appender.SGSearch.SyslogHost=localhost
    log4j.appender.SGSearch.Facility=LOCAL6
    log4j.appender.SGSearch.layout=org.apache.log4j.PatternLayout
    log4j.appender.SGSearch.layout.ConversionPattern=[%-5p] %m%n
    log4j.appender.SGSearch.Threshold=DEBUG
    

    希望对你有帮助。

    【讨论】:

    • 谢谢。那行得通,但我发现我确实需要在您提供的示例中添加“log4j.logger.SGSearch=ALL,SGSearch”行。
    • @AndrewR:或者你可以这样做log4j.appender.SGSearch.Threshold=ALL,但那会使log4j.rootLogger 无用(如果我没记错的话)。
    • 我认为这个解决方案不是最理想的。请参阅下面的建议。
    • 嗯,@Adriaan Koster,该解决方案帮助了提问者,而这正是他/她想要的。
    • 很公平。我只是碰巧认为打开根记录器是一个常见错误,因为误解了 Log4j 中“可加性”的工作方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多