Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to get an exception's stack trace as a string

Short answer

A stack trace shows the chain of method calls that led to an error. printStackTrace() can write it into a StringWriter, from which you take it as a string:

void main() {
    try {
        Integer.parseInt("abc");
    } catch (NumberFormatException e) {
        var writer = new StringWriter();
        e.printStackTrace(new PrintWriter(writer));
 
        String trace = writer.toString();
        IO.println(trace.lines().count() > 1);
        IO.println(trace.lines().findFirst().orElseThrow());
    }
}

Output:

true
java.lang.NumberFormatException: For input string: "abc"

Where the error happened

getStackTrace() returns an array of stack elements. The last call in the chain is the first element:

void check(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("age < 0");
    }
}
 
void main() {
    try {
        check(-1);
    } catch (IllegalArgumentException e) {
        StackTraceElement top = e.getStackTrace()[0];
        IO.println(top.getMethodName() + " at line " + top.getLineNumber());
    }
}

Output:

check at line 3

To a log

Loggers take the exception as a separate argument and print the stack themselves. For example, with System.Logger:

// src/main/java/shop/OrderService.java
private static final System.Logger LOG = System.getLogger(OrderService.class.getName());
 
void save(Order order) {
    try {
        repository.save(order);
    } catch (RuntimeException e) {
        LOG.log(System.Logger.Level.ERROR, "Cannot save order " + order.id(), e);
        throw e;
    }
}

Common mistake

Logging only e.getMessage(). Many exceptions have an empty or unhelpful message, and without the stack you cannot tell where the error happened:

void main() {
    try {
        Object value = null;
        value.toString();
    } catch (NullPointerException e) {
        IO.println(e.getClass().getSimpleName() + ": " + e.getMessage());
    }
}

Output:

NullPointerException: Cannot invoke "Object.toString()" because "<local1>" is null

The message exists here, but it has neither the method name nor the line number. Pass the whole exception to the logger.

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.