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 3To 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 nullThe 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
- Throwable.printStackTrace() — Prints the exception and the chain of calls that led to it to the error stream.
- Throwable.getMessage() — Returns the message text of an exception.