dropwizard/dropwizard — pull request #396 by nicktelford (2013-09-23 17:45:12+00:00)
Title: Log nested Exception traces in a sane order.

When an Exception is wrapped by another Exception, Java and Logback format the traces such that the root cause is the last trace output:

```
! java.lang.RuntimeException: Very general error doing something
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwOuterWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:48)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.getException(PrefixedRootCauseFirstThrowableProxyConverterTest.java:24)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.(PrefixedRootCauseFirstThrowableProxyConverterTest.java:20)
! at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

! at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: ! java.io.IOException: Fairly general error doing some IO
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwInnerWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:40)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwOuterWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:46)
!... 30 common frames omitted
Caused by: ! java.net.SocketTimeoutException: Timed-out reading from socket
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwRoot(PrefixedRootCauseFirstThrowableProxyConverterTest.java:33)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwInnerWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:38)
!... 31 common frames omitted
```

Instead, the root cause should be the first Exception, with the trace ascending up through the wrapping exceptions.

This makes identifying the root cause of a problem simpler, because it's usually described in more detail by the root cause. Also, the stack trace now ascends linearly, in one pass, without the need for any messy "N common frames omitted"; the first frame is the frame where the error occurred, and the last is the `main` entry-point to the program.

```
! java.net.SocketTimeoutException: Timed-out reading from socket
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwRoot(PrefixedRootCauseFirstThrowableProxyConverterTest.java:32)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwInnerWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:37)
! Causing: java.io.IOException: Fairly general error doing some IO
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwInnerWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:39)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwOuterWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:45)
! Causing: java.lang.RuntimeException: Very general error doing something
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.throwOuterWrapper(PrefixedRootCauseFirstThrowableProxyConverterTest.java:47)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.getException(PrefixedRootCauseFirstThrowableProxyConverterTest.java:23)
! at io.dropwizard.logging.PrefixedRootCauseFirstThrowableProxyConverterTest.(PrefixedRootCauseFirstThrowableProxyConverterTest.java:19)
! at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

! at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
```

Since Logback provides this functionality via the `%rEx` pattern (instead of `%ex` or `%xEx`), users may enable/disable this behaviour by configuring `logFormat`.