log4j记录两次


70

我正在使用log4j记录错误和其他系统信息。但是在INFO级别记录两次的信息。

public static void main(final String... args) throws Exception {

    LOGGER.info("program started");
    try {
        // try body codes
    } catch (Exception ex) {
        LOGGER.info("program start-up failed.",ex);
    }
}

但是,当程序启动或失败两次时,信息记录两次,任何人都可以帮助我找到造成这种情况的原因。


可能是配置问题或初始化问题。您在哪里初始化记录器?您不会两次调用Logger.getLogger(SomeClass.class)吗?一些其他代码可以为我们提供更多信息,以帮助您。
MaSEL 2011年

Answers:


98

好像您的消息是由根记录器记录的,还是由特定记录器记录的,因为您可能已经配置了两个附加程序(可能位于不同的位置-在属性文件中,然后在代码中)。

这可以通过在记录器上将可加性设置为false来解决。Log4j手册在Appenders和Layout部分中提到了可加性。


4
这是您应该如何解决,还是用创可贴掩盖了更大的配置问题?
Daniel Kaplan 2015年

1
没有记录器,将不会记录任何内容。当我重新添加记录器时,记录了两次。当我将可加性设置为false时,它将被记录一次。这里发生了什么?
詹姆斯·沃特金斯

@DanielKaplan如果您的记录器具有某种层次结构,则可以。从手动链接改写,说您只想要除Foo以外的所有类的ERROR消息,您想从中查看所有消息。您可以将Foo logger的可加性设置为false,这样任何ERROR消息都不会继续出现在root位置并再次打印。没有可加性,配置将变得更加复杂且难以维护,因此我会说这是正确的。
user812786 '16

1
我认为在此答案中包含XML配置示例会很好,因此无需参考手册即可快速添加可加性参数。
在线

@DanielKaplan是的,起初我想像您一样,不喜欢可加性创可贴,直到我在配置页上看到此注释“ Log4j将提供默认配置(如果无法找到配置文件)”并且默认配置强制即使您没有配置根记录器,也可以使用根记录器,而根记录器是记录日志的第二个副本的原因,这就是为什么其创建者发明了可加性配置并建议使用它的原因。现在,我觉得使用加性功能会更好。log4j
会计师

35

同意亚特兰蒂斯号。

log4j.rootCategory=INFO, console
log4j.logger.org.hibernate=INFO

上面的属性设置将导致重复记录。

但是添加

log4j.additivity.org.hibernate=false

解决了这个问题。

查阅本书第62页。http://books.google.com/books?id=hZBimlxiyAcC&printsec=frontcover#v=onepage&q&f=false


6
难道不是“假”,不是“真”吗?
James Scriven

Google图书似乎会随机隐藏某些页面。是我发现有帮助的博客文章。它包括一个更广泛的示例,其中包括一些log4j.category ...条目
Glenn Lawrence

31

对于那些使用XML格式的文件:

<logger name="package.class" additivity="false">
    <level value="info" />
    <appender-ref ref="file" />
    <appender-ref ref="console" />
</logger>

注意:默认情况下,记录器的可加性标志设置为true。


6

只需添加

logger.setadditivity(false);

到您的代码(参考)。

我们在控制台中得到了双倍的结果,这是因为附加器不是单例的,而是可加的。含义是,类别从其祖先继承所有附加程序(默认情况下)。如果我们将一个追加程序添加到类别中,并且它与其他某些追加程序写入同一基础流(控制台,相同文件等),则同一日志消息将在日志中出现两次(或多次)。此外,如果将层次结构中的两个类别配置为使用相同的附加程序名称,则Log4j将向该附加程序写入两次。针对该类别进行配置


1
参考”现在是无效链接。log4j 2.x的Logger不再可用setAdditivity()
Gerold Broser

2

如果可以使用Java调试器运行该程序,请在程序中放置一个断点,其中发生两次重复记录调用之一。

检查调试器中的记录器对象。如果它是org.apache.log4j.Logger(v 1.2.x),则它可能具有AppenderAttachableImpl。您可以查询AppenderAttachableImpl的附加列表。

如果您发现多个追加程序,则可能是问题所在-以及解决此问题的线索。


1

我遇到了同样的问题,并通过从根记录器中删除所有附加程序来解决。我不知道为什么,但是解决了我的问题,我正在分享:

        // Root
    rootLogger = Logger.getRootLogger();
    rootLogger.removeAllAppenders(); // Solve my problem
        // CSV
    csvLogger = rootLogger.getLogger("csvLogger");
        // Txt
    txtLogger = rootLogger.getLogger("txtLogger");

没有此额外的行,甚至当我使用csvLogger或txtLogger登录时,甚至将加性设置为false,它都会记录两次。


0

调整additivity属性的一种可能替代方法是从最具体到最一般的方式检查记录器。在下面的示例中,我们期望在foo.bar.LoggingExampleClass中发生的任何日志事件中,在控制台中看到两次日志记录。从foo.bar.LoggingExampleClass日志记录器中删除额外的控制台附加程序是安全的,因为Root记录器已经涵盖了它。

<Logger name="foo.bar.LoggingExampleClass" level="DEBUG">
  <AppenderRef ref="Console" />   <!-- THIS APPENDER COULD BE REMOVED -->
  <AppenderRef ref="FooBarPackageLogging" />
</Logger>

<Root level="WARN">
  <AppenderRef ref="Console" />
  <AppenderRef ref="MainLogFile" />
</Root>

可加性调整方法和附加器调整方法都需要权衡。关闭可加性可能会无意间阻止了所需的通用级别记录器的附加程序的使用。在上面的示例中,additivity="false"在foo.bar.LoggingExampleClass Logger上设置属性将意味着日志记录事件不会附加到Root记录器中引用的MainLogFile中。

另一方面,如果更改了父附加程序而不检查对更细粒度的记录器的影响,则依赖父附加程序可能会出现问题。例如,假设有一个要求将foo.bar.LoggingExampleClass日志记录事件写入控制台。由于可加性,它们当前处于上述示例配置中,即使已删除foo.bar.LoggingExampleClass Logger的控制台附加程序也是如此。但是,如果在没有任何其他调整的情况下也从根记录器中删除了控制台附加程序,则将不再满足该要求。


0

如果您不喜欢使用“加性”功能,则这是另一种选择。

就我而言(大多数情况下也是如此),根记录器位于此附加日志的后面,并且您的配置中还有另一个更高的记录器,类似这样

  <Loggers>
    <Logger name="com.foo.Bar" level="trace">
      <AppenderRef ref="Console"/>
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>

这将导致日志重复,并且如果您从该配置文件中完全删除了根记录器,log4j将强制使用默认的根记录器,请检查此说明

如果Log4j找不到配置文件,它将提供默认配置。DefaultConfiguration类中提供的默认配置将设置:

附加到根记录器的ConsoleAppender 。

一个PatternLayout设置为附加到ConsoleAppender的模式“%d {HH:mm:ss.SSS} [%t]%-5level%logger {36}-%msg%n”

请注意,默认情况下,Log4j将根记录程序分配给Level.ERROR。

如果要覆盖默认的根记录器并强制其不记录,可以从配置文件中删除它的Appender,如下所示

<Root level="error">
</Root>

这只是另一个选择,但是,我喜欢使用推荐的方法,并将“ additivity”属性设置为子记录器

<Logger name="com.foo.Bar" level="trace" additivity="false">
  <AppenderRef ref="Console"/>
</Logger>

-1

在您的resources/log4.properties文件中。

在该配置文件中,如果您有“ log4j.rootLogger= DEBUG, file”,则不要包含“ log4j.logger.org.springframework=DEBUG, file”。只需保留log4j.rootLogger部分。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.