Search code examples
javajava-8logbackslf4j

How to force java to show full stack trace


I'm trying to debug issue with an app that throws exception, and the stack trace is cut off even when I use -XX:MaxJavaStackTraceDepth=16777216 (or any other value there, like -1 or 2048).

It is cut off like this:

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

I want to see more stack trace elements instead of ... 89 more how to achieve that?

This is in Java 8 using SLF4J + Logback for logging with the following configuration:

<?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>

Solution

  • When you have an example program like this:

    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");
        }
    }
    

    It will produce:

    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
    

    Since within bar, the method invocation that led to an exception is on a different line than the construction of the wrapping secondary exception, it appears in both stack traces. The call chain of bar, i.e. main > foo, is identical and hence, omitted in the cause.

    The stack trace still is recorded in the throwable, only the printing is affected. That’s why JVM options regarding the recording do not affect this. E.g.

    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");
        }
    }
    

    will print

    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)