From c66053504aecd50a7bba1dd9d1b81664d58fc28f Mon Sep 17 00:00:00 2001 From: Mikhail Mazursky Date: Sun, 22 Sep 2013 17:08:45 +0600 Subject: [PATCH] Support suppressed exceptions in throwable converter --- .../pattern/ThrowableProxyConverter.java | 51 ++++++++++++++----- .../classic/spi/ThrowableProxyUtil.java | 42 ++++++++------- .../classic/spi/ThrowableProxyTest.java | 17 +++++++ .../ch/qos/logback/core/CoreConstants.java | 2 +- 4 files changed, 79 insertions(+), 33 deletions(-) diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableProxyConverter.java b/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableProxyConverter.java index a981ebf1cc..624305a381 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableProxyConverter.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableProxyConverter.java @@ -34,6 +34,8 @@ */ public class ThrowableProxyConverter extends ThrowableHandlingConverter { + protected static final int BUILDER_CAPACITY = 2048; + int lengthOption; List> evaluatorList = null; @@ -137,18 +139,41 @@ public String convert(ILoggingEvent event) { } protected String throwableProxyToString(IThrowableProxy tp) { - StringBuilder buf = new StringBuilder(32); - IThrowableProxy currentThrowable = tp; - while (currentThrowable != null) { - subjoinThrowableProxy(buf, currentThrowable); - currentThrowable = currentThrowable.getCause(); + StringBuilder sb = new StringBuilder(BUILDER_CAPACITY); + + recursiveAppend(sb, null, ThrowableProxyUtil.REGULAR_EXCEPTION_INDENT, tp); + + return sb.toString(); + } + + private void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) { + if(tp == null) + return; + subjoinFirstLine(sb, prefix, indent, tp); + sb.append(CoreConstants.LINE_SEPARATOR); + subjoinSTEPArray(sb, indent, tp); + IThrowableProxy[] suppressed = tp.getSuppressed(); + if(suppressed != null) { + for(IThrowableProxy current : suppressed) { + recursiveAppend(sb, CoreConstants.SUPPRESSED, indent + ThrowableProxyUtil.SUPPRESSED_EXCEPTION_INDENT, current); + } } - return buf.toString(); + recursiveAppend(sb, CoreConstants.CAUSED_BY, indent, tp.getCause()); + } + + private void subjoinFirstLine(StringBuilder buf, String prefix, int indent, IThrowableProxy tp) { + ThrowableProxyUtil.indent(buf, indent - 1); + if (prefix != null) { + buf.append(prefix); + } + subjoinExceptionMessage(buf, tp); + } + + private void subjoinExceptionMessage(StringBuilder buf, IThrowableProxy tp) { + buf.append(tp.getClassName()).append(": ").append(tp.getMessage()); } - void subjoinThrowableProxy(StringBuilder buf, IThrowableProxy tp) { - ThrowableProxyUtil.subjoinFirstLine(buf, tp); - buf.append(CoreConstants.LINE_SEPARATOR); + private void subjoinSTEPArray(StringBuilder buf, int indent, IThrowableProxy tp) { StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray(); int commonFrames = tp.getCommonFrames(); @@ -161,15 +186,15 @@ void subjoinThrowableProxy(StringBuilder buf, IThrowableProxy tp) { } for (int i = 0; i < maxIndex; i++) { - String string = stepArray[i].toString(); - buf.append(CoreConstants.TAB); - buf.append(string); + ThrowableProxyUtil.indent(buf, indent); + buf.append(stepArray[i]); extraData(buf, stepArray[i]); // allow other data to be added buf.append(CoreConstants.LINE_SEPARATOR); } if (commonFrames > 0 && unrestrictedPrinting) { - buf.append("\t... ").append(tp.getCommonFrames()).append( + ThrowableProxyUtil.indent(buf, indent); + buf.append("... ").append(tp.getCommonFrames()).append( " common frames omitted").append(CoreConstants.LINE_SEPARATOR); } } diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxyUtil.java b/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxyUtil.java index 9f0d7f9656..39fac65ba2 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxyUtil.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxyUtil.java @@ -17,14 +17,15 @@ /** * Convert a throwable into an array of ThrowableDataPoint objects. - * - * + * + * * @author Ceki Gülcü */ public class ThrowableProxyUtil { public static final int REGULAR_EXCEPTION_INDENT = 1; - public static final int SUPPRESSED_EXCEPTION_INDENT = 2; + public static final int SUPPRESSED_EXCEPTION_INDENT = 1; + private static final int BUILDER_CAPACITY = 2048; public static void build(ThrowableProxy nestedTP, Throwable nestedThrowable, ThrowableProxy parentTP) { @@ -76,7 +77,7 @@ static int findNumberOfCommonFrames(StackTraceElement[] steArray, } public static String asString(IThrowableProxy tp) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(BUILDER_CAPACITY); recursiveAppend(sb, null, REGULAR_EXCEPTION_INDENT, tp); @@ -86,19 +87,26 @@ public static String asString(IThrowableProxy tp) { private static void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) { if(tp == null) return; - subjoinFirstLine(sb, prefix, tp); + subjoinFirstLine(sb, prefix, indent, tp); sb.append(CoreConstants.LINE_SEPARATOR); subjoinSTEPArray(sb, indent, tp); IThrowableProxy[] suppressed = tp.getSuppressed(); if(suppressed != null) { for(IThrowableProxy current : suppressed) { - recursiveAppend(sb, CoreConstants.SUPPRESSED, SUPPRESSED_EXCEPTION_INDENT, current); + recursiveAppend(sb, CoreConstants.SUPPRESSED, indent + SUPPRESSED_EXCEPTION_INDENT, current); } } - recursiveAppend(sb, CoreConstants.CAUSED_BY, REGULAR_EXCEPTION_INDENT, tp.getCause()); + recursiveAppend(sb, CoreConstants.CAUSED_BY, indent, tp.getCause()); + } + + public static void indent(StringBuilder buf, int indent) { + for(int j = 0; j < indent; j++) { + buf.append(CoreConstants.TAB); + } } - private static void subjoinFirstLine(StringBuilder buf, String prefix, IThrowableProxy tp) { + private static void subjoinFirstLine(StringBuilder buf, String prefix, int indent, IThrowableProxy tp) { + indent(buf, indent - 1); if (prefix != null) { buf.append(prefix); } @@ -114,13 +122,13 @@ public static void subjoinPackagingData(StringBuilder builder, StackTraceElement } else { builder.append(" ["); } - + builder.append(cpd.getCodeLocation()).append(':').append( cpd.getVersion()).append(']'); } } } - + public static void subjoinSTEP(StringBuilder sb, StackTraceElementProxy step) { sb.append(step.toString()); subjoinPackagingData(sb, step); @@ -138,7 +146,7 @@ public static void subjoinSTEPArray(StringBuilder sb, IThrowableProxy tp) { /** * @param sb The StringBuilder the STEPs are appended to. - * @param indentLevel indentation level used for the STEPs, usually either REGULAR_EXCEPTION_INDENT or SUPPRESSED_EXCEPTION_INDENT. + * @param indentLevel indentation level used for the STEPs, usually REGULAR_EXCEPTION_INDENT. * @param tp the IThrowableProxy containing the STEPs. */ public static void subjoinSTEPArray(StringBuilder sb, int indentLevel, IThrowableProxy tp) { @@ -147,21 +155,17 @@ public static void subjoinSTEPArray(StringBuilder sb, int indentLevel, IThrowabl for (int i = 0; i < stepArray.length - commonFrames; i++) { StackTraceElementProxy step = stepArray[i]; - for(int j = 0; j < indentLevel ; j++) { - sb.append(CoreConstants.TAB); - } + indent(sb, indentLevel); subjoinSTEP(sb, step); sb.append(CoreConstants.LINE_SEPARATOR); } - + if (commonFrames > 0) { - for(int j = 0; j < indentLevel ; j++) { - sb.append(CoreConstants.TAB); - } + indent(sb, indentLevel); sb.append("... ").append(commonFrames).append(" common frames omitted") .append(CoreConstants.LINE_SEPARATOR); } - + } public static void subjoinFirstLine(StringBuilder buf, IThrowableProxy tp) { diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/spi/ThrowableProxyTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/spi/ThrowableProxyTest.java index 2d0aba0ee8..e0c552d951 100644 --- a/logback-classic/src/test/java/ch/qos/logback/classic/spi/ThrowableProxyTest.java +++ b/logback-classic/src/test/java/ch/qos/logback/classic/spi/ThrowableProxyTest.java @@ -127,6 +127,23 @@ public void suppressedWithCause() throws InvocationTargetException, IllegalAcces verify(ex); } + @Test + public void suppressedWithSuppressed() throws Exception + { + assumeNotNull(ADD_SUPPRESSED_METHOD); // only execute on Java 7, would work anyway but doesn't make sense. + Exception ex = null; + try { + someMethod(); + } catch (Exception e) { + ex=new Exception("Wrapper", e); + Exception fooException = new Exception("Foo"); + Exception barException = new Exception("Bar"); + addSuppressed(barException, fooException); + addSuppressed(e, barException); + } + verify(ex); + } + // see also http://jira.qos.ch/browse/LBCLASSIC-216 @Test public void nullSTE() { diff --git a/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java b/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java index 0b426b0666..ff55691c82 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java +++ b/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java @@ -85,7 +85,7 @@ public class CoreConstants { */ public static final Class[] EMPTY_CLASS_ARRAY = new Class[]{}; public static final String CAUSED_BY = "Caused by: "; - public static final String SUPPRESSED = "\tSuppressed: "; + public static final String SUPPRESSED = "Suppressed: "; public static final String WRAPPED_BY = "Wrapped by: "; public static final char PERCENT_CHAR = '%';