当包装器异常有消息时,带有Log4j的Slf4j不会打印包装异常(由...引起)

时间:2016-04-08 19:14:50

标签: java exception logging log4j slf4j

第一个例子:

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

3 个答案:

答案 0 :(得分:6)

尽可能尝试使用所有文档并进行调试,我希望这有助于它以任何方式:

  @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-DocNullPointerException Java-Doc

public RuntimeException(Throwable cause)
  

使用指定的cause和a构造一个新的运行时异常   (cause==null ? null : cause.toString())的详细信息(其中   通常包含原因的类和详细信息。这个   构造函数对于稍微多于的运行时异常非常有用   其他扔掉的包装纸。

public NullPointerException(String s)
  

使用指定的详细消息构造NullPointerException。

因此,可能会回答问题的第一部分,其中 java.lang.RuntimeException 在执行期间被new NullPointerException 引起但是{ {1}}评估为 false 打印cause==null,即 cause.toString() ,现在由于此异常本身传递的消息为 java.lang.NullPointerException

注意:您在代码中已将原因称为NullPointerException。(因此NPE计算结果为false)

案例2 cause==null

throw new RuntimeException("RTE", new NullPointerException("NPE"))
  

使用指定的详细消息构造新的运行时异常   和原因。请注意,与原因关联的详细消息不是   自动合并到此运行时异常的详细消息中。

在这种情况下,由于您的原因是{{1}的孩子,您最终会收到 public RuntimeException(String message, Throwable cause) 并收到消息 java.lang.RuntimeException 本身和父亲首先被捕获,它被执行,在这种情况下没有到达子女。

答案 1 :(得分:1)

有2个问题。

  
      
  1. 为什么在这种情况下不记录NullPointerException [throw new RuntimeException(" RTE",new NullPointerException(" NPE"));]?
  2.   

答:

实际上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次异常。这不是很好的编码。

  
      
  1. 为什么e.printStackTrace()会在两种情况下都打印两个例外?
  2.   

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()
  • 记录的数据
  • 具有初始化非null原因的可抛出的回溯 通常应包括原因的回溯。格式 这些信息取决于实施情况。为了你的清楚 理解,请看下面的回溯示例:

    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"

    这些行表示堆栈的其余部分为此跟踪 异常匹配来自底部的指定帧数 由此异常引起的异常的堆栈跟踪 ("附上"例外)。

资源链接:

  1. What printstacktrace does?
  2. SLF4J-Log4J does not appear to have disabled logging
  3. 对于SLF4J,您可以通过

    1. sysout-over-slf4j模块将所有来电重定向到System.outSystem.err到SLF4J定义的记录器,名称为完全 System.out.println(或类似)调用的限定类 是在可配置的级别制作的。
    2. idalia SLF4J Extensions允许在确定的级别进行日志记录 runtime而不是compile-time

答案 2 :(得分:0)

当我在群集模式下运行的Apache Spark应用程序中使用Slf4j Logger时,我遇到了类似的问题。我发现问题在我的情况下是由与OmitStackTraceInFastThrow相关的JVM优化引起的,基本上没有打印整个堆栈只是顶级错误而没有任何细节。

在您的情况下,这可能会隐藏NullPointerException的错误消息。尝试在启动应用程序时将此参数添加到JVM -XX:-OmitStackTraceInFastThrow,并告诉我们它是否有效。