使用Log4j2减少Java堆栈跟踪日志记录

使用Log4j2减少Java堆栈跟踪日志记录,java,stack-trace,Java,Stack Trace,我希望Log4j2在第一次引发异常时只输出一次完整的Java堆栈跟踪,而不是在异常向调用链上传播时重复该信息。我试图找出哪些定制Log4j2组件将实现这种最小的调用链日志策略 我正在基于PatternLayout创建一个自定义布局,不知道是否需要创建自己的PatternSelector。在我走得太远之前,我想听听那些了解Log4j2(v2.13.3)内部结构的人的建议 下面的伪代码说明了这个问题 m0() {try {m1();} catch (Exception e) {log.err

我希望Log4j2在第一次引发异常时只输出一次完整的Java堆栈跟踪,而不是在异常向调用链上传播时重复该信息。我试图找出哪些定制Log4j2组件将实现这种最小的调用链日志策略

我正在基于PatternLayout创建一个自定义布局,不知道是否需要创建自己的PatternSelector。在我走得太远之前,我想听听那些了解Log4j2(v2.13.3)内部结构的人的建议

下面的伪代码说明了这个问题

    m0() {try {m1();} catch (Exception e) {log.error("emsg0", e);} }
    m1() {try {m2();} catch (Exception e) {log.error("msg1", e); throw new Exception("emsg1", e);} }
    m2() {try {m3();} catch (Exception e) {log.error("msg2", e); throw new Exception("emsg2", e);} }
    m3() {_log.error("msg3"); throw new Exception("emsg3"); }
以下是实际代码运行时的日志记录:

14:08:47.425 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg3
14:08:47.426 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg2
java.lang.Exception: emsg3
    at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
    at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
14:08:47.431 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg1
java.lang.Exception: emsg2
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:23)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
    at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
Caused by: java.lang.Exception: emsg3
    at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
    ... 3 more
14:08:47.432 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg0
java.lang.Exception: emsg1
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:20)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
    at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
Caused by: java.lang.Exception: emsg2
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:23)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
    ... 2 more
Caused by: java.lang.Exception: emsg3
    at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
    ... 2 more
以下是我希望看到的:

14:08:47.425 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg3
14:08:47.426 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg2
java.lang.Exception: emsg3
    at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
    at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
    at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
14:08:47.431 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg1
    java.lang.Exception: emsg2
    Caused by: java.lang.Exception: emsg3
14:08:47.432 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg0
    java.lang.Exception: emsg1
    Caused by: java.lang.Exception: emsg2
    Caused by: java.lang.Exception: emsg3
感谢您的指导,
Rich

您需要创建一个自定义的ThrowablePatternConverter。但这样做可能不是个好主意。在应用程序运行很长时间(天、周或月)的现实生活中,您可能在很长一段时间内看不到异常,仅看到由异常引起的1行可能会有点令人沮丧,因为由异常引起的根通常是最有趣的。
此外,缓存异常并尝试进行匹配会使异常处理变得非常缓慢。

我认为解决此问题的最佳方法是接受njzk2的建议,记录或抛出异常,但不要同时执行这两项操作。只要代码结构合理,每个异常都会准确记录一次,Log4j2会以可接受的方式记录整个异常链。

这不是log4j的问题。在这些异常到达中心异常处理程序之前,不要捕获它们,然后将它们记录到一个位置。这在今天并不存在,但您需要创建以前异常的缓存,以将新异常与其他异常进行比较。然后这将是一个内存问题——您保留“旧”异常多长时间?您保留了多少?通常,在给定的方法中,要么记录错误,要么抛出错误,但不要同时执行这两个操作。听起来您可以在
异常上递归。因为
直到找到最后一个为止。这与Log4J无关,除非您创建自己的appender。谢谢大家的宝贵意见。Abhijit的方法是我计划采取的方法,以避免stdunbar指出的复杂性。但我认为简单而优雅的解决方案是接受njzk2的建议,记录或抛出异常,但不要两者兼而有之。在继承了25万行代码之后,我养成了两者兼而有之的习惯,这些代码通常会吞并异常,而不会留下许多事件的痕迹。这有效地实现了Nathan提倡的“记录一次”方法。再次感谢。同意,保留异常用于匹配目的可能会产生比解决问题更多的问题。我发现选择关注哪个Log4j2扩展点需要对Log4j2的内部结构有相当多的了解。