【问题标题】:Log4j2: Logs not sent to Console where as logs to file works fineLog4j2:日志未发送到控制台,其中日志到文件工作正常
【发布时间】:2019-09-20 13:09:54
【问题描述】:

我是 log4j 的新手。我的 log4j 配置没有将日志写入控制台,因为文件的日志工作正常。尽管参考了早期的帖子,但我无法解决此问题。 我有两个附加程序——一个用于控制台,另一个用于文件。我打算将 ERROR 和 FATAL 写入文件,因此使用 level=ERROR。我打算将所有日志写入控制台,因此使用 level=TRACE 作为控制台。 我的代码只包含一个名为“parallel”的包,有一个名为 ClassA 的类,其中一个方法可以记录所有类型的日志。

如果我在 Root 标记中同时指定控制台和文件附加程序,那么我的期望就得到了满足。如果我将 File appender 移到 Root 之外并在 Logger 标签下提及它,那么只有 File appender 可以工作,而 Console appender 不能工作。是否必须将所有 appender 都放在 Root 标签下?

package parallel;
public class ClassA {
private final   Logger log = LogManager.getLogger(ClassA.class);
@Test 
public void testLogs() {
    log.info("info");
    log.debug("debug");
    log.warn("warn");
    log.error("error");
    log.fatal("fatal");
    log.trace("trace");
}

}

<Configuration status="INFO">
<Properties>
   <Property name="basePath" value="./logs" />
</Properties>
<Appenders>
  <Console name="console" target="SYSTEM_OUT">
    <PatternLayout>
     <Pattern>
     [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
     </Pattern>
    </PatternLayout>
  </Console>
  <File name="fileLogger" fileName="${basePath}/error.log">
    <PatternLayout>
    <Pattern>
     [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %msg%n
    </Pattern>
    </PatternLayout>
  </File>
</Appenders>
<Loggers>
   <Root name="parallel">
     <AppenderRef ref="console" level="trace" />
   </Root>
   <Logger name="parallel" level="warn" additivity="false">
      <AppenderRef ref="fileLogger" />
   </Logger>
</Loggers>

【问题讨论】:

  • 只是为了检查 Root 标签是否工作正常,我在 Root 标签中提到了无效的 appender ref 值。程序错误说无法找到附加程序,这意味着我对控制台附加程序的原始参考很好。不确定控制台标签有什么问题
  • 很可能您的 System.out 和/或错误流正在被重定向。
  • 不确定重定向 system.out 是什么意思。当两个 Appender 都放在根目录下时,控制台输出工作正常

标签: log4j2


【解决方案1】:

部分解决了..... 我在 Logger 标记中添加了 Additivity="true",这使得日志在控制台和文件中都打印出来。但是,错误的日志级别同时应用于控制台和文件。我的实际要求是控制台具有跟踪和文件具有错误级别。 我无法从 log4j2 官方文档中理解可加性的概念。任何能解释这个概念的人都会有很大的帮助。

【讨论】:

    【解决方案2】:

    据我了解,您的目标是完成这些项目:

    我打算将 ERROR 和 FATAL 写入文件,因此使用 level=ERROR。一世 打算将所有日志写入控制台,因此使用 level=TRACE for 控制台。

    请在最终选择您将在代码中实现的内容之前阅读完整的答案。

    可以通过如下配置您的记录器来做到这一点:

    <Loggers>
        <Root>
            <AppenderRef ref="console"/>
        </Root>
        <Logger name="parallel" level="ALL" additivity="true">
            <AppenderRef ref="fileLogger" level="ERROR"/>
        </Logger>
    </Loggers>
    

    每个记录器都会根据记录器名称和事件级别接受记录事件。例如,如果您调用log.error(...),则会生成ERROR 级别事件。如果log 是通过LogManager.getLogger(ClassA.class) 获得的,那么log4j 将在其配置中搜索名为“parallel.ClassA”的记录器。如果它没有找到这样的记录器,它将转到up the hierarchy 到一个不太具体的记录器 - “并行”。如果此记录器不存在,它将转到根记录器。

    一旦记录器被识别,log4j 必须确定事件是否被该记录器接受。这基于记录器的级别设置。由于“并行”记录器设置为ALL 级别,它将接受任何级别的事件。

    在 logger 接受一个事件后,它的 appender 也必须接受这个事件。与“并行”记录器的文件附加程序关联的级别是ERROR,因此此附加程序将只接受ERRORFATAL 级别的事件。

    由于“并行”记录器的可加性为true,因此每当它接受一个事件时,它也会将该事件传递给appenders of all of its parent loggers(除非其中一个通过指定可加性false 来破坏链 - 请参阅log4j2 architecture page详情)。因此,“并行”接受的任何事件都将转到与根记录器关联的控制台附加程序。

    这种方法存在一个问题,如果日志事件到达根记录器的级别为 ERROR 或 FATAL,则它不会被写入您的日志文件。日志会“泄漏”到控制台。如果您不小心编写了一些错误的代码,或者您在添加一些新代码后不小心忘记更新配置文件,就会发生这种情况。

    这里有一些示例代码来说明问题:

    package parallel;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class ClassA {
        private static final Logger log = LogManager.getLogger(ClassA.class);
    
        public static void main(String[] args) {
            log.info("info");
            log.debug("debug");
            log.warn("warn");
            log.error("error");
            log.fatal("fatal");
            log.trace("trace");
    
            // See the mistake here? 
            // The wrong logger name was used in the code, 
            // now the error event goes to the root logger!
            final Logger log2 = LogManager.getLogger("foo");
            log2.error("Woops an error!");
        }
    }
    

    上面使用答案开头的配置的控制台输出是:

    [INFO ] 2019-05-05 12:48:31.410 [main] ClassA - info
    [DEBUG] 2019-05-05 12:48:31.411 [main] ClassA - debug
    [WARN ] 2019-05-05 12:48:31.411 [main] ClassA - warn
    [ERROR] 2019-05-05 12:48:31.411 [main] ClassA - error
    [FATAL] 2019-05-05 12:48:31.412 [main] ClassA - fatal
    [TRACE] 2019-05-05 12:48:31.412 [main] ClassA - trace
    [ERROR] 2019-05-05 12:48:31.413 [main] foo - Woops an error!
    

    错误日志文件只显示:

    [ERROR] 2019-05-05 12:48:31 [main] ClassA - error
    [FATAL] 2019-05-05 12:48:31 [main] ClassA - fatal
    

    最简单的解决方法是将所有附加程序移动到根记录器,如下所示:

    <Loggers>
        <Root level="ALL">
            <AppenderRef ref="console"/>
            <AppenderRef ref="fileLogger" level="ERROR"/>
        </Root>
    </Loggers>
    

    现在根记录器和控制台附加程序接受所有事件,但文件附加程序只接受错误和致命事件。现在即使使用不正确的代码,日志事件也会转到正确的位置。

    控制台输出:

    [INFO ] 2019-05-05 12:59:32.419 [main] ClassA - info
    [DEBUG] 2019-05-05 12:59:32.421 [main] ClassA - debug
    [WARN ] 2019-05-05 12:59:32.421 [main] ClassA - warn
    [ERROR] 2019-05-05 12:59:32.421 [main] ClassA - error
    [FATAL] 2019-05-05 12:59:32.421 [main] ClassA - fatal
    [TRACE] 2019-05-05 12:59:32.421 [main] ClassA - trace
    [ERROR] 2019-05-05 12:59:32.422 [main] foo - Woops an error!
    

    错误日志文件:

    [ERROR] 2019-05-05 12:59:32 [main] ClassA - error
    [FATAL] 2019-05-05 12:59:32 [main] ClassA - fatal
    [ERROR] 2019-05-05 12:59:32 [main] foo - Woops an error!
    

    其他可能有用的链接:

    https://stackoverflow.com/a/51567436/3284624

    希望对你有帮助!

    【讨论】:

    • 很好的解释。现在我明白了逻辑。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2016-07-12
    • 2016-10-24
    相关资源
    最近更新 更多