【问题标题】:How to force java to show full stack trace如何强制java显示完整的堆栈跟踪
【发布时间】:2020-05-12 12:23:19
【问题描述】:

我正在尝试调试引发异常的应用程序的问题,即使我使用 -XX:MaxJavaStackTraceDepth=16777216(或其中的任何其他值,如 -12048),堆栈跟踪也会被切断。

是这样截断的:

Caused by: java.lang.IllegalStateException: unexpected message type: DefaultLastHttpContent
    at io.netty.handler.codec.http.HttpObjectEncoder.encode(HttpObjectEncoder.java:124)
    at io.netty.handler.codec.http.HttpClientCodec$Encoder.encode(HttpClientCodec.java:167)
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:89)
    ... 89 more

我想查看更多堆栈跟踪元素而不是... 89 more 如何实现?

这是在 Java 8 中使用 SLF4J + Logback 进行日志记录,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
            </Pattern>
        </layout>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

【问题讨论】:

  • 不,-XX:-OmitStackTraceInFastThrow 不会改变这一点,我认为只有当我在重复出现的异常中遇到这个问题时它才会起作用,但我在第一个抛出的异常中也看到了这一点。
  • 如何得出没有重叠堆栈帧的结论?重叠的帧是没有打印的89帧。
  • 其实这个功能直观上是可以理解的,只要你不像这个问题那样只看原因。我很确定在两个异常的堆栈跟踪中都有 are 条目 io.netty.handler.codec.MessageToMessageEncoder.write(…),因为 write 方法的调用者必须是第一个相同的条目。
  • 基本上,这意味着write在第89行调用encode,这产生了第一个异常IllegalStateException,然后write捕获了异常并在行中构造了一个新异常107,然后被抛出。通常,抛出包装异常的异常处理程序与产生第一个异常的调用位于不同的行。然后,代表该方法调用者的所有其他条目都是相同的。
  • @Michael OmitStackTraceInFastThrow 选项影响是否实际记录堆栈跟踪。正如我在回答中所解释的,这个问题是关于如何打印堆栈跟踪,而它们仍然被完全记录。

标签: java java-8 logback slf4j


【解决方案1】:

当你有这样的示例程序时:

public class ExceptionExample {
    public static void main(String[] args) {
        foo();
    }
    static void foo() {
        bar();
    }
    static void bar() {
        try { baz(); }
        catch(Exception ex) { throw new RuntimeException("secondary", ex); }
    }
    static void baz() {
        throw new RuntimeException("primary");
    }
}

它将产生:

Exception in thread "main" java.lang.RuntimeException: secondary
    at ExceptionExample.bar(ExceptionExample.java:11)
    at ExceptionExample.foo(ExceptionExample.java:7)
    at ExceptionExample.main(ExceptionExample.java:4)
Caused by: java.lang.RuntimeException: primary
    at ExceptionExample.baz(ExceptionExample.java:14)
    at ExceptionExample.bar(ExceptionExample.java:10)
    ... 2 more

由于在bar 中,导致异常的方法调用与包装辅助异常的构造位于不同的行,因此它出现在两个堆栈跟踪中。 bar 的调用链,即main > foo,是相同的,因此在原因中省略。

堆栈跟踪仍然记录在 throwable 中,仅影响打印。这就是为什么关于记录的 JVM 选项不会影响这一点。例如

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            foo();
        }
        catch(Throwable t) {
            for(; t != null; t = t.getCause()) {
                System.err.println(t);
                for(StackTraceElement e: t.getStackTrace())
                    System.err.println("\tat "+e);
            }
        }
    }
    static void foo() {
        bar();
    }
    static void bar() {
        try { baz(); }
        catch(Exception ex) { throw new RuntimeException("secondary", ex); }
    }
    static void baz() {
        throw new RuntimeException("primary");
    }
}

将打印

java.lang.RuntimeException: secondary
    at ExceptionExample.bar(ExceptionExample.java:20)
    at ExceptionExample.foo(ExceptionExample.java:16)
    at ExceptionExample.main(ExceptionExample.java:5)
java.lang.RuntimeException: primary
    at ExceptionExample.baz(ExceptionExample.java:23)
    at ExceptionExample.bar(ExceptionExample.java:19)
    at ExceptionExample.foo(ExceptionExample.java:16)
    at ExceptionExample.main(ExceptionExample.java:5)

【讨论】:

    猜你喜欢
    • 2010-09-27
    • 2011-04-15
    • 2016-10-05
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 2020-06-05
    相关资源
    最近更新 更多