【问题标题】:Log4j logging twice with different formatsLog4j 使用不同格式记录两次
【发布时间】:2016-08-26 15:06:47
【问题描述】:

我不明白为什么 log4j 会以不同的格式附加两次。有人遇到过这种情况吗?

这是我的 log4j.xml 文件:

<log4j:configuration>

    <appender name="async" class="org.apache.log4j.AsyncAppender">
    <!-- this parameter need to be set to false to avoid application from hanging. -->
        <param name="Blocking" value="false" />
        <appender-ref ref="myAppender" />
    </appender>

    <appender name="myAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="INFO" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{ISO8601} [%t] %c %x - %m%n" />
        </layout>
    </appender>

    <logger name="com.server">
        <level value="INFO" />
    </logger>

    <logger name="org.springframework">
        <level value="INFO" />
    </logger>

    <logger name="org.hibernate.LazyInitializationException" additivity="false">
       <level value="off" />
       <appender-ref ref="async" />
    </logger>

    <logger name="net.sf.ehcache">
        <level value="INFO" />
    </logger>

     <logger name="com.mchange">
         <level value="INFO" />
     </logger>

     <root>
         <priority value="INFO" />
         <appender-ref ref="async" />
     </root>

</log4j:configuration>

这是一些示例输出:

INFO  2016-08-26 11:01:38,353 [main] com.server.Server  - Server started successfully...
11:01:38,353 INFO :  Server started successfully...

编辑:当我将“myAppender”附加程序阈值更改为“ERROR”时,仍在生成显示的第二条日志消息(以时间开头的消息,而不是“INFO”)。是否有一些我需要禁用的默认记录器?似乎某些东西仍在记录那些“INFO”级别的消息,即使指定的附加程序是用于“ERROR”级别的消息。此外,如果我注释掉整个 log4j.xml 文件,第二条日志消息(以及所有类似的)仍在记录中。我怎样才能防止这种情况?谢谢!

【问题讨论】:

  • 我认为那是因为您为同一件事使用了 2 个附加程序。尝试注释掉“异步”附加程序并将根子节点更改为&lt;appender-ref ref="myAppender" /&gt;
  • 没有帮助,生成相同的重复输出
  • 尝试用name="org.hibernate.LazyInitializationException"注释掉完整的记录器
  • 发生同样的问题
  • 嗯,那我建议你把所有的loggers和appender都注释掉,从根目录开始一一添加

标签: java log4j


【解决方案1】:

我不熟悉 log4j 的 XML 语法(我使用 log4j.properties 进行配置)所以这里是我的 2 美分来帮助您调试和修复代码。

首先尝试使用下面的根记录器配置而不是你的&lt;appender-ref ref="async" /&gt; -

<logger name="org.hibernate.LazyInitializationException" additivity="false">
   <level value="off" />
   <appender-ref ref="myAppender" />
</logger>
..............
...........
 <root>
     <priority value="INFO" />
     <appender-ref ref="myAppender" />
 </root>

如果上述方法不起作用,请尝试将&lt;param name="Threshold" value="ERROR" /&gt; 放在asyncmyAppender 中,我想不会打印Server started successfully 日志(我想你已经尝试过myAppender

如果这有帮助,则意味着您尝试引用/继承记录器的方式无法正常工作或使用,因此您已经从该方向思考并纠正了问题,您需要阅读有关appender-ref 元素的更多信息和AsyncAppender记录器。

无论上述是否有效,我猜您正在尝试实现以下目标 -

  1. 在标准输入/输出(即终端窗口)上打印
  2. 在文件中打印以及用于 prod 环境

我会在 log4j.properties 中执行以下操作:

log4j.logger.com.sks.cs50=DEBUG, CS50GlobalFileAppender, stdout

#####CS50 Web log##########
log4j.appender.CS50GlobalFileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.CS50GlobalFileAppender.File=${logDir}cs50.log
log4j.appender.CS50GlobalFileAppender.MaxBackupIndex=50
log4j.appender.CS50GlobalFileAppender.Threshold=DEBUG
log4j.appender.CS50GlobalFileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.CS50GlobalFileAppender.layout.ConversionPattern=%C %d [%t] [%X{randomNumber}] %-5p - %m%n
log4j.appender.CS50GlobalFileAppender.MaxFileSize=500000KB

# Log format to standard output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%X{randomNumber}] %-5p - %m%n

log4j.logger.org.apache = INFO
log4j.logger.com.sun = INFO
log4j.logger.sun = INFO
log4j.logger.javax.xml.bind = INFO
log4j.logger.org.springframework = INFO
log4j.logger.com.cgi = DEBUG

所以,我想你可以做如下的事情。

<log4j:configuration>

    <appender name="async" class="org.apache.log4j.AsyncAppender">
    <!-- this parameter need to be set to false to avoid application from hanging. -->
        <param name="Blocking" value="false" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{ISO8601} [%t] %c %x - %m%n" />
        </layout>
    </appender>

    <appender name="myAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="INFO" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{ISO8601} [%t] %c %x - %m%n" />
        </layout>
    </appender>

    <logger name="com.server">
        <level value="INFO" />
    </logger>

    <logger name="org.springframework">
        <level value="INFO" />
    </logger>

    <logger name="org.hibernate.LazyInitializationException" additivity="false">
       <level value="off" />
       <appender-ref ref="async" />
    </logger>

    <logger name="net.sf.ehcache">
        <level value="INFO" />
    </logger>

     <logger name="com.mchange">
         <level value="INFO" />
     </logger>

     <root>
         <priority value="INFO" />
         <appender-ref ref="async" />
         <appender-ref ref="myAppender" />
     </root>

</log4j:configuration>

请注意上面的 XML 配置是假设 org.apache.log4j.AsyncAppender 打印在某个日志文件中,但如果它没有(我猜它没有)那么上面不会工作(如果你用org.apache.log4j.RollingFileAppender替换AsyncAppender,你仍然可以使用上面的XML配置来实现文件+控制台日志记录)我想知道为什么你不能直接使用org.apache.log4j.AsyncAppender,因为它已经打印到控制台,所以可能只是使用:

<appender name="async" class="org.apache.log4j.AsyncAppender">
<!-- this parameter need to be set to false to avoid application from hanging. -->
    <param name="Blocking" value="false" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%-5p %d{ISO8601} [%t] %c %x - %m%n" />
    </layout>
</appender>

【讨论】:

  • 已经尝试了所有的 appender 组合,仍然重复
  • @holtc:啊,很奇怪,当你将&lt;param name="Threshold" value="ERROR" /&gt; 用于“async”和“myAppender”记录器时,你得到了什么??
  • 我的东西没有记录(b/c 没有错误),但其他 3rd 方 jars 仍然记录
  • 可能你需要寻找更多的选项,你能检查你的类路径中是否有其他 log4j 配置文件,或者你可以尝试在你的&lt;root&gt; 中不使用记录器,可能是你白手起家,即没有记录,然后尝试向上移动..
  • 有一堆依赖被拉进来,所以也许有配置的东西来自那里。有什么办法可以忽略除我之外的所有配置文件?
【解决方案2】:

为什么 Log4j 记录两次?

  • Log4j 记录到层次结构中的所有记录器,除非您不要求它 到(通过将 additivity 设置为 false ),所以你看到了输出 来自您的 com.server 记录器和默认的 ROOT 记录器 永远存在。

上述问题的解决方案

  • 发生这种情况,因为您尚未定义 com.server 记录器上的 additivity="false" 属性。现在我修好了,你可以试试。

    <appender name="async" class="org.apache.log4j.AsyncAppender">
    <!-- this parameter need to be set to false to avoid application from hanging. -->
        <param name="Blocking" value="false" />
        <appender-ref ref="myAppender" />
    </appender>
    
    <appender name="myAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="INFO" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{ISO8601} [%t] %c %x - %m%n" />
        </layout>
    </appender>
    
    <logger name="com.server" additivity="false">
        <level value="INFO" />
    </logger>
    
    <logger name="org.springframework">
        <level value="INFO" />
    </logger>
    
    <logger name="org.hibernate.LazyInitializationException" additivity="false">
       <level value="off" />
       <appender-ref ref="async" />
    </logger>
    
    <logger name="net.sf.ehcache">
        <level value="INFO" />
    </logger>
    
     <logger name="com.mchange">
         <level value="INFO" />
     </logger>
    
     <root>
         <priority value="INFO" />
         <appender-ref ref="async" />
     </root>
    

【讨论】:

  • 我试过了,然后我的服务器上什么都没有记录
  • @holtc,您是否无法获取Root 的日志,正如我在回答中提到的那样。
  • 如果上面的答案不起作用,我想建议this answer
  • root appender 可以工作,如果有任何日志来自我的服务器,即使是最简单的配置形式,它们也会被复制
  • 这不会记录任何内容,因为com.server 没有附加程序。
【解决方案3】:

我的猜测是在您的应用程序的某个地方以编程方式添加了另一个附加程序,可能是这样的:

package de.scrum_master.app;

import java.io.OutputStreamWriter;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

public class Application {
    private static Logger log = Logger.getLogger(Application.class);

    public static void main(String[] args) throws InterruptedException {
        //log.setAdditivity(false);
        ConsoleAppender ca = new ConsoleAppender();
        ca.setWriter(new OutputStreamWriter(System.out));
        ca.setLayout(new PatternLayout("%-5p [%t]: %m%n"));
        log.addAppender(ca);
        log.info("Hello world");
        log.info("Bye world");
        Thread.sleep(1000);
    }
}

除了在类路径中找到的 log4j.xmllog4j.properties 文件之外,还会导致您在日志中看到的效果。


更新: 甚至可能会调用 Logger.getRootLogger().addAppender(ca) 之类的东西,从而影响根记录器,而不仅仅是一个特定的记录器。

为我使用您的配置文件会产生以下日志输出:

INFO  [main]: Hello world
INFO  [main]: Bye world
INFO  2016-09-04 13:48:25,887 [main] de.scrum_master.app.Application  - Hello world
INFO  2016-09-04 13:48:25,889 [main] de.scrum_master.app.Application  - Bye world

【讨论】:

  • 查看了代码,没有以编程方式添加附加程序
  • 然后可能是第三方工具、内部库或容器执行此操作。如果您可以使用最少的配置示例和有关容器的详细信息使问题可重现,我想有人可以帮助您。
【解决方案4】:

已经有了一些答案,所以我继续创建了一个程序来证明这确实有效,除非您的代码中有问题 - 请参阅下面我的两个简单类,并尝试找出这些与您的区别.

import org.apache.log4j.xml.DOMConfigurator;

import com.server.Test;

public class MyListener {
public static void main(String[] args) {

    DOMConfigurator.configure("/home/sanjeevd/depot/bas/projects/xxx.1/yyy/src/log4j.xml");

    Test test = new Test();
}

}

package com.server;

import org.apache.log4j.Logger;

public class Test {

private static Logger logger = Logger.getLogger(Test.class);

public Test() {
    logger.info("PRINTTTTTTTTTTTT");
}

}

还将这两行添加到 log4j.xml 的顶部 -

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

话虽如此,我很确定还有其他一些记录器正在初始化,或者您的应用程序中有多个 lo4j.xml 等。请注意,我没有更改您的 log4j.xml 中的任何内容,除了添加标题。

输出如下(它只打印一次)-

INFO  2016-09-06 10:57:37,506 [main] com.server.Test  - PRINTTTTTTTTTTTT

您应该做的另一件事是为引导调试设置“系统属性”,以查看 log4j 级别发生了什么,即放置

System.setProperty("log4j.debug", "true");

就在配置 log4j 之前。如果您将其部署到某个 servlet 容器(tomcat 等)上,请在启动期间传递 -Dlog4j.debug=true 参数。

我的输出是 -

log4j: Trying to find [log4j.xml] using context classloader   sun.misc.Launcher$AppClassLoader@42a57993.
log4j: Using URL [file:/home/sanjeevd/depot/bas/projects/xxx.1/yyy/bin/log4j.xml] for automatic log4j configuration.
log4j: Preferred configurator class: org.apache.log4j.xml.DOMConfigurator
log4j: System property is :null
log4j: Standard DocumentBuilderFactory search succeded.
log4j: DocumentBuilderFactory is: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
log4j: debug attribute= "null".
log4j: Ignoring debug attribute.
log4j: reset attribute= "false".
log4j: Threshold ="null".
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [com.server] additivity to [true].
log4j: Level value for com.server is  [INFO].
log4j: com.server level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [org.springframework] additivity to [true].
log4j: Level value for org.springframework is  [INFO].
log4j: org.springframework level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [org.hibernate.LazyInitializationException] additivity to [false].
log4j: Level value for org.hibernate.LazyInitializationException is  [off].
log4j: org.hibernate.LazyInitializationException level set to OFF
log4j: Class name: [org.apache.log4j.AsyncAppender]
log4j: Attaching appender named [myAppender] to appender named [async].
log4j: Class name: [org.apache.log4j.ConsoleAppender]
log4j: Setting property [threshold] to [INFO].
log4j: Setting property [target] to [System.out].
log4j: Parsing layout of class: "org.apache.log4j.PatternLayout"
log4j: Setting property [conversionPattern] to [%-5p %d{ISO8601} [%t] %c %x - %m%n].
log4j: Adding appender named [async] to category [org.hibernate.LazyInitializationException].
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [net.sf.ehcache] additivity to [true].
log4j: Level value for net.sf.ehcache is  [INFO].
log4j: net.sf.ehcache level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [com.mchange] additivity to [true].
log4j: Level value for com.mchange is  [INFO].
log4j: com.mchange level set to INFO
log4j: Level value for root is  [INFO].
log4j: root level set to INFO
log4j: Adding appender named [async] to category [root].
log4j: System property is :null
log4j: Standard DocumentBuilderFactory search succeded.
log4j: DocumentBuilderFactory is: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
log4j: debug attribute= "null".
log4j: Ignoring debug attribute.
log4j: reset attribute= "false".
log4j: Threshold ="null".
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [com.server] additivity to [true].
log4j: Level value for com.server is  [INFO].
log4j: com.server level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [org.springframework] additivity to [true].
log4j: Level value for org.springframework is  [INFO].
log4j: org.springframework level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [org.hibernate.LazyInitializationException] additivity to [false].
log4j: Level value for org.hibernate.LazyInitializationException is  [off].
log4j: org.hibernate.LazyInitializationException level set to OFF
log4j: Class name: [org.apache.log4j.AsyncAppender]
log4j: Attaching appender named [myAppender] to appender named [async].
log4j: Class name: [org.apache.log4j.ConsoleAppender]
log4j: Setting property [threshold] to [INFO].
log4j: Setting property [target] to [System.out].
log4j: Parsing layout of class: "org.apache.log4j.PatternLayout"
log4j: Setting property [conversionPattern] to [%-5p %d{ISO8601} [%t] %c %x - %m%n].
log4j: Adding appender named [async] to category [org.hibernate.LazyInitializationException].
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [net.sf.ehcache] additivity to [true].
log4j: Level value for net.sf.ehcache is  [INFO].
log4j: net.sf.ehcache level set to INFO
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [com.mchange] additivity to [true].
log4j: Level value for com.mchange is  [INFO].
log4j: com.mchange level set to INFO
log4j: Level value for root is  [INFO].
log4j: root level set to INFO
log4j: Adding appender named [async] to category [root].

【讨论】:

    【解决方案5】:

    我认为将 additivity="false" 添加到您的 com.server 记录器将解决问题。

        <logger name="com.server" additivity="false">
            <level value="INFO" />
        </logger>
    

    https://logging.apache.org/log4j/2.x/manual/configuration.html#Additivity

    【讨论】:

    • 我试过了,然后我的服务器上什么都没有记录
    • 这意味着该记录器没有附加程序。没有附加程序意味着没有附加到任何日志目标。
    【解决方案6】:

    问题解决了,我必须这样做:

    <logger name="com.server" additivity="false">
        <level value="INFO" />
        <appender-ref ref="async" />
    </logger>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 2018-02-23
      • 1970-01-01
      相关资源
      最近更新 更多