diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java index 817f76c8b7c1..009311621409 100644 --- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java +++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java @@ -62,27 +62,38 @@ protected void writeThrowable(Throwable t, PrintStream stream) { } stream.println(); - while (t != null) { - for (StackTraceElement e : t.getStackTrace()) { - stream.print(" "); - stream.print(buffer().strong("at")); - stream.print(" " + e.getClassName() + "." + e.getMethodName()); - stream.print(buffer().a(" (").strong(getLocation(e)).a(")")); - stream.println(); - } + printStackTrace(t, stream, ""); + } - t = t.getCause(); - if (t != null) { - stream.print(buffer().strong("Caused by").a(": ").a(t.getClass().getName())); - if (t.getMessage() != null) { - stream.print(": "); - stream.print(buffer().failure(t.getMessage())); - } - stream.println(); - } + private void printStackTrace(Throwable t, PrintStream stream, String prefix) { + for (StackTraceElement e : t.getStackTrace()) { + stream.print(prefix); + stream.print(" "); + stream.print(buffer().strong("at")); + stream.print(" " + e.getClassName() + "." + e.getMethodName()); + stream.print(buffer().a(" (").strong(getLocation(e)).a(")")); + stream.println(); + } + for (Throwable se : t.getSuppressed()) { + writeThrowable(se, stream, "Suppressed", prefix + " "); + } + Throwable cause = t.getCause(); + if (cause != null) { + writeThrowable(cause, stream, "Caused by", prefix); } } + private void writeThrowable(Throwable t, PrintStream stream, String caption, String prefix) { + stream.print(buffer().a(prefix).strong(caption).a(": ").a(t.getClass().getName())); + if (t.getMessage() != null) { + stream.print(": "); + stream.print(buffer().failure(t.getMessage())); + } + stream.println(); + + printStackTrace(t, stream, prefix); + } + protected String getLocation(final StackTraceElement e) { assert e != null; diff --git a/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java new file mode 100644 index 000000000000..ec198efbc361 --- /dev/null +++ b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.slf4j.impl; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.Test; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.stringContainsInOrder; + +public class MavenSimpleLoggerTest { + + @Test + public void includesCauseAndSuppressedExceptionsWhenWritingThrowables() throws Exception { + Exception causeOfSuppressed = new NoSuchElementException("cause of suppressed"); + Exception suppressed = new IllegalStateException("suppressed", causeOfSuppressed); + suppressed.addSuppressed(new IllegalArgumentException( + "suppressed suppressed", new ArrayIndexOutOfBoundsException("suppressed suppressed cause"))); + Exception cause = new IllegalArgumentException("cause"); + cause.addSuppressed(suppressed); + Exception throwable = new RuntimeException("top-level", cause); + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + new MavenSimpleLogger("logger").writeThrowable(throwable, new PrintStream(output)); + + String actual = output.toString(UTF_8.name()); + + List expectedLines = Arrays.asList( + "java.lang.RuntimeException: top-level", + "Caused by: java.lang.IllegalArgumentException: cause", + " Suppressed: java.lang.IllegalStateException: suppressed", + " Suppressed: java.lang.IllegalArgumentException: suppressed suppressed", + " Caused by: java.lang.ArrayIndexOutOfBoundsException: suppressed suppressed cause", + " Caused by: java.util.NoSuchElementException: cause of suppressed"); + + assertThat(actual, stringContainsInOrder(expectedLines)); + } +}