Logging log4j记录两次

Logging log4j记录两次,logging,log4j,Logging,Log4j,我使用log4j来记录错误和其他系统信息。但来自信息级别记录两次的信息 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.",

我使用log4j来记录错误和其他系统信息。但来自信息级别记录两次的信息

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

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

看起来您的消息会由根记录器记录一次,由特定记录器记录一次,因为您可能已配置了两个附加器(可能位于不同的位置-在属性文件中,然后在代码中)

这可以通过在您的记录器上将加法设置为false来解决。Log4j在Appenders和Layout部分提到加法。检查是否同意亚特兰蒂斯

log4j.rootCategory=INFO, console
log4j.logger.org.hibernate=INFO
上述属性设置将导致双重日志记录

然而,增加

log4j.additivity.org.hibernate=false
修正了这个问题


查看本书第62页。

对于使用XML格式的用户:

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


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

如果可以使用Java调试器运行程序,请在程序中设置一个断点,在其中一个双日志调用发生的地方设置断点

检查调试器中的logger对象。如果它是org.apache.log4j.logger(v1.2.x),则它可能有一个AppenderTachableImpl。您可以查询AppenderTachableImpl以获取appender列表

如果您发现多个appender,这可能就是问题所在,也是解决问题的线索。

只需添加

logger.setadditivity(false);
添加到您的代码()


我们在控制台中得到了双重结果,这是因为附加器不是单例,它们是可加的。这意味着,一个类别从其祖先继承了所有附加器(默认情况下)。如果我们将一个附加器添加到一个类别中,它将写入相同的底层流(控制台、相同的文件等)与其他附件一样,相同的日志消息将出现两次(或更多)此外,如果层次结构中的两个类别被配置为使用相同的appender名称,Log4j将向该appender写入两次。为该类别配置的调整
additivity
属性的一个潜在替代方法是从最特定的到最通用的检查记录器。在下面的示例中,我们将对于foo.bar.LoggingExampleClass中发生的任何日志事件,我们希望在控制台中看到双重日志记录。从foo.bar.LoggingExampleClass记录器中删除额外的控制台附加程序是安全的,因为它已经被根记录器覆盖

<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记录器上的属性意味着日志事件不会附加到根记录器中引用的MainLogFile中

<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>

另一方面,如果在未检查对更细粒度记录器的影响的情况下更改父附加程序,则依赖父附加程序可能会有问题。例如,假设有一项要求,即foo.bar.LoggingExampleClass日志事件应写入控制台。由于此外,即使删除了foo.bar.LoggingExampleClass记录器的控制台追加器,也无法满足此要求。但是,如果控制台追加器也在不进行任何额外调整的情况下从根记录器中删除,则将不再满足此要求。

我也遇到了同样的问题,并通过从根记录器中删除所有追加器进行了修复。 我不知道为什么,但解决了我的问题,我正在分享:

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

如果没有这一行,即使将additivity设置为false,只要我使用csvLogger或txtLogger登录,它就会在
资源/log4.properties
文件中记录两次


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

如果您不喜欢使用“additivity”功能,这是另一个选项

在我的情况下(大多数情况下也是在你的情况下),根记录器在这个额外的日志后面,并且在你的配置中有另一个更高的记录器,类似这样的

  <Loggers>
    <Logger name="com.foo.Bar" level="trace">
      <AppenderRef ref="Console"/>
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
<Root level="error">
</Root>
这只是另一个选项,但是,我喜欢使用推荐的方法,并将“additivity”属性设置为子记录器

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


这是你应该如何解决的问题,或者是一个创可贴掩盖了一个更大的配置问题?没有记录器,什么都没有记录。当我添加记录器回来时,它被记录了两次。当我设置可加性为false时,它记录了一次。这里发生了什么?您只希望所有类都有错误消息,除了Foo,您希望从中查看所有消息。您可以将Foo logger additivity设置为false,这样所有错误消息都不会继续发送到root并再次打印。如果没有additivity,配置将更加复杂且不易维护,因此我认为这是正确的。我认为这样做会更好o在这个答案中包含XML配置的例子,这样你就可以在不引用手册的情况下快速添加可加性参数。@丹尼尔卡普兰:是的,起初我想你,不喜欢加性带帮助,直到我看到这个注解“Log4J将提供一个默认配置,如果它找不到配置文件”此时,默认配置强制使用根日志记录器,即使您没有配置根日志记录器,根日志记录器也会记录日志的第二个副本,这就是为什么
log4j
的创建者发明了可加性配置,并推荐使用它。现在我觉得使用可加性功能更好。Google books似乎随机隐藏某些页面。一篇我发现很有用的博客文章。它包括一个更广泛的示例,包括一些log4j。类别…entries这可能是配置问题