Slf4j with Log4j 在wrapper exception有消息时不打印wrapped exception (caused by)
Slf4j with Log4j does not print wrapped exception (caused by) when wrapper exception has a message
第一个例子:
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) throws Exception {
try {
throw new RuntimeException(new NullPointerException("NPE"));
} catch (RuntimeException e) {
logger.error("Error:", e);
}
}
}
输出:
Error:
java.lang.RuntimeException: java.lang.NullPointerException: NPE
at Main.main(Main.java:10)
在第二个示例中,我们只是向 RuntimeException
添加一条消息:
throw new RuntimeException("RTE", new NullPointerException("NPE"));
输出:
Error:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
为什么在这种情况下 NullPointerException
没有登录?
注意:e.printStackTrace()
在两种情况下都打印两个异常:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
Caused by: java.lang.NullPointerException: NPE
... 1 more
版本:
slf4j-api: 1.7.12
slf4j-log4j12: 1.7.12
log4j: 1.2.17
尽可能尝试使用所有文档和调试,我希望这能以任何方式提供帮助:
@param message the message object to log.
@param t the exception to log, including its stack trace.
public void error(Object message, Throwable t)
所以你的两个案例都包括代码语句抛出的 RuntimeException 的堆栈跟踪。差别不大。
案例 1 : throw new RuntimeException(new NullPointerException("NPE"));
引用自 RuntimeException Java-Doc and NullPointerException Java-Doc
public RuntimeException(Throwable cause)
Constructs a new runtime exception with the specified cause and a
detail message of (cause==null ? null : cause.toString())
(which
typically contains the class and detail message of cause). This
constructor is useful for runtime exceptions that are little more than
wrappers for other throwables.
public NullPointerException(String s)
Constructs a NullPointerException with the specified detail message.
所以这可能会回答您问题的第一部分,其中 java.lang.RuntimeException
在执行期间被抛出,这是由 引起的 new NullPointerException
但是当 cause==null
评估为 false 时打印 cause.toString()
即 java.lang.NullPointerException
和现在因为这个异常本身有一条消息传递如下 NPE
注意:您在代码中提到了 NullPointerException 的原因。(因此 cause==null
的计算结果为 false)
案例 2 : throw new RuntimeException("RTE", new NullPointerException("NPE"))
public RuntimeException(String message, Throwable cause)
Constructs a new runtime exception with the specified detail message
and cause. Note that the detail message associated with cause is not
automatically incorporated in this runtime exception's detail message.
在这种情况下,由于您的原因,您最终会收到 java.lang.RuntimeException
消息 RTE
是 RuntimeException
本身的子项,父项首先被捕获,它被执行并且在这种情况下未到达子项。
我在集群模式下的 Apache Spark 应用程序 运行 中使用 Slf4j Logger 时遇到了类似的问题。正如我发现的,在我的案例中,问题是由与 OmitStackTraceInFastThrow
相关的 JVM 优化引起的,它基本上没有打印整个堆栈,只是没有任何细节的顶级错误。
在您的情况下,这可能隐藏了来自 NullPointerException
的错误消息。尝试在启动您的应用程序时将此参数添加到 JVM -XX:-OmitStackTraceInFastThrow
并告诉我们它是否有效。
有 2 个问题。
- Why is NullPointerException not logged in this case[throw new RuntimeException("RTE", new NullPointerException("NPE"));]?
答案:
实际上 SLF4J has no impact on that case
。这是纯粹的 JVM 问题。在 JVM 中,需要在函数调用之前计算每个传递的参数。如果你按照这两个例子,你可以很容易地理解这个问题。
示例 1:
public class Main {
public static void main(String[] args) {
throw new RuntimeException(new NullPointerException("NPE"));
}
}
输出:
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException: NPE // Here, "java.lang.NullPointerException: NPE" - this portion is used as message according to RuntimeException
at Main.main(Main.java:3)
Caused by: java.lang.NullPointerException: NPE
... 1 more
这里,"java.lang.NullPointerException: NPE"
- 这部分根据 RuntimeException 用作消息,其中一个也是从另一个异常生成的 NullPointerException(String s)
示例 2:
public class Main {
public static void main(String[] args) {
throw new RuntimeException("RTE", new NullPointerException("NPE"));
}
}
输出:
Exception in thread "main" java.lang.RuntimeException: RTE // Here "RTE" is used as message
at Main.main(Main.java:3)
Caused by: java.lang.NullPointerException: NPE
... 1 more
此处"RTE"
用作消息。
在您的代码中,您使用了 3 次异常。那不是好的编码。
- Why e.printStackTrace() prints both exceptions in both cases?
e.printStackTrace()
将这个 throwable 及其回溯打印到标准错误流。它在错误输出流上打印此 Throwable 对象的堆栈跟踪,即字段 System.err
的值
因为你的输出是:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
Caused by: java.lang.NullPointerException: NPE
... 1 more
- 输出的第一行
["java.lang.RuntimeException: RTE"]
包含此 Throwable 的 toString() 方法的结果
对象。
- 剩余行表示之前用方法fillInStackTrace()
记录的数据
具有已初始化非空原因的 throwable 的回溯
通常应该包括原因的回溯。的格式
此信息取决于实施。为了您的清晰
理解,通过下面的回溯示例:
HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more
Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
"... 1"
这些行表明此堆栈跟踪的其余部分
exception 与从底部开始的指定帧数相匹配
由该异常引起的异常的堆栈跟踪
("enclosing" 异常)。
资源Link:
- What printstacktrace does?
- SLF4J-Log4J does not appear to have disabled logging
对于SLF4J
,你可以通过
- sysout-over-slf4j 模块将所有调用重定向到
System.out
和
System.err
到一个 SLF4J 定义的记录器
合格的 class 其中 System.out.println
(或类似)调用
以可配置的级别制作。
- idalia SLF4J Extensions 允许在确定的级别进行日志记录
runtime
而不是 compile-time
.
我注意到在我使用的 log4j.properties
文件中有以下行:
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
这似乎导致记录异常时省略 caused by
元素。
删除后,将记录完整的堆栈跟踪。
第一个例子:
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) throws Exception {
try {
throw new RuntimeException(new NullPointerException("NPE"));
} catch (RuntimeException e) {
logger.error("Error:", e);
}
}
}
输出:
Error:
java.lang.RuntimeException: java.lang.NullPointerException: NPE
at Main.main(Main.java:10)
在第二个示例中,我们只是向 RuntimeException
添加一条消息:
throw new RuntimeException("RTE", new NullPointerException("NPE"));
输出:
Error:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
为什么在这种情况下 NullPointerException
没有登录?
注意:e.printStackTrace()
在两种情况下都打印两个异常:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
Caused by: java.lang.NullPointerException: NPE
... 1 more
版本:
slf4j-api: 1.7.12
slf4j-log4j12: 1.7.12
log4j: 1.2.17
尽可能尝试使用所有文档和调试,我希望这能以任何方式提供帮助:
@param message the message object to log.
@param t the exception to log, including its stack trace.
public void error(Object message, Throwable t)
所以你的两个案例都包括代码语句抛出的 RuntimeException 的堆栈跟踪。差别不大。
案例 1 : throw new RuntimeException(new NullPointerException("NPE"));
引用自 RuntimeException Java-Doc and NullPointerException Java-Doc
public RuntimeException(Throwable cause)
Constructs a new runtime exception with the specified cause and a detail message of
(cause==null ? null : cause.toString())
(which typically contains the class and detail message of cause). This constructor is useful for runtime exceptions that are little more than wrappers for other throwables.
public NullPointerException(String s)
Constructs a NullPointerException with the specified detail message.
所以这可能会回答您问题的第一部分,其中 java.lang.RuntimeException
在执行期间被抛出,这是由 引起的 new NullPointerException
但是当 cause==null
评估为 false 时打印 cause.toString()
即 java.lang.NullPointerException
和现在因为这个异常本身有一条消息传递如下 NPE
注意:您在代码中提到了 NullPointerException 的原因。(因此 cause==null
的计算结果为 false)
案例 2 : throw new RuntimeException("RTE", new NullPointerException("NPE"))
public RuntimeException(String message, Throwable cause)
Constructs a new runtime exception with the specified detail message and cause. Note that the detail message associated with cause is not automatically incorporated in this runtime exception's detail message.
在这种情况下,由于您的原因,您最终会收到 java.lang.RuntimeException
消息 RTE
是 RuntimeException
本身的子项,父项首先被捕获,它被执行并且在这种情况下未到达子项。
我在集群模式下的 Apache Spark 应用程序 运行 中使用 Slf4j Logger 时遇到了类似的问题。正如我发现的,在我的案例中,问题是由与 OmitStackTraceInFastThrow
相关的 JVM 优化引起的,它基本上没有打印整个堆栈,只是没有任何细节的顶级错误。
在您的情况下,这可能隐藏了来自 NullPointerException
的错误消息。尝试在启动您的应用程序时将此参数添加到 JVM -XX:-OmitStackTraceInFastThrow
并告诉我们它是否有效。
有 2 个问题。
- Why is NullPointerException not logged in this case[throw new RuntimeException("RTE", new NullPointerException("NPE"));]?
答案:
实际上 SLF4J has no impact on that case
。这是纯粹的 JVM 问题。在 JVM 中,需要在函数调用之前计算每个传递的参数。如果你按照这两个例子,你可以很容易地理解这个问题。
示例 1:
public class Main {
public static void main(String[] args) {
throw new RuntimeException(new NullPointerException("NPE"));
}
}
输出:
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException: NPE // Here, "java.lang.NullPointerException: NPE" - this portion is used as message according to RuntimeException
at Main.main(Main.java:3)
Caused by: java.lang.NullPointerException: NPE
... 1 more
这里,"java.lang.NullPointerException: NPE"
- 这部分根据 RuntimeException 用作消息,其中一个也是从另一个异常生成的 NullPointerException(String s)
示例 2:
public class Main {
public static void main(String[] args) {
throw new RuntimeException("RTE", new NullPointerException("NPE"));
}
}
输出:
Exception in thread "main" java.lang.RuntimeException: RTE // Here "RTE" is used as message
at Main.main(Main.java:3)
Caused by: java.lang.NullPointerException: NPE
... 1 more
此处"RTE"
用作消息。
在您的代码中,您使用了 3 次异常。那不是好的编码。
- Why e.printStackTrace() prints both exceptions in both cases?
e.printStackTrace()
将这个 throwable 及其回溯打印到标准错误流。它在错误输出流上打印此 Throwable 对象的堆栈跟踪,即字段 System.err
的值
因为你的输出是:
java.lang.RuntimeException: RTE
at Main.main(Main.java:10)
Caused by: java.lang.NullPointerException: NPE
... 1 more
- 输出的第一行
["java.lang.RuntimeException: RTE"]
包含此 Throwable 的 toString() 方法的结果 对象。 - 剩余行表示之前用方法fillInStackTrace() 记录的数据
具有已初始化非空原因的 throwable 的回溯 通常应该包括原因的回溯。的格式 此信息取决于实施。为了您的清晰 理解,通过下面的回溯示例:
HighLevelException: MidLevelException: LowLevelException at Junk.a(Junk.java:13) at Junk.main(Junk.java:4) Caused by: MidLevelException: LowLevelException at Junk.c(Junk.java:23) at Junk.b(Junk.java:17) at Junk.a(Junk.java:11) ... 1 more Caused by: LowLevelException at Junk.e(Junk.java:30) at Junk.d(Junk.java:27) at Junk.c(Junk.java:21) ... 3 more
"... 1"
这些行表明此堆栈跟踪的其余部分 exception 与从底部开始的指定帧数相匹配 由该异常引起的异常的堆栈跟踪 ("enclosing" 异常)。
资源Link:
- What printstacktrace does?
- SLF4J-Log4J does not appear to have disabled logging
对于SLF4J
,你可以通过
- sysout-over-slf4j 模块将所有调用重定向到
System.out
和System.err
到一个 SLF4J 定义的记录器 合格的 class 其中System.out.println
(或类似)调用 以可配置的级别制作。 - idalia SLF4J Extensions 允许在确定的级别进行日志记录
runtime
而不是compile-time
.
我注意到在我使用的 log4j.properties
文件中有以下行:
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
这似乎导致记录异常时省略 caused by
元素。
删除后,将记录完整的堆栈跟踪。