How to log as much information as possible for a Java Exception?

Steve Chambers picture Steve Chambers · Jan 30, 2013 · Viewed 104.4k times · Source

There's a common problem I've come across a few times when logging Exceptions. There seem to be various different types to deal with. E.g. some wrap other Exceptions, some don't have a message at all - just a type.

Most code I've seen logs Exceptions using either getMessage() or toString() but these don't always capture all the information needed to pinpoint the problem - other methods such as getCause() and getStackTrace() sometimes provide additional info.

As an example, the Exception I'm looking at right now in my Eclipse Inspect window is an InvocationTargetException. The Exception itself has no cause, no message, no stacktrace ... but the target from getCause() is InvalidUseOfMatchersException with these details populated.

So my question is: Given an Exception of any type as an input please provide a single method that will output a nicely formatted String containing all relevant information about the Exception (e.g. possibly recursively calling getCause() amongst other things?) Before posting this question I was nearly going to have a stab at this myself but don't really want to reinvent the wheel - surely such a thing must have been done many times before...?

Please don't point me at any particular logging or utility framework to do this. I'm looking for a fragment of code rather than a library since I don't have the right to add external dependencies on the project I'm working on and it's actually being logged to part of a webpage rather than a file. If it's a case of copying the code fragment out of such a framework (and attributing it) that's fine :-)

Answer

flup picture flup · Jan 30, 2013

The java.util.logging package is standard in Java SE. Its Logger includes an overloaded log method that accepts Throwable objects. It will log stacktraces of exceptions and their cause for you.

For example:

import java.util.logging.Level;
import java.util.logging.Logger;

[...]

Logger logger = Logger.getAnonymousLogger();
Exception e1 = new Exception();
Exception e2 = new Exception(e1);
logger.log(Level.SEVERE, "an exception was thrown", e2);

Will log:

SEVERE: an exception was thrown
java.lang.Exception: java.lang.Exception
    at LogStacktrace.main(LogStacktrace.java:21)
Caused by: java.lang.Exception
    at LogStacktrace.main(LogStacktrace.java:20)

Internally, this does exactly what @philipp-wendler suggests, by the way. See the source code for SimpleFormatter.java. This is just a higher level interface.