From 7d7c55955b239d6b338a57bb3ccc7aa6c1e82bf3 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 26 Jun 2024 00:05:51 +0900 Subject: [PATCH 01/72] fix: LOG4J2-3627 and gh issue 1729 --- .../core/impl/ThrowableProxyRendererTest.java | 3 +- .../log4j/core/impl/ThrowableProxy.java | 41 ++++++-- .../core/impl/ThrowableProxyRenderer.java | 40 ++++++-- .../ExtendedThrowablePatternConverter.java | 3 +- .../RootThrowablePatternConverter.java | 25 ++--- .../pattern/ThrowablePatternConverter.java | 97 ++++++++++++++++--- 6 files changed, 156 insertions(+), 53 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java index faa5ef9c869..b0e3b03b49a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java @@ -33,6 +33,7 @@ public void test_formatExtendedStackTraceTo() { new ArrayList<>(), new PlainTextRenderer(), "", - System.lineSeparator()); + System.lineSeparator(), + null); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 8685294a54f..e689204cb58 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -255,7 +255,7 @@ public ThrowableProxy getCauseProxy() { * @param suffix Append this to the end of each stack frame. */ public String getCauseStackTraceAsString(final String suffix) { - return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR); + return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR, null); } /** @@ -266,7 +266,7 @@ public String getCauseStackTraceAsString(final String suffix) { * @return The formatted Throwable that caused this Throwable. */ public String getCauseStackTraceAsString(final List packages, final String suffix) { - return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR); + return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR, null); } /** @@ -279,7 +279,7 @@ public String getCauseStackTraceAsString(final List packages, final Stri */ public String getCauseStackTraceAsString( final List ignorePackages, final TextRenderer textRenderer, final String suffix) { - return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR); + return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR, null); } /** @@ -295,12 +295,35 @@ public String getCauseStackTraceAsString( final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator) { + final String lineSeparator, + final Integer linesToKeep) { final StringBuilder sb = new StringBuilder(); - ThrowableProxyRenderer.formatCauseStackTrace(this, sb, ignorePackages, textRenderer, suffix, lineSeparator); + ThrowableProxyRenderer.formatCauseStackTraceTo( + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); return sb.toString(); } + /** + * Formats the stack trace with cause exception. + * + * @param sb Destination. + * @param ignorePackages List of packages to be ignored in the trace. + * @param textRenderer The message renderer. + * @param suffix Append this to the end of each stack frame. + * @param lineSeparator The end-of-line separator. + * @param linesToKeep The total line count of final result + */ + public void formatCauseStackTraceTo( + final StringBuilder sb, + final List ignorePackages, + final TextRenderer textRenderer, + final String suffix, + final String lineSeparator, + final Integer linesToKeep) { + ThrowableProxyRenderer.formatCauseStackTraceTo( + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); + } + /** * Returns the number of elements that are being omitted because they are common with the parent Throwable's stack * trace. @@ -389,7 +412,7 @@ public String getExtendedStackTraceAsString( final String suffix, final String lineSeparator) { final StringBuilder sb = new StringBuilder(1024); - formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator); + formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator, null); return sb.toString(); } @@ -401,15 +424,17 @@ public String getExtendedStackTraceAsString( * @param textRenderer The message renderer. * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. + * @param linesToKeep The total line count of final result */ public void formatExtendedStackTraceTo( final StringBuilder sb, final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator) { + final String lineSeparator, + final Integer linesToKeep) { ThrowableProxyRenderer.formatExtendedStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); } public String getLocalizedMessage() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index 79994753dc9..4efb5ea3229 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -240,10 +240,9 @@ static void formatExtendedStackTraceTo( final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator) { - textRenderer.render(src.getName(), sb, "Name"); - textRenderer.render(": ", sb, "NameMessageSeparator"); - textRenderer.render(src.getMessage(), sb, "Message"); + final String lineSeparator, + final Integer linesToKeep) { + renderOn(src, sb, textRenderer); renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); final StackTraceElement[] causedTrace = @@ -260,6 +259,7 @@ static void formatExtendedStackTraceTo( lineSeparator); formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator); formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator); + truncateLines(sb, lineSeparator, linesToKeep, textRenderer); } /** @@ -272,23 +272,24 @@ static void formatExtendedStackTraceTo( * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. */ - static void formatCauseStackTrace( + static void formatCauseStackTraceTo( final ThrowableProxy src, final StringBuilder sb, final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator) { + final String lineSeparator, + final Integer linesToKeep) { final ThrowableProxy causeProxy = src.getCauseProxy(); if (causeProxy != null) { formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator); sb.append(WRAPPED_BY_LABEL); - ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer); + renderSuffix(suffix, sb, textRenderer); } renderOn(src, sb, textRenderer); - ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer); + renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); - ThrowableProxyRenderer.formatElements( + formatElements( sb, Strings.EMPTY, 0, @@ -298,6 +299,7 @@ static void formatCauseStackTrace( textRenderer, suffix, lineSeparator); + truncateLines(sb, lineSeparator, linesToKeep, textRenderer); } private static void renderOn( @@ -309,4 +311,24 @@ private static void renderOn( textRenderer.render(msg, output, "Message"); } } + + private static void truncateLines( + StringBuilder sb, String lineSeparator, Integer linesToKeep, TextRenderer textRenderer) { + if (linesToKeep == null) { + return; + } + + String content = sb.toString(); + String[] lines = content.split(lineSeparator); + + if (lines.length <= linesToKeep) { + return; + } + + sb.setLength(0); + for (int i = 0; i < linesToKeep; i++) { + sb.append(lines[i]); + textRenderer.render(lineSeparator, sb, "Text"); + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index 12e362e8d15..3d12255ebcf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -76,7 +76,8 @@ public void format(final LogEvent event, final StringBuilder toAppendTo) { options.getIgnorePackages(), options.getTextRenderer(), getSuffix(event), - options.getSeparator()); + options.getSeparator(), + options.allLines() ? null : options.getLines()); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index a068c3d7601..0088f1a0887 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -20,7 +20,6 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.impl.ThrowableProxy; -import org.apache.logging.log4j.util.Strings; /** * Outputs the Throwable portion of the LoggingEvent as a full stack trace @@ -68,27 +67,17 @@ public void format(final LogEvent event, final StringBuilder toAppendTo) { super.format(event, toAppendTo); return; } - final String trace = proxy.getCauseStackTraceAsString( - options.getIgnorePackages(), options.getTextRenderer(), getSuffix(event), options.getSeparator()); final int len = toAppendTo.length(); if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { toAppendTo.append(' '); } - if (!options.allLines() || !Strings.LINE_SEPARATOR.equals(options.getSeparator())) { - final StringBuilder sb = new StringBuilder(); - final String[] array = trace.split(Strings.LINE_SEPARATOR); - final int limit = options.minLines(array.length) - 1; - for (int i = 0; i <= limit; ++i) { - sb.append(array[i]); - if (i < limit) { - sb.append(options.getSeparator()); - } - } - toAppendTo.append(sb.toString()); - - } else { - toAppendTo.append(trace); - } + proxy.formatCauseStackTraceTo( + toAppendTo, + options.getIgnorePackages(), + options.getTextRenderer(), + getSuffix(event), + options.getSeparator(), + options.allLines() ? null : options.getLines()); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index d2086cbc212..2489224b870 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -18,7 +18,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.PrintWriter; -import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -188,23 +187,24 @@ private void formatOption(final Throwable throwable, final String suffix, final if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { buffer.append(' '); } - if (!options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix)) { - final StringWriter w = new StringWriter(); - throwable.printStackTrace(new PrintWriter(w)); - - final String[] array = w.toString().split(Strings.LINE_SEPARATOR); - final int limit = options.minLines(array.length) - 1; - final boolean suffixNotBlank = Strings.isNotBlank(suffix); - for (int i = 0; i <= limit; ++i) { - buffer.append(array[i]); - if (suffixNotBlank) { - buffer.append(' '); - buffer.append(suffix); - } - if (i < limit) { - buffer.append(options.getSeparator()); + if (requireAdditionalFormatting(suffix)) { + StackTraceElement[] stackTrace = throwable.getStackTrace(); + int ignoredCount = 0; + for (StackTraceElement stackTraceElement : stackTrace) { + if (!ignoreElement(stackTraceElement, options.getIgnorePackages())) { + if (ignoredCount > 0) { + appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); + ignoredCount = 0; + } + appendEntry(stackTraceElement, buffer, suffix, options.getSeparator()); + } else { + ++ignoredCount; } } + if (ignoredCount > 0) { + appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); + } + truncateLines(buffer, options.getSeparator(), options.allLines() ? null : options.getLines()); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -235,4 +235,69 @@ protected String getSuffix(final LogEvent event) { public ThrowableFormatOptions getOptions() { return options; } + + private boolean requireAdditionalFormatting(String suffix) { + return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); + } + + private boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { + if (ignorePackages != null) { + final String className = element.getClassName(); + for (final String pkg : ignorePackages) { + if (className.startsWith(pkg)) { + return true; + } + } + } + return false; + } + + private void appendSuppressedCount( + final StringBuilder sb, final int count, final String suffix, final String lineSeparator) { + if (count == 1) { + sb.append("\t... "); + } else { + sb.append("\t... suppressed "); + sb.append(count); + sb.append(" lines"); + } + appendSuffix(sb, suffix); + sb.append(lineSeparator); + } + + private void appendEntry( + final StackTraceElement stackTraceElement, + final StringBuilder sb, + final String suffix, + final String lineSeparator) { + sb.append(stackTraceElement.toString()); + appendSuffix(sb, suffix); + sb.append(lineSeparator); + } + + private void appendSuffix(StringBuilder buffer, String suffix) { + if (Strings.isNotBlank(suffix)) { + buffer.append(' '); + buffer.append(suffix); + } + } + + private void truncateLines(StringBuilder sb, String lineSeparator, Integer linesToKeep) { + if (linesToKeep == null) { + return; + } + + String content = sb.toString(); + String[] lines = content.split(lineSeparator); + + if (lines.length <= linesToKeep) { + return; + } + + sb.setLength(0); + for (int i = 0; i < linesToKeep; i++) { + sb.append(lines[i]); + sb.append(lineSeparator); + } + } } From 9f8af82e6919d68b6755033795dafab47a6d1131 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 26 Jun 2024 20:18:35 +0900 Subject: [PATCH 02/72] update naming and add final --- .../log4j/core/impl/ThrowableProxy.java | 23 +++++++++---------- .../core/impl/ThrowableProxyRenderer.java | 19 ++++++++------- .../pattern/ThrowablePatternConverter.java | 15 ++++++++---- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index e689204cb58..6c9b4bd8e10 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -255,7 +255,7 @@ public ThrowableProxy getCauseProxy() { * @param suffix Append this to the end of each stack frame. */ public String getCauseStackTraceAsString(final String suffix) { - return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR, null); + return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR); } /** @@ -266,7 +266,7 @@ public String getCauseStackTraceAsString(final String suffix) { * @return The formatted Throwable that caused this Throwable. */ public String getCauseStackTraceAsString(final List packages, final String suffix) { - return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR, null); + return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR); } /** @@ -279,7 +279,7 @@ public String getCauseStackTraceAsString(final List packages, final Stri */ public String getCauseStackTraceAsString( final List ignorePackages, final TextRenderer textRenderer, final String suffix) { - return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR, null); + return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR); } /** @@ -295,11 +295,10 @@ public String getCauseStackTraceAsString( final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator, - final Integer linesToKeep) { + final String lineSeparator) { final StringBuilder sb = new StringBuilder(); ThrowableProxyRenderer.formatCauseStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, null); return sb.toString(); } @@ -311,7 +310,7 @@ public String getCauseStackTraceAsString( * @param textRenderer The message renderer. * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. - * @param linesToKeep The total line count of final result + * @param maxLineCount The total line count of final result */ public void formatCauseStackTraceTo( final StringBuilder sb, @@ -319,9 +318,9 @@ public void formatCauseStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer linesToKeep) { + final Integer maxLineCount) { ThrowableProxyRenderer.formatCauseStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); } /** @@ -424,7 +423,7 @@ public String getExtendedStackTraceAsString( * @param textRenderer The message renderer. * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. - * @param linesToKeep The total line count of final result + * @param maxLineCount The total line count of final result */ public void formatExtendedStackTraceTo( final StringBuilder sb, @@ -432,9 +431,9 @@ public void formatExtendedStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer linesToKeep) { + final Integer maxLineCount) { ThrowableProxyRenderer.formatExtendedStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); } public String getLocalizedMessage() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index 4efb5ea3229..46f554cb02d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -241,7 +241,7 @@ static void formatExtendedStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer linesToKeep) { + final Integer maxLineCount) { renderOn(src, sb, textRenderer); renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); @@ -259,7 +259,7 @@ static void formatExtendedStackTraceTo( lineSeparator); formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator); formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator); - truncateLines(sb, lineSeparator, linesToKeep, textRenderer); + truncateLines(sb, lineSeparator, maxLineCount, textRenderer); } /** @@ -279,7 +279,7 @@ static void formatCauseStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer linesToKeep) { + final Integer maxLineCount) { final ThrowableProxy causeProxy = src.getCauseProxy(); if (causeProxy != null) { formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator); @@ -299,7 +299,7 @@ static void formatCauseStackTraceTo( textRenderer, suffix, lineSeparator); - truncateLines(sb, lineSeparator, linesToKeep, textRenderer); + truncateLines(sb, lineSeparator, maxLineCount, textRenderer); } private static void renderOn( @@ -313,20 +313,23 @@ private static void renderOn( } private static void truncateLines( - StringBuilder sb, String lineSeparator, Integer linesToKeep, TextRenderer textRenderer) { - if (linesToKeep == null) { + final StringBuilder sb, + final String lineSeparator, + final Integer maxLineCount, + final TextRenderer textRenderer) { + if (maxLineCount == null) { return; } String content = sb.toString(); String[] lines = content.split(lineSeparator); - if (lines.length <= linesToKeep) { + if (lines.length <= maxLineCount) { return; } sb.setLength(0); - for (int i = 0; i < linesToKeep; i++) { + for (int i = 0; i < maxLineCount; i++) { sb.append(lines[i]); textRenderer.render(lineSeparator, sb, "Text"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 2489224b870..9560765ed4b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -275,27 +275,32 @@ private void appendEntry( sb.append(lineSeparator); } - private void appendSuffix(StringBuilder buffer, String suffix) { + private void appendSuffix( + final StringBuilder buffer, + final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); buffer.append(suffix); } } - private void truncateLines(StringBuilder sb, String lineSeparator, Integer linesToKeep) { - if (linesToKeep == null) { + private void truncateLines( + final StringBuilder sb, + final String lineSeparator, + final Integer maxLineCount) { + if (maxLineCount == null) { return; } String content = sb.toString(); String[] lines = content.split(lineSeparator); - if (lines.length <= linesToKeep) { + if (lines.length <= maxLineCount) { return; } sb.setLength(0); - for (int i = 0; i < linesToKeep; i++) { + for (int i = 0; i < maxLineCount; i++) { sb.append(lines[i]); sb.append(lineSeparator); } From dbefb4f4ee1b392dd323dea38cf009d6bf00ec3a Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 26 Jun 2024 20:37:22 +0900 Subject: [PATCH 03/72] add final --- .../log4j/core/pattern/ThrowablePatternConverter.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 9560765ed4b..ff43f84c52a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -236,7 +236,7 @@ public ThrowableFormatOptions getOptions() { return options; } - private boolean requireAdditionalFormatting(String suffix) { + private boolean requireAdditionalFormatting(final String suffix) { return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); } @@ -275,19 +275,14 @@ private void appendEntry( sb.append(lineSeparator); } - private void appendSuffix( - final StringBuilder buffer, - final String suffix) { + private void appendSuffix(final StringBuilder buffer, final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); buffer.append(suffix); } } - private void truncateLines( - final StringBuilder sb, - final String lineSeparator, - final Integer maxLineCount) { + private void truncateLines(final StringBuilder sb, final String lineSeparator, final Integer maxLineCount) { if (maxLineCount == null) { return; } From 66212e035f295b05e9c761f065b430a9357ae8df Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 26 Jun 2024 20:57:15 +0900 Subject: [PATCH 04/72] update core version to 3.0.0 --- .../main/java/org/apache/logging/log4j/core/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java index 266256b4637..d0ff7b8cab5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java @@ -18,7 +18,7 @@ * Implementation of Log4j 2. */ @Export -@Version("2.24.0") +@Version("3.0.0") package org.apache.logging.log4j.core; import org.osgi.annotation.bundle.Export; From de8316385eb2432770d30833655264087df814bc Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 26 Jun 2024 22:15:05 +0900 Subject: [PATCH 05/72] update as per comment --- .../log4j/core/impl/ThrowableProxy.java | 21 +++++++++++++++++++ .../logging/log4j/core/package-info.java | 2 +- .../pattern/ThrowablePatternConverter.java | 4 ++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 6c9b4bd8e10..e27d64a6839 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -415,6 +415,27 @@ public String getExtendedStackTraceAsString( return sb.toString(); } + /** + * Formats the stack trace including packaging information. + * + * @param sb Destination. + * @param ignorePackages List of packages to be ignored in the trace. + * @param textRenderer The message renderer. + * @param suffix Append this to the end of each stack frame. + * @param lineSeparator The end-of-line separator. + * @deprecated since 2.24.0. Use {@link #formatExtendedStackTraceTo(StringBuilder, List, TextRenderer, String, String, Integer)}. + */ + @Deprecated + public void formatExtendedStackTraceTo( + final StringBuilder sb, + final List ignorePackages, + final TextRenderer textRenderer, + final String suffix, + final String lineSeparator) { + ThrowableProxyRenderer.formatExtendedStackTraceTo( + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, null); + } + /** * Formats the stack trace including packaging information. * diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java index d0ff7b8cab5..171f9c7e78d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java @@ -18,7 +18,7 @@ * Implementation of Log4j 2. */ @Export -@Version("3.0.0") +@Version("2.25.0") package org.apache.logging.log4j.core; import org.osgi.annotation.bundle.Export; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index ff43f84c52a..231f9b67bb9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -188,9 +188,9 @@ private void formatOption(final Throwable throwable, final String suffix, final buffer.append(' '); } if (requireAdditionalFormatting(suffix)) { - StackTraceElement[] stackTrace = throwable.getStackTrace(); + final StackTraceElement[] stackTrace = throwable.getStackTrace(); int ignoredCount = 0; - for (StackTraceElement stackTraceElement : stackTrace) { + for (final StackTraceElement stackTraceElement : stackTrace) { if (!ignoreElement(stackTraceElement, options.getIgnorePackages())) { if (ignoredCount > 0) { appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); From 38cd7fe82b04948dbb133be36973a0b08f7f6c50 Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 27 Jun 2024 08:04:06 +0900 Subject: [PATCH 06/72] add StringBuilders --- .../core/impl/ThrowableProxyRendererTest.java | 2 +- .../log4j/core/util/StringBuildersTest.java | 47 +++++++++++++++ .../log4j/core/impl/ThrowableProxy.java | 4 +- .../core/impl/ThrowableProxyRenderer.java | 28 +-------- .../pattern/ThrowablePatternConverter.java | 22 +------ .../core/util/internal/StringBuilders.java | 57 +++++++++++++++++++ .../logging/log4j/core/util/package-info.java | 2 +- 7 files changed, 113 insertions(+), 49 deletions(-) create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java index b0e3b03b49a..397d9a4d57d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java @@ -34,6 +34,6 @@ public void test_formatExtendedStackTraceTo() { new PlainTextRenderer(), "", System.lineSeparator(), - null); + Integer.MAX_VALUE); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java new file mode 100644 index 00000000000..0380110a4b9 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java @@ -0,0 +1,47 @@ +/* + * 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.apache.logging.log4j.core.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; +import org.apache.logging.log4j.core.util.internal.StringBuilders; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class StringBuildersTest { + + static Stream testTruncateLines_dataSource() { + return Stream.of( + Arguments.of("abc | def | ghi | jkl | ", " | ", 2, "abc | def | "), + Arguments.of("abc\ndef\nghi\njkl\n", "\n", 2, "abc\ndef\n"), + Arguments.of("abc | def | ghi | jkl | ", " | ", 4, "abc | def | ghi | jkl | "), + Arguments.of("abc | def | ghi | jkl | ", " | ", null, "abc | def | ghi | jkl | "), + Arguments.of("abc | def | ghi | jkl | ", " | ", Integer.MAX_VALUE, "abc | def | ghi | jkl | "), + Arguments.of("abc | def | ghi | jkl | ", " | ", 10, "abc | def | ghi | jkl | "), + Arguments.of("abc | def | ghi | jkl | ", "", 2, "abc | def | ghi | jkl | ")); + } + + @ParameterizedTest + @MethodSource("testTruncateLines_dataSource") + public void testTruncateLines(String original, String lineSeparator, Integer maxLine, String expected) { + final StringBuilder sb = new StringBuilder(original); + StringBuilders.truncateLines(sb, lineSeparator, maxLine); + assertEquals(expected, sb.toString()); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index e27d64a6839..872907807a0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -298,7 +298,7 @@ public String getCauseStackTraceAsString( final String lineSeparator) { final StringBuilder sb = new StringBuilder(); ThrowableProxyRenderer.formatCauseStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, null); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); return sb.toString(); } @@ -433,7 +433,7 @@ public void formatExtendedStackTraceTo( final String suffix, final String lineSeparator) { ThrowableProxyRenderer.formatExtendedStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, null); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); } /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index 46f554cb02d..1e6eb031c80 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -18,6 +18,7 @@ import java.util.List; import org.apache.logging.log4j.core.pattern.TextRenderer; +import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; /** @@ -259,7 +260,7 @@ static void formatExtendedStackTraceTo( lineSeparator); formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator); formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator); - truncateLines(sb, lineSeparator, maxLineCount, textRenderer); + StringBuilders.truncateLines(sb, lineSeparator, maxLineCount); } /** @@ -299,7 +300,7 @@ static void formatCauseStackTraceTo( textRenderer, suffix, lineSeparator); - truncateLines(sb, lineSeparator, maxLineCount, textRenderer); + StringBuilders.truncateLines(sb, lineSeparator, maxLineCount); } private static void renderOn( @@ -311,27 +312,4 @@ private static void renderOn( textRenderer.render(msg, output, "Message"); } } - - private static void truncateLines( - final StringBuilder sb, - final String lineSeparator, - final Integer maxLineCount, - final TextRenderer textRenderer) { - if (maxLineCount == null) { - return; - } - - String content = sb.toString(); - String[] lines = content.split(lineSeparator); - - if (lines.length <= maxLineCount) { - return; - } - - sb.setLength(0); - for (int i = 0; i < maxLineCount; i++) { - sb.append(lines[i]); - textRenderer.render(lineSeparator, sb, "Text"); - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 231f9b67bb9..55c43d4e812 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.StringBuilderWriter; +import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; /** @@ -204,7 +205,7 @@ private void formatOption(final Throwable throwable, final String suffix, final if (ignoredCount > 0) { appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); } - truncateLines(buffer, options.getSeparator(), options.allLines() ? null : options.getLines()); + StringBuilders.truncateLines(buffer, options.getSeparator(), options.getLines()); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -281,23 +282,4 @@ private void appendSuffix(final StringBuilder buffer, final String suffix) { buffer.append(suffix); } } - - private void truncateLines(final StringBuilder sb, final String lineSeparator, final Integer maxLineCount) { - if (maxLineCount == null) { - return; - } - - String content = sb.toString(); - String[] lines = content.split(lineSeparator); - - if (lines.length <= maxLineCount) { - return; - } - - sb.setLength(0); - for (int i = 0; i < maxLineCount; i++) { - sb.append(lines[i]); - sb.append(lineSeparator); - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java new file mode 100644 index 00000000000..01b3d8d84d6 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java @@ -0,0 +1,57 @@ +/* + * 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.apache.logging.log4j.core.util.internal; + +/** + * StringBuilder helpers + */ +public class StringBuilders { + + /** + * Truncates the content of the given {@code StringBuilder} to the specified maximum number of lines. + * + *

If {@code maxLineCount} is {@code null}, {@link Integer#MAX_VALUE}, or if {@code lineSeparator} is empty, + * the method returns without making any changes to the {@code StringBuilder}. + * + * @param buffer the {@code StringBuilder} whose content is to be truncated + * @param lineSeparator the line separator used to determine the end of a line + * @param maxLineCount the maximum number of lines to retain in the {@code StringBuilder}; + * if this value is {@code null} or {@link Integer#MAX_VALUE}, no truncation will occur + */ + public static void truncateLines( + final StringBuilder buffer, final String lineSeparator, final Integer maxLineCount) { + if (buffer == null + || maxLineCount == null + || maxLineCount == Integer.MAX_VALUE + || lineSeparator == null + || lineSeparator.isEmpty()) { + return; + } + final int lineSeparatorLen = lineSeparator.length(); + int offset = 0; + int currentLineCount = 0; + while (currentLineCount < maxLineCount) { + int lineSeparatorIndex = buffer.indexOf(lineSeparator, offset); + if (lineSeparatorIndex == -1) { + break; + } + currentLineCount++; + offset = lineSeparatorIndex + lineSeparatorLen; + } + buffer.setLength(offset); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java index 6c602546054..932e8bc0800 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java @@ -18,7 +18,7 @@ * Log4j 2 helper classes. */ @Export -@Version("2.24.0") +@Version("2.25.0") package org.apache.logging.log4j.core.util; import org.osgi.annotation.bundle.Export; From 26dbdff5e5a02d7199a211b4116900bf4bcca848 Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 27 Jun 2024 08:06:50 +0900 Subject: [PATCH 07/72] update --- .../java/org/apache/logging/log4j/core/impl/ThrowableProxy.java | 2 +- .../log4j/core/pattern/ExtendedThrowablePatternConverter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 872907807a0..039e08ca4d2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -411,7 +411,7 @@ public String getExtendedStackTraceAsString( final String suffix, final String lineSeparator) { final StringBuilder sb = new StringBuilder(1024); - formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator, null); + formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); return sb.toString(); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index 3d12255ebcf..6c2944e123f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -77,7 +77,7 @@ public void format(final LogEvent event, final StringBuilder toAppendTo) { options.getTextRenderer(), getSuffix(event), options.getSeparator(), - options.allLines() ? null : options.getLines()); + options.getLines()); } } } From 8d3f7e42fdc9479cdd63eeb634b38bafb1a62944 Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 27 Jun 2024 09:08:31 +0900 Subject: [PATCH 08/72] add tests --- .../pattern/ExtendedThrowableFilterTest.java | 52 ++++++++++++++++ .../core/pattern/ExtendedThrowableTest.java | 6 +- .../ExtendedThrowableTruncateTest.java | 55 ++++++++++++++++ .../core/pattern/RootThrowableFilterTest.java | 46 ++++++++++++++ .../log4j/core/pattern/RootThrowableTest.java | 6 +- .../pattern/RootThrowableTruncateTest.java | 49 +++++++++++++++ .../core/pattern/ThrowableFilterTest.java | 56 +++++++++++++++++ .../log4j/core/pattern/ThrowableTest.java | 2 +- .../core/pattern/ThrowableTruncateTest.java | 62 +++++++++++++++++++ ....xml => log4j-extend-throwable-filter.xml} | 0 .../log4j-extend-throwable-truncate.xml | 39 ++++++++++++ .../test/resources/log4j-extend-throwable.xml | 39 ++++++++++++ ...er.xml => log4j-root-throwable-filter.xml} | 0 .../log4j-root-throwable-truncate.xml | 39 ++++++++++++ .../test/resources/log4j-root-throwable.xml | 39 ++++++++++++ .../test/resources/log4j-throwable-filter.xml | 39 ++++++++++++ .../resources/log4j-throwable-truncate.xml | 39 ++++++++++++ 17 files changed, 561 insertions(+), 7 deletions(-) create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java rename log4j-core-test/src/test/resources/{log4j-throwablefilter.xml => log4j-extend-throwable-filter.xml} (100%) create mode 100644 log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml create mode 100644 log4j-core-test/src/test/resources/log4j-extend-throwable.xml rename log4j-core-test/src/test/resources/{log4j-rootthrowablefilter.xml => log4j-root-throwable-filter.xml} (100%) create mode 100644 log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml create mode 100644 log4j-core-test/src/test/resources/log4j-root-throwable.xml create mode 100644 log4j-core-test/src/test/resources/log4j-throwable-filter.xml create mode 100644 log4j-core-test/src/test/resources/log4j-throwable-truncate.xml diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java new file mode 100644 index 00000000000..5b58e4b9bc7 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java @@ -0,0 +1,52 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@LoggerContextSource("log4j-extend-throwable-filter.xml") +public class ExtendedThrowableFilterTest { + private ListAppender app; + + @BeforeEach + public void setUp(@Named("List") final ListAppender app) throws Exception { + this.app = app.clear(); + } + + @Test + public void testException(final LoggerContext context) { + final Logger logger = context.getLogger("LoggerTest"); + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java index 639837c8042..39afe6a5f78 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java @@ -17,8 +17,8 @@ package org.apache.logging.log4j.core.pattern; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; import org.apache.logging.log4j.Logger; @@ -29,7 +29,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -@LoggerContextSource("log4j-throwablefilter.xml") +@LoggerContextSource("log4j-extend-throwable.xml") public class ExtendedThrowableTest { private ListAppender app; @@ -47,6 +47,6 @@ public void testException(final LoggerContext context) { final List msgs = app.getMessages(); assertNotNull(msgs); assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); + assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java new file mode 100644 index 00000000000..7def6bd969d --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java @@ -0,0 +1,55 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@LoggerContextSource("log4j-extend-throwable-truncate.xml") +public class ExtendedThrowableTruncateTest { + private ListAppender app; + + @BeforeEach + public void setUp(@Named("List") final ListAppender app) throws Exception { + this.app = app.clear(); + } + + @Test + public void testException(final LoggerContext context) { + final Logger logger = context.getLogger("LoggerTest"); + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + String[] splits = msgs.get(0).split("\n"); + assertEquals(5, splits.length); + assertEquals("Exception java.lang.IllegalArgumentException: IllegalArgument", splits[0]); + assertFalse(msgs.get(0).contains("suppressed"), "No suppressed lines"); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java new file mode 100644 index 00000000000..ee14c9088f1 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java @@ -0,0 +1,46 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.Test; + +@LoggerContextSource("log4j-root-throwable-filter.xml") +public class RootThrowableFilterTest { + @Test + public void testException(final LoggerContext context, @Named("List") final ListAppender app) { + app.clear(); + final Logger logger = context.getLogger("LoggerTest"); + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); + app.clear(); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java index 1bbd44aa5e6..1b86b9c6ee3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java @@ -17,8 +17,8 @@ package org.apache.logging.log4j.core.pattern; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; import org.apache.logging.log4j.Logger; @@ -28,7 +28,7 @@ import org.apache.logging.log4j.core.test.junit.Named; import org.junit.jupiter.api.Test; -@LoggerContextSource("log4j-rootthrowablefilter.xml") +@LoggerContextSource("log4j-root-throwable.xml") public class RootThrowableTest { @Test public void testException(final LoggerContext context, @Named("List") final ListAppender app) { @@ -40,7 +40,7 @@ public void testException(final LoggerContext context, @Named("List") final List final List msgs = app.getMessages(); assertNotNull(msgs); assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); + assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); app.clear(); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java new file mode 100644 index 00000000000..6bc7707c318 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java @@ -0,0 +1,49 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.Test; + +@LoggerContextSource("log4j-root-throwable-truncate.xml") +public class RootThrowableTruncateTest { + @Test + public void testException(final LoggerContext context, @Named("List") final ListAppender app) { + app.clear(); + final Logger logger = context.getLogger("LoggerTest"); + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + String[] splits = msgs.get(0).split("\n"); + assertEquals(10, splits.length); + assertEquals("Exception java.lang.NullPointerException: null pointer", splits[0]); + assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); + app.clear(); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java new file mode 100644 index 00000000000..d159cbbb355 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java @@ -0,0 +1,56 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@code throwable} pattern. + */ +@LoggerContextSource("log4j-throwable-filter.xml") +public class ThrowableFilterTest { + private ListAppender app; + private Logger logger; + + @BeforeEach + public void setUp(final LoggerContext context, @Named("List") final ListAppender app) { + this.logger = context.getLogger("LoggerTest"); + this.app = app.clear(); + } + + @Test + public void testException() { + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 76ddfd4004e..1924fa33137 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -51,6 +51,6 @@ public void testException() { final List msgs = app.getMessages(); assertNotNull(msgs); assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertFalse(msgs.get(0).contains("suppressed"), "No suppressed lines"); + assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java new file mode 100644 index 00000000000..ae58b7b90f6 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java @@ -0,0 +1,62 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@code throwable} pattern. + */ +@LoggerContextSource("log4j-throwable-truncate.xml") +public class ThrowableTruncateTest { + private ListAppender app; + private Logger logger; + + @BeforeEach + public void setUp(final LoggerContext context, @Named("List") final ListAppender app) { + this.logger = context.getLogger("LoggerTest"); + this.app = app.clear(); + } + + @Test + public void testException() { + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + logger.error("Exception", parent); + final List msgs = app.getMessages(); + assertNotNull(msgs); + assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); + String[] splits = msgs.get(0).split("\n"); + assertEquals(5, splits.length); + assertTrue( + splits[0].startsWith( + "Exception org.apache.logging.log4j.core.pattern.ThrowableTruncateTest.testException(ThrowableTruncateTest.java:")); + assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); + } +} diff --git a/log4j-core-test/src/test/resources/log4j-throwablefilter.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml similarity index 100% rename from log4j-core-test/src/test/resources/log4j-throwablefilter.xml rename to log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml diff --git a/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml new file mode 100644 index 00000000000..b4ead102ef1 --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/log4j-extend-throwable.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable.xml new file mode 100644 index 00000000000..c40d2fd0954 --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-extend-throwable.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/log4j-rootthrowablefilter.xml b/log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml similarity index 100% rename from log4j-core-test/src/test/resources/log4j-rootthrowablefilter.xml rename to log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml diff --git a/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml new file mode 100644 index 00000000000..436d5d3e55a --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/log4j-root-throwable.xml b/log4j-core-test/src/test/resources/log4j-root-throwable.xml new file mode 100644 index 00000000000..c65e6cd66f7 --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-root-throwable.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/log4j-throwable-filter.xml b/log4j-core-test/src/test/resources/log4j-throwable-filter.xml new file mode 100644 index 00000000000..d47b245bec4 --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-throwable-filter.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml new file mode 100644 index 00000000000..6e993c643be --- /dev/null +++ b/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml @@ -0,0 +1,39 @@ + + + + + org.junit,org.apache.maven,sun.reflect,java.lang.reflect + + + + + + + + + + + + + + + + + + + From f17e6dad7c07c4b8d7f0937f7882e61714884a73 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Thu, 27 Jun 2024 10:14:56 +0200 Subject: [PATCH 09/72] Fix OSGi failures --- log4j-osgi-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-osgi-test/pom.xml b/log4j-osgi-test/pom.xml index d8e241ce79c..60930eb3173 100644 --- a/log4j-osgi-test/pom.xml +++ b/log4j-osgi-test/pom.xml @@ -203,7 +203,7 @@ maven-surefire-plugin - org.osgi:org.osgi.framework + org.osgi:org.osgi.core From 42459ed966eaa728757e74d7dcfc0fb1953891ca Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 28 Jun 2024 19:47:08 +0900 Subject: [PATCH 10/72] create tests programmatically --- .../pattern/ExtendedThrowableFilterTest.java | 52 -------- .../core/pattern/ExtendedThrowableTest.java | 52 -------- .../ExtendedThrowableTruncateTest.java | 55 -------- .../core/pattern/RootThrowableFilterTest.java | 46 ------- .../log4j/core/pattern/RootThrowableTest.java | 46 ------- .../pattern/RootThrowableTruncateTest.java | 49 -------- .../core/pattern/ThrowableFilterTest.java | 56 --------- .../log4j/core/pattern/ThrowableTest.java | 119 ++++++++++++++---- .../core/pattern/ThrowableTruncateTest.java | 62 --------- .../log4j/core/util/StringBuildersTest.java | 71 +++++++++-- .../log4j-extend-throwable-filter.xml | 39 ------ .../log4j-extend-throwable-truncate.xml | 39 ------ .../test/resources/log4j-extend-throwable.xml | 39 ------ .../resources/log4j-root-throwable-filter.xml | 39 ------ .../log4j-root-throwable-truncate.xml | 39 ------ .../test/resources/log4j-root-throwable.xml | 39 ------ .../test/resources/log4j-throwable-filter.xml | 39 ------ .../resources/log4j-throwable-truncate.xml | 39 ------ .../src/test/resources/log4j-throwable.xml | 39 ------ .../log4j/core/impl/ThrowableProxy.java | 4 +- .../core/impl/ThrowableProxyRenderer.java | 8 +- .../RootThrowablePatternConverter.java | 2 +- .../pattern/ThrowablePatternConverter.java | 10 +- .../core/util/internal/StringBuilders.java | 39 +++--- .../.2.x.x/fix_throwable_converter_issues.xml | 10 ++ 25 files changed, 195 insertions(+), 837 deletions(-) delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java delete mode 100644 log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-extend-throwable.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-root-throwable.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-throwable-filter.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-throwable-truncate.xml delete mode 100644 log4j-core-test/src/test/resources/log4j-throwable.xml create mode 100644 src/changelog/.2.x.x/fix_throwable_converter_issues.xml diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java deleted file mode 100644 index 5b58e4b9bc7..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableFilterTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-extend-throwable-filter.xml") -public class ExtendedThrowableFilterTest { - private ListAppender app; - - @BeforeEach - public void setUp(@Named("List") final ListAppender app) throws Exception { - this.app = app.clear(); - } - - @Test - public void testException(final LoggerContext context) { - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java deleted file mode 100644 index 39afe6a5f78..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-extend-throwable.xml") -public class ExtendedThrowableTest { - private ListAppender app; - - @BeforeEach - public void setUp(@Named("List") final ListAppender app) throws Exception { - this.app = app.clear(); - } - - @Test - public void testException(final LoggerContext context) { - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java deleted file mode 100644 index 7def6bd969d..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTruncateTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-extend-throwable-truncate.xml") -public class ExtendedThrowableTruncateTest { - private ListAppender app; - - @BeforeEach - public void setUp(@Named("List") final ListAppender app) throws Exception { - this.app = app.clear(); - } - - @Test - public void testException(final LoggerContext context) { - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - String[] splits = msgs.get(0).split("\n"); - assertEquals(5, splits.length); - assertEquals("Exception java.lang.IllegalArgumentException: IllegalArgument", splits[0]); - assertFalse(msgs.get(0).contains("suppressed"), "No suppressed lines"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java deleted file mode 100644 index ee14c9088f1..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableFilterTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-root-throwable-filter.xml") -public class RootThrowableFilterTest { - @Test - public void testException(final LoggerContext context, @Named("List") final ListAppender app) { - app.clear(); - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); - app.clear(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java deleted file mode 100644 index 1b86b9c6ee3..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-root-throwable.xml") -public class RootThrowableTest { - @Test - public void testException(final LoggerContext context, @Named("List") final ListAppender app) { - app.clear(); - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); - app.clear(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java deleted file mode 100644 index 6bc7707c318..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTruncateTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.Test; - -@LoggerContextSource("log4j-root-throwable-truncate.xml") -public class RootThrowableTruncateTest { - @Test - public void testException(final LoggerContext context, @Named("List") final ListAppender app) { - app.clear(); - final Logger logger = context.getLogger("LoggerTest"); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - String[] splits = msgs.get(0).split("\n"); - assertEquals(10, splits.length); - assertEquals("Exception java.lang.NullPointerException: null pointer", splits[0]); - assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); - app.clear(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java deleted file mode 100644 index d159cbbb355..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFilterTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@code throwable} pattern. - */ -@LoggerContextSource("log4j-throwable-filter.xml") -public class ThrowableFilterTest { - private ListAppender app; - private Logger logger; - - @BeforeEach - public void setUp(final LoggerContext context, @Named("List") final ListAppender app) { - this.logger = context.getLogger("LoggerTest"); - this.app = app.clear(); - } - - @Test - public void testException() { - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertTrue(msgs.get(0).contains("suppressed"), "No suppressed lines"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 1924fa33137..19076489863 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -16,41 +16,110 @@ */ package org.apache.logging.log4j.core.pattern; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; -import java.util.List; +import java.util.stream.Stream; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; +import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; /** - * Unit tests for {@code throwable} pattern. + * Unit tests for {@code throwable}, {@code rThrowable} and {@code xThrowable} pattern. */ -@LoggerContextSource("log4j-throwable.xml") public class ThrowableTest { - private ListAppender app; - private Logger logger; + static Stream testConverter_dataSource() { + final String filters = "org.junit,org.apache.maven,sun.reflect,java.lang.reflect"; + final Integer depth = 5; + return Stream.of( + // Throwable + Arguments.of("%ex", filters, null), + Arguments.of("%ex", null, depth), + // RootThrowable + Arguments.of("%rEx", filters, null), + Arguments.of("%rEx", null, depth), + // ExtendedThrowable + Arguments.of("%xEx", filters, null), + Arguments.of("%xEx", null, depth) + ); + } + + @ParameterizedTest + @MethodSource("testConverter_dataSource") + void testConverter(String exceptionPattern, String filters, Integer depth) { + final String pattern = buildPattern(exceptionPattern, filters, depth); + final ConfigurationBuilder configBuilder = + ConfigurationBuilderFactory.newConfigurationBuilder(); + + final String appenderName = "LIST"; + final Configuration config = configBuilder + .add(configBuilder + .newAppender(appenderName, "List") + .add(configBuilder.newLayout("PatternLayout").addAttribute("pattern", pattern))) + .add(configBuilder.newRootLogger(Level.ALL).add(configBuilder.newAppenderRef(appenderName))) + .build(false); + + try (final LoggerContext loggerContext = Configurator.initialize(config)) { + // Restart logger context after first test run + if (loggerContext.isStopped()) { + loggerContext.start(); + loggerContext.reconfigure(config); + } + final Throwable cause = new NullPointerException("null pointer"); + final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + + final Logger logger = loggerContext.getLogger("LoggerTest"); + final ListAppender appender = loggerContext.getConfiguration().getAppender(appenderName); + logger.error("Exception", parent); + + assertThat(appender.getMessages()).hasSize(1); + final String message = appender.getMessages().get(0); + assertThat(message).isNotNull(); + verifyFilters(message, filters); + verifyDepth(message, depth); + } + } + + static private String buildPattern(String exceptionPattern, String filters, Integer depth) { + final StringBuilder buffer = new StringBuilder("%m"); + buffer.append(exceptionPattern); + if (filters != null) { + buffer.append("{filters("); + buffer.append(filters); + buffer.append(")})"); + } + + if (depth != null) { + buffer.append("{"); + buffer.append(depth); + buffer.append("}"); + } + return buffer.toString(); + } - @BeforeEach - public void setUp(final LoggerContext context, @Named("List") final ListAppender app) { - this.logger = context.getLogger("LoggerTest"); - this.app = app.clear(); + static private void verifyFilters(final String message, final String filters) { + if (filters != null) { + assertThat(message).contains("suppressed"); + final String[] filterArray = filters.split(","); + for (final String filter : filterArray) { + assertThat(message).doesNotContain(filter); + } + } else { + assertThat(message).doesNotContain("suppressed"); + } } - @Test - public void testException() { - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); + static private void verifyDepth(final String message, final Integer depth) { + if (depth != null) { + assertThat(message).hasLineCount(depth); + } } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java deleted file mode 100644 index ae58b7b90f6..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTruncateTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.test.junit.Named; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@code throwable} pattern. - */ -@LoggerContextSource("log4j-throwable-truncate.xml") -public class ThrowableTruncateTest { - private ListAppender app; - private Logger logger; - - @BeforeEach - public void setUp(final LoggerContext context, @Named("List") final ListAppender app) { - this.logger = context.getLogger("LoggerTest"); - this.app = app.clear(); - } - - @Test - public void testException() { - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - logger.error("Exception", parent); - final List msgs = app.getMessages(); - assertNotNull(msgs); - assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size()); - String[] splits = msgs.get(0).split("\n"); - assertEquals(5, splits.length); - assertTrue( - splits[0].startsWith( - "Exception org.apache.logging.log4j.core.pattern.ThrowableTruncateTest.testException(ThrowableTruncateTest.java:")); - assertFalse(msgs.get(0).contains("suppressed"), "Should not suppress lines"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java index 0380110a4b9..387c45c85fb 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.util; -import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.stream.Stream; import org.apache.logging.log4j.core.util.internal.StringBuilders; @@ -24,24 +23,70 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + public class StringBuildersTest { - static Stream testTruncateLines_dataSource() { + static Stream testTruncateLines_happyCases() { return Stream.of( - Arguments.of("abc | def | ghi | jkl | ", " | ", 2, "abc | def | "), + // maxOccurrenceCount < lines count Arguments.of("abc\ndef\nghi\njkl\n", "\n", 2, "abc\ndef\n"), - Arguments.of("abc | def | ghi | jkl | ", " | ", 4, "abc | def | ghi | jkl | "), - Arguments.of("abc | def | ghi | jkl | ", " | ", null, "abc | def | ghi | jkl | "), - Arguments.of("abc | def | ghi | jkl | ", " | ", Integer.MAX_VALUE, "abc | def | ghi | jkl | "), - Arguments.of("abc | def | ghi | jkl | ", " | ", 10, "abc | def | ghi | jkl | "), - Arguments.of("abc | def | ghi | jkl | ", "", 2, "abc | def | ghi | jkl | ")); + // maxOccurrenceCount == lines count + Arguments.of("abc|def|ghi|jkl|", "|", 4, "abc|def|ghi|jkl|"), + // maxOccurrenceCount > lines count + Arguments.of("abc|def|ghi|jkl|", "|", 10, "abc|def|ghi|jkl|"), + // maxOccurrenceCount == Integer.MAX_VALUE + Arguments.of("abc|def|ghi|jkl|", "|", Integer.MAX_VALUE, "abc|def|ghi|jkl|"), + // maxOccurrenceCount == 0 + Arguments.of("abc|def|ghi|jkl|", "|", 0, ""), + // empty buffer + Arguments.of("", "|", 2, ""), + // empty delimiter + Arguments.of("abc|def|ghi|jkl|", "", 2, "abc|def|ghi|jkl|"), + // delimiter | + Arguments.of("|", "|", 10, "|"), + Arguments.of("||", "|", 10, "||"), + Arguments.of("a|", "|", 10, "a|"), + Arguments.of("|a", "|", 10, "|"), + // delimiter || + Arguments.of("||", "||", 10, "||"), + Arguments.of("|||", "||", 10, "||"), + Arguments.of("||||", "||", 10, "||||"), + Arguments.of("a|", "||", 10, ""), + Arguments.of("a||", "||", 10, "a||"), + Arguments.of("a|||", "||", 10, "a||"), + Arguments.of("a||||", "||", 10, "a||||"), + Arguments.of("|a", "||", 10, ""), + Arguments.of("||a", "||", 10, "||"), + Arguments.of("|||a", "||", 10, "||"), + Arguments.of("||||a", "||", 10, "||||") + ); + } + + @ParameterizedTest + @MethodSource("testTruncateLines_happyCases") + void testTruncateLinesHappyCases(String input, String delimiter, int maxOccurrenceCount, String expected) { + final StringBuilder buffer = new StringBuilder(input); + StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount); + assertThat(buffer.toString()).isEqualTo(expected); + } + + static Stream testTruncateLines_failCases() { + return Stream.of( + // negative maxOccurrenceCount + Arguments.of("abc\ndef\nghi\njkl\n", "\n", -1, IllegalArgumentException.class), + // null buffer + Arguments.of(null, "|", 10, NullPointerException.class), + // null delimiter + Arguments.of("abc|def|ghi|jkl|", null, 10, NullPointerException.class) + ); } @ParameterizedTest - @MethodSource("testTruncateLines_dataSource") - public void testTruncateLines(String original, String lineSeparator, Integer maxLine, String expected) { - final StringBuilder sb = new StringBuilder(original); - StringBuilders.truncateLines(sb, lineSeparator, maxLine); - assertEquals(expected, sb.toString()); + @MethodSource("testTruncateLines_failCases") + void testTruncateLinesFailCases(String input, String delimiter, int maxOccurrenceCount, Class expected) { + final StringBuilder buffer = input == null ? null : new StringBuilder(input); + assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)).isInstanceOf(expected); } } diff --git a/log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml deleted file mode 100644 index e1c97c03ad4..00000000000 --- a/log4j-core-test/src/test/resources/log4j-extend-throwable-filter.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml deleted file mode 100644 index b4ead102ef1..00000000000 --- a/log4j-core-test/src/test/resources/log4j-extend-throwable-truncate.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-extend-throwable.xml b/log4j-core-test/src/test/resources/log4j-extend-throwable.xml deleted file mode 100644 index c40d2fd0954..00000000000 --- a/log4j-core-test/src/test/resources/log4j-extend-throwable.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml b/log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml deleted file mode 100644 index 9412a1e7760..00000000000 --- a/log4j-core-test/src/test/resources/log4j-root-throwable-filter.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml deleted file mode 100644 index 436d5d3e55a..00000000000 --- a/log4j-core-test/src/test/resources/log4j-root-throwable-truncate.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-root-throwable.xml b/log4j-core-test/src/test/resources/log4j-root-throwable.xml deleted file mode 100644 index c65e6cd66f7..00000000000 --- a/log4j-core-test/src/test/resources/log4j-root-throwable.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-throwable-filter.xml b/log4j-core-test/src/test/resources/log4j-throwable-filter.xml deleted file mode 100644 index d47b245bec4..00000000000 --- a/log4j-core-test/src/test/resources/log4j-throwable-filter.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml b/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml deleted file mode 100644 index 6e993c643be..00000000000 --- a/log4j-core-test/src/test/resources/log4j-throwable-truncate.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core-test/src/test/resources/log4j-throwable.xml b/log4j-core-test/src/test/resources/log4j-throwable.xml deleted file mode 100644 index db9647f9ef2..00000000000 --- a/log4j-core-test/src/test/resources/log4j-throwable.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.junit,org.apache.maven,sun.reflect,java.lang.reflect - - - - - - - - - - - - - - - - - - - diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 039e08ca4d2..3d6822600fc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -318,7 +318,7 @@ public void formatCauseStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer maxLineCount) { + final int maxLineCount) { ThrowableProxyRenderer.formatCauseStackTraceTo( this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); } @@ -452,7 +452,7 @@ public void formatExtendedStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer maxLineCount) { + final int maxLineCount) { ThrowableProxyRenderer.formatExtendedStackTraceTo( this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index 1e6eb031c80..6979c8d66f8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -242,7 +242,7 @@ static void formatExtendedStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer maxLineCount) { + final int maxLineCount) { renderOn(src, sb, textRenderer); renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); @@ -260,7 +260,7 @@ static void formatExtendedStackTraceTo( lineSeparator); formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator); formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator); - StringBuilders.truncateLines(sb, lineSeparator, maxLineCount); + StringBuilders.truncateAfterDelimiter(sb, lineSeparator, maxLineCount); } /** @@ -280,7 +280,7 @@ static void formatCauseStackTraceTo( final TextRenderer textRenderer, final String suffix, final String lineSeparator, - final Integer maxLineCount) { + final int maxLineCount) { final ThrowableProxy causeProxy = src.getCauseProxy(); if (causeProxy != null) { formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator); @@ -300,7 +300,7 @@ static void formatCauseStackTraceTo( textRenderer, suffix, lineSeparator); - StringBuilders.truncateLines(sb, lineSeparator, maxLineCount); + StringBuilders.truncateAfterDelimiter(sb, lineSeparator, maxLineCount); } private static void renderOn( diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index 0088f1a0887..c0529f0e53e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -77,7 +77,7 @@ public void format(final LogEvent event, final StringBuilder toAppendTo) { options.getTextRenderer(), getSuffix(event), options.getSeparator(), - options.allLines() ? null : options.getLines()); + options.getLines()); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 55c43d4e812..fb4f28e21d1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -205,7 +205,7 @@ private void formatOption(final Throwable throwable, final String suffix, final if (ignoredCount > 0) { appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); } - StringBuilders.truncateLines(buffer, options.getSeparator(), options.getLines()); + StringBuilders.truncateAfterDelimiter(buffer, options.getSeparator(), options.getLines()); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -241,7 +241,7 @@ private boolean requireAdditionalFormatting(final String suffix) { return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); } - private boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { + private static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); for (final String pkg : ignorePackages) { @@ -253,7 +253,7 @@ private boolean ignoreElement(final StackTraceElement element, final ListIf {@code maxLineCount} is {@code null}, {@link Integer#MAX_VALUE}, or if {@code lineSeparator} is empty, + *

If {@code maxOccurrenceCount} is {@link Integer#MAX_VALUE}, or if {@code delimiter} is empty, * the method returns without making any changes to the {@code StringBuilder}. * * @param buffer the {@code StringBuilder} whose content is to be truncated - * @param lineSeparator the line separator used to determine the end of a line - * @param maxLineCount the maximum number of lines to retain in the {@code StringBuilder}; - * if this value is {@code null} or {@link Integer#MAX_VALUE}, no truncation will occur + * @param delimiter the delimiter used to determine the end of a line + * @param maxOccurrenceCount the maximum number of lines to retain in the {@code StringBuilder}; + * if this value is {@link Integer#MAX_VALUE}, no truncation will occur */ - public static void truncateLines( - final StringBuilder buffer, final String lineSeparator, final Integer maxLineCount) { - if (buffer == null - || maxLineCount == null - || maxLineCount == Integer.MAX_VALUE - || lineSeparator == null - || lineSeparator.isEmpty()) { + public static void truncateAfterDelimiter( + final StringBuilder buffer, final String delimiter, final int maxOccurrenceCount) { + Objects.requireNonNull(buffer, "buffer"); + Objects.requireNonNull(delimiter, "delimiter"); + if (maxOccurrenceCount < 0) { + throw new IllegalArgumentException("maxOccurrenceCount should not be negative"); + } + if (buffer.length() < delimiter.length() || delimiter.isEmpty() || maxOccurrenceCount == Integer.MAX_VALUE) { return; } - final int lineSeparatorLen = lineSeparator.length(); + final int delimiterLen = delimiter.length(); int offset = 0; - int currentLineCount = 0; - while (currentLineCount < maxLineCount) { - int lineSeparatorIndex = buffer.indexOf(lineSeparator, offset); - if (lineSeparatorIndex == -1) { + int currentOccurrenceCount = 0; + while (currentOccurrenceCount < maxOccurrenceCount) { + int delimiterIndex = buffer.indexOf(delimiter, offset); + if (delimiterIndex == -1) { break; } - currentLineCount++; - offset = lineSeparatorIndex + lineSeparatorLen; + currentOccurrenceCount++; + offset = delimiterIndex + delimiterLen; } buffer.setLength(offset); } diff --git a/src/changelog/.2.x.x/fix_throwable_converter_issues.xml b/src/changelog/.2.x.x/fix_throwable_converter_issues.xml new file mode 100644 index 00000000000..6d4d86b4285 --- /dev/null +++ b/src/changelog/.2.x.x/fix_throwable_converter_issues.xml @@ -0,0 +1,10 @@ + + + + + Resolved the lack of support for "filters" in the %ex pattern and "depth" in the %xEx pattern. + + From 659f7e5bc0bb1f7e71039571768b5b19f7043f5d Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 28 Jun 2024 21:37:25 +0900 Subject: [PATCH 11/72] fix style --- .../logging/log4j/core/pattern/ThrowableTest.java | 9 ++++----- .../log4j/core/util/StringBuildersTest.java | 14 ++++++-------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 19076489863..44510a57d11 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -48,8 +48,7 @@ static Stream testConverter_dataSource() { Arguments.of("%rEx", null, depth), // ExtendedThrowable Arguments.of("%xEx", filters, null), - Arguments.of("%xEx", null, depth) - ); + Arguments.of("%xEx", null, depth)); } @ParameterizedTest @@ -88,7 +87,7 @@ void testConverter(String exceptionPattern, String filters, Integer depth) { } } - static private String buildPattern(String exceptionPattern, String filters, Integer depth) { + private static String buildPattern(String exceptionPattern, String filters, Integer depth) { final StringBuilder buffer = new StringBuilder("%m"); buffer.append(exceptionPattern); if (filters != null) { @@ -105,7 +104,7 @@ static private String buildPattern(String exceptionPattern, String filters, Inte return buffer.toString(); } - static private void verifyFilters(final String message, final String filters) { + private static void verifyFilters(final String message, final String filters) { if (filters != null) { assertThat(message).contains("suppressed"); final String[] filterArray = filters.split(","); @@ -117,7 +116,7 @@ static private void verifyFilters(final String message, final String filters) { } } - static private void verifyDepth(final String message, final Integer depth) { + private static void verifyDepth(final String message, final Integer depth) { if (depth != null) { assertThat(message).hasLineCount(depth); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java index 387c45c85fb..1153af8075b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.util; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.stream.Stream; import org.apache.logging.log4j.core.util.internal.StringBuilders; @@ -23,9 +25,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - public class StringBuildersTest { static Stream testTruncateLines_happyCases() { @@ -60,8 +59,7 @@ static Stream testTruncateLines_happyCases() { Arguments.of("|a", "||", 10, ""), Arguments.of("||a", "||", 10, "||"), Arguments.of("|||a", "||", 10, "||"), - Arguments.of("||||a", "||", 10, "||||") - ); + Arguments.of("||||a", "||", 10, "||||")); } @ParameterizedTest @@ -79,14 +77,14 @@ static Stream testTruncateLines_failCases() { // null buffer Arguments.of(null, "|", 10, NullPointerException.class), // null delimiter - Arguments.of("abc|def|ghi|jkl|", null, 10, NullPointerException.class) - ); + Arguments.of("abc|def|ghi|jkl|", null, 10, NullPointerException.class)); } @ParameterizedTest @MethodSource("testTruncateLines_failCases") void testTruncateLinesFailCases(String input, String delimiter, int maxOccurrenceCount, Class expected) { final StringBuilder buffer = input == null ? null : new StringBuilder(input); - assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)).isInstanceOf(expected); + assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)) + .isInstanceOf(expected); } } From efc126a30d104eb38115e787433ac29adf0c2147 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 3 Jul 2024 23:22:02 +0900 Subject: [PATCH 12/72] update as comment --- .../log4j/core/pattern/ThrowableTest.java | 3 +- .../{ => internal}/StringBuildersTest.java | 76 +++++++++++-------- .../logging/log4j/core/package-info.java | 2 +- .../core/util/internal/StringBuilders.java | 13 ++-- .../.2.x.x/fix_throwable_converter_issues.xml | 2 +- 5 files changed, 55 insertions(+), 41 deletions(-) rename log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/{ => internal}/StringBuildersTest.java (52%) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 44510a57d11..bf37e396fc1 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -22,6 +22,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.LoggerTest; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; @@ -75,7 +76,7 @@ void testConverter(String exceptionPattern, String filters, Integer depth) { final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final Logger logger = loggerContext.getLogger("LoggerTest"); + final Logger logger = loggerContext.getLogger(LoggerTest.class); final ListAppender appender = loggerContext.getConfiguration().getAppender(appenderName); logger.error("Exception", parent); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java similarity index 52% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java index 1153af8075b..d2fd4ecfc7b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/StringBuildersTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java @@ -14,75 +14,87 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.util.internal; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.Arrays; +import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -public class StringBuildersTest { +class StringBuildersTest { static Stream testTruncateLines_happyCases() { return Stream.of( // maxOccurrenceCount < lines count - Arguments.of("abc\ndef\nghi\njkl\n", "\n", 2, "abc\ndef\n"), + Arguments.of("abc#def#ghi#jkl#", "#", 2), // maxOccurrenceCount == lines count - Arguments.of("abc|def|ghi|jkl|", "|", 4, "abc|def|ghi|jkl|"), + Arguments.of("abc#def#ghi#jkl#", "#", 4), // maxOccurrenceCount > lines count - Arguments.of("abc|def|ghi|jkl|", "|", 10, "abc|def|ghi|jkl|"), + Arguments.of("abc#def#ghi#jkl#", "#", 10), // maxOccurrenceCount == Integer.MAX_VALUE - Arguments.of("abc|def|ghi|jkl|", "|", Integer.MAX_VALUE, "abc|def|ghi|jkl|"), + Arguments.of("abc#def#ghi#jkl#", "#", Integer.MAX_VALUE), // maxOccurrenceCount == 0 - Arguments.of("abc|def|ghi|jkl|", "|", 0, ""), + Arguments.of("abc#def#ghi#jkl#", "#", 0), // empty buffer - Arguments.of("", "|", 2, ""), + Arguments.of("", "#", 2), // empty delimiter - Arguments.of("abc|def|ghi|jkl|", "", 2, "abc|def|ghi|jkl|"), - // delimiter | - Arguments.of("|", "|", 10, "|"), - Arguments.of("||", "|", 10, "||"), - Arguments.of("a|", "|", 10, "a|"), - Arguments.of("|a", "|", 10, "|"), - // delimiter || - Arguments.of("||", "||", 10, "||"), - Arguments.of("|||", "||", 10, "||"), - Arguments.of("||||", "||", 10, "||||"), - Arguments.of("a|", "||", 10, ""), - Arguments.of("a||", "||", 10, "a||"), - Arguments.of("a|||", "||", 10, "a||"), - Arguments.of("a||||", "||", 10, "a||||"), - Arguments.of("|a", "||", 10, ""), - Arguments.of("||a", "||", 10, "||"), - Arguments.of("|||a", "||", 10, "||"), - Arguments.of("||||a", "||", 10, "||||")); + Arguments.of("abc#def#ghi#jkl#", "", 2), + // delimiter # + Arguments.of("#", "#", 1), + Arguments.of("##", "#", 1), + Arguments.of("a#", "#", 1), + Arguments.of("#a", "#", 1), + // delimiter ## + Arguments.of("##", "##", 1), + Arguments.of("###", "##", 1), + Arguments.of("####", "##", 1), + Arguments.of("a#", "##", 1), + Arguments.of("a##", "##", 1), + Arguments.of("a###", "##", 1), + Arguments.of("a####", "##", 1), + Arguments.of("#a", "##", 1), + Arguments.of("##a", "##", 1), + Arguments.of("###a", "##", 1), + Arguments.of("####a", "##", 1)); } @ParameterizedTest @MethodSource("testTruncateLines_happyCases") - void testTruncateLinesHappyCases(String input, String delimiter, int maxOccurrenceCount, String expected) { + void testTruncateLinesHappyCases(final String input, final String delimiter, final int maxOccurrenceCount) { final StringBuilder buffer = new StringBuilder(input); StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount); + final String expected; + if (delimiter.isEmpty()) { + expected = input; + } else if (buffer.length() == 0) { + expected = ""; + } else { + expected = Arrays.stream(input.split(delimiter)) + .limit(maxOccurrenceCount) + .collect(Collectors.joining(delimiter, "", delimiter)); + } assertThat(buffer.toString()).isEqualTo(expected); } static Stream testTruncateLines_failCases() { return Stream.of( // negative maxOccurrenceCount - Arguments.of("abc\ndef\nghi\njkl\n", "\n", -1, IllegalArgumentException.class), + Arguments.of("abc#def#ghi#jkl#", "#", -1, IllegalArgumentException.class), // null buffer - Arguments.of(null, "|", 10, NullPointerException.class), + Arguments.of(null, "#", 10, NullPointerException.class), // null delimiter - Arguments.of("abc|def|ghi|jkl|", null, 10, NullPointerException.class)); + Arguments.of("abc#def#ghi#jkl#", null, 10, NullPointerException.class)); } @ParameterizedTest @MethodSource("testTruncateLines_failCases") - void testTruncateLinesFailCases(String input, String delimiter, int maxOccurrenceCount, Class expected) { + void testTruncateLinesFailCases( + final String input, final String delimiter, final int maxOccurrenceCount, final Class expected) { final StringBuilder buffer = input == null ? null : new StringBuilder(input); assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)) .isInstanceOf(expected); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java index 171f9c7e78d..266256b4637 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java @@ -18,7 +18,7 @@ * Implementation of Log4j 2. */ @Export -@Version("2.25.0") +@Version("2.24.0") package org.apache.logging.log4j.core; import org.osgi.annotation.bundle.Export; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java index 1ba86932162..547f5dbab03 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java @@ -24,22 +24,23 @@ public class StringBuilders { /** - * Truncates the content of the given {@code StringBuilder} to the specified maximum number of lines. + * Truncates the content of the given {@code StringBuilder} after the specified times of occurrences of the given delimiter. * *

If {@code maxOccurrenceCount} is {@link Integer#MAX_VALUE}, or if {@code delimiter} is empty, * the method returns without making any changes to the {@code StringBuilder}. * - * @param buffer the {@code StringBuilder} whose content is to be truncated - * @param delimiter the delimiter used to determine the end of a line - * @param maxOccurrenceCount the maximum number of lines to retain in the {@code StringBuilder}; - * if this value is {@link Integer#MAX_VALUE}, no truncation will occur + * @param buffer the {@code StringBuilder} to be truncated + * @param delimiter The delimiter to be used. + * Setting this value to an empty string effectively disables truncation. + * @param maxOccurrenceCount Denotes the maximum number of {@code delimiter} occurrences allowed. + * Setting this value to {@link Integer#MAX_VALUE} effectively disables truncation. */ public static void truncateAfterDelimiter( final StringBuilder buffer, final String delimiter, final int maxOccurrenceCount) { Objects.requireNonNull(buffer, "buffer"); Objects.requireNonNull(delimiter, "delimiter"); if (maxOccurrenceCount < 0) { - throw new IllegalArgumentException("maxOccurrenceCount should not be negative"); + throw new IllegalArgumentException("`maxOccurrenceCount` should not be negative"); } if (buffer.length() < delimiter.length() || delimiter.isEmpty() || maxOccurrenceCount == Integer.MAX_VALUE) { return; diff --git a/src/changelog/.2.x.x/fix_throwable_converter_issues.xml b/src/changelog/.2.x.x/fix_throwable_converter_issues.xml index 6d4d86b4285..fb81a7c0b57 100644 --- a/src/changelog/.2.x.x/fix_throwable_converter_issues.xml +++ b/src/changelog/.2.x.x/fix_throwable_converter_issues.xml @@ -5,6 +5,6 @@ type="fixed"> - Resolved the lack of support for "filters" in the %ex pattern and "depth" in the %xEx pattern. + Add `filters` and `depth` support to `%ex` and `%xEx` converters, respectively, of Pattern Layout From e4fa22366b5ffecd53c69728797d8e4f23eb4393 Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 12 Jul 2024 10:59:33 +0900 Subject: [PATCH 13/72] Add ThrowableRenderer --- .../pattern/ThrowablePatternConverter.java | 63 +-------- .../log4j/core/pattern/ThrowableRenderer.java | 133 ++++++++++++++++++ .../log4j/core/pattern/package-info.java | 2 +- 3 files changed, 137 insertions(+), 61 deletions(-) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index fb4f28e21d1..1d6c9e79058 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -27,7 +27,6 @@ import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.StringBuilderWriter; -import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; /** @@ -189,23 +188,9 @@ private void formatOption(final Throwable throwable, final String suffix, final buffer.append(' '); } if (requireAdditionalFormatting(suffix)) { - final StackTraceElement[] stackTrace = throwable.getStackTrace(); - int ignoredCount = 0; - for (final StackTraceElement stackTraceElement : stackTrace) { - if (!ignoreElement(stackTraceElement, options.getIgnorePackages())) { - if (ignoredCount > 0) { - appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); - ignoredCount = 0; - } - appendEntry(stackTraceElement, buffer, suffix, options.getSeparator()); - } else { - ++ignoredCount; - } - } - if (ignoredCount > 0) { - appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator()); - } - StringBuilders.truncateAfterDelimiter(buffer, options.getSeparator(), options.getLines()); + ThrowableRenderer renderer = new ThrowableRenderer<>( + options.getIgnorePackages(), suffix, options.getSeparator(), options.getLines()); + renderer.renderThrowable(buffer, throwable); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -240,46 +225,4 @@ public ThrowableFormatOptions getOptions() { private boolean requireAdditionalFormatting(final String suffix) { return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); } - - private static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { - if (ignorePackages != null) { - final String className = element.getClassName(); - for (final String pkg : ignorePackages) { - if (className.startsWith(pkg)) { - return true; - } - } - } - return false; - } - - private static void appendSuppressedCount( - final StringBuilder sb, final int count, final String suffix, final String lineSeparator) { - if (count == 1) { - sb.append("\t... "); - } else { - sb.append("\t... suppressed "); - sb.append(count); - sb.append(" lines"); - } - appendSuffix(sb, suffix); - sb.append(lineSeparator); - } - - private static void appendEntry( - final StackTraceElement stackTraceElement, - final StringBuilder sb, - final String suffix, - final String lineSeparator) { - sb.append(stackTraceElement.toString()); - appendSuffix(sb, suffix); - sb.append(lineSeparator); - } - - private static void appendSuffix(final StringBuilder buffer, final String suffix) { - if (Strings.isNotBlank(suffix)) { - buffer.append(' '); - buffer.append(suffix); - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java new file mode 100644 index 00000000000..9fa91ab207f --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -0,0 +1,133 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.util.List; +import org.apache.logging.log4j.core.util.internal.StringBuilders; +import org.apache.logging.log4j.util.Strings; + +public class ThrowableRenderer { + protected final List ignoredPackageNames; + protected final String stackTraceElementSuffix; + protected final String lineSeparator; + protected final int maxLineCount; + private int ignoredCount; + + ThrowableRenderer( + final List ignoredPackageNames, + final String stackTraceElementSuffix, + final String lineSeparator, + final int maxLineCount) { + this.ignoredPackageNames = ignoredPackageNames; + this.stackTraceElementSuffix = stackTraceElementSuffix; + this.lineSeparator = lineSeparator; + this.maxLineCount = maxLineCount; + } + + final void renderThrowable(final StringBuilder buffer, final Throwable throwable) { + C context = createContext(throwable); + renderThrowable(buffer, throwable, context); + } + + C createContext(final Throwable throwable) { + return null; + } + + void renderThrowable(final StringBuilder buffer, final Throwable throwable, final C context) { + renderThrowableMessage(buffer, throwable); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + + ignoredCount = 0; + final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + for (final StackTraceElement element : stackTraceElements) { + renderStackTraceElement(buffer, element, context); + } + if (ignoredCount > 0) { + appendSuppressedCount(buffer, ignoredCount, stackTraceElementSuffix, lineSeparator); + } + StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); + } + + void renderStackTraceElement( + final StringBuilder buffer, final StackTraceElement stackTraceElement, final C context) { + if (!ignoreElement(stackTraceElement, ignoredPackageNames)) { + if (ignoredCount > 0) { + appendSuppressedCount(buffer, ignoredCount, stackTraceElementSuffix, lineSeparator); + ignoredCount = 0; + } + appendEntry(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); + } else { + ++ignoredCount; + } + } + + protected static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { + final String message = throwable.getMessage(); + buffer.append(throwable.getClass().getName()); + if (message != null) { + buffer.append(": "); + buffer.append(message); + } + } + + protected static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { + if (ignorePackages != null) { + final String className = element.getClassName(); + for (final String pkg : ignorePackages) { + if (className.startsWith(pkg)) { + return true; + } + } + } + return false; + } + + protected static void appendSuppressedCount( + final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { + if (count == 1) { + buffer.append("\t... "); + } else { + buffer.append("\t... suppressed "); + buffer.append(count); + buffer.append(" lines"); + } + appendSuffix(buffer, suffix); + buffer.append(lineSeparator); + } + + protected static void appendEntry( + final StackTraceElement stackTraceElement, + final StringBuilder buffer, + final String suffix, + final String lineSeparator) { + buffer.append(stackTraceElement.toString()); + appendSuffix(buffer, suffix); + buffer.append(lineSeparator); + } + + protected static void appendSuffix(final StringBuilder buffer, final String suffix) { + if (Strings.isNotBlank(suffix)) { + buffer.append(' '); + buffer.append(suffix); + } + } + + protected static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { + buffer.append(lineSeparator); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java index dba7d0e5493..5e6af62542d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java @@ -18,7 +18,7 @@ * Provides classes implementing format specifiers in conversion patterns. */ @Export -@Version("2.21.1") +@Version("2.22.0") package org.apache.logging.log4j.core.pattern; import org.osgi.annotation.bundle.Export; From 40162395f461e263c0df286248e57d1bc1a8d226 Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 12 Jul 2024 22:49:48 +0900 Subject: [PATCH 14/72] Add ThrowableRenderer.Context and update ThrowablePatternConverter suffix logic --- .../pattern/ThrowablePatternConverter.java | 81 +++++++++---------- .../log4j/core/pattern/ThrowableRenderer.java | 51 +++++++----- 2 files changed, 72 insertions(+), 60 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 1d6c9e79058..17ea41b4e56 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -19,8 +19,8 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import java.util.function.Function; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -37,12 +37,7 @@ @Plugin(name = "ThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"ex", "throwable", "exception"}) public class ThrowablePatternConverter extends LogEventPatternConverter { - - /** - * Lists {@link PatternFormatter}s for the suffix attribute. - */ - protected final List formatters; - + private final Function suffixProvider; private String rawOption; private final boolean subShortOption; private final boolean nonStandardLineSeparator; @@ -78,30 +73,7 @@ protected ThrowablePatternConverter( if (options != null && options.length > 0) { rawOption = options[0]; } - if (this.options.getSuffix() != null) { - final PatternParser parser = PatternLayout.createPatternParser(config); - final List parsedSuffixFormatters = parser.parse(this.options.getSuffix()); - // filter out nested formatters that will handle throwable - boolean hasThrowableSuffixFormatter = false; - for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { - if (suffixFormatter.handlesThrowable()) { - hasThrowableSuffixFormatter = true; - } - } - if (!hasThrowableSuffixFormatter) { - this.formatters = parsedSuffixFormatters; - } else { - final List suffixFormatters = new ArrayList<>(); - for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { - if (!suffixFormatter.handlesThrowable()) { - suffixFormatters.add(suffixFormatter); - } - } - this.formatters = suffixFormatters; - } - } else { - this.formatters = Collections.emptyList(); - } + this.suffixProvider = createSuffixProvider(this.options.getSuffix(), config); subShortOption = ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.FILE_NAME.equalsIgnoreCase(rawOption) @@ -188,7 +160,7 @@ private void formatOption(final Throwable throwable, final String suffix, final buffer.append(' '); } if (requireAdditionalFormatting(suffix)) { - ThrowableRenderer renderer = new ThrowableRenderer<>( + ThrowableRenderer renderer = new ThrowableRenderer<>( options.getIgnorePackages(), suffix, options.getSeparator(), options.getLines()); renderer.renderThrowable(buffer, throwable); } else { @@ -207,15 +179,7 @@ public boolean handlesThrowable() { } protected String getSuffix(final LogEvent event) { - if (formatters.isEmpty()) { - return Strings.EMPTY; - } - //noinspection ForLoopReplaceableByForEach - final StringBuilder toAppendTo = new StringBuilder(); - for (int i = 0, size = formatters.size(); i < size; i++) { - formatters.get(i).format(event, toAppendTo); - } - return toAppendTo.toString(); + return suffixProvider.apply(event); } public ThrowableFormatOptions getOptions() { @@ -225,4 +189,39 @@ public ThrowableFormatOptions getOptions() { private boolean requireAdditionalFormatting(final String suffix) { return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); } + + private static Function createSuffixProvider(final String suffix, final Configuration config) { + if (suffix != null) { + final PatternParser parser = PatternLayout.createPatternParser(config); + final List parsedSuffixFormatters = parser.parse(suffix); + // filter out nested formatters that will handle throwable + boolean hasThrowableSuffixFormatter = false; + for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { + if (suffixFormatter.handlesThrowable()) { + hasThrowableSuffixFormatter = true; + } + } + List finalFormatters; + if (!hasThrowableSuffixFormatter) { + finalFormatters = parsedSuffixFormatters; + } else { + final List suffixFormatters = new ArrayList<>(); + for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { + if (!suffixFormatter.handlesThrowable()) { + suffixFormatters.add(suffixFormatter); + } + } + finalFormatters = suffixFormatters; + } + return logEvent -> { + final StringBuilder toAppendTo = new StringBuilder(); + for (int i = 0, size = finalFormatters.size(); i < size; i++) { + finalFormatters.get(i).format(logEvent, toAppendTo); + } + return toAppendTo.toString(); + }; + } else { + return logEvent -> Strings.EMPTY; + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 9fa91ab207f..0293ef39e42 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -20,12 +20,11 @@ import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; -public class ThrowableRenderer { +class ThrowableRenderer { protected final List ignoredPackageNames; protected final String stackTraceElementSuffix; protected final String lineSeparator; protected final int maxLineCount; - private int ignoredCount; ThrowableRenderer( final List ignoredPackageNames, @@ -43,40 +42,42 @@ final void renderThrowable(final StringBuilder buffer, final Throwable throwable renderThrowable(buffer, throwable, context); } - C createContext(final Throwable throwable) { - return null; + private C createContext(final Throwable throwable) { + return (C) new ThrowableRenderer.Context(); } - void renderThrowable(final StringBuilder buffer, final Throwable throwable, final C context) { + private void renderThrowable(final StringBuilder buffer, final Throwable throwable, final C context) { renderThrowableMessage(buffer, throwable); appendSuffix(buffer, stackTraceElementSuffix); appendLineSeparator(buffer, lineSeparator); - ignoredCount = 0; + context.setIgnoredStackTraceElementCount(0); final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (final StackTraceElement element : stackTraceElements) { renderStackTraceElement(buffer, element, context); } - if (ignoredCount > 0) { - appendSuppressedCount(buffer, ignoredCount, stackTraceElementSuffix, lineSeparator); + if (context.getIgnoredStackTraceElementCount() > 0) { + appendSuppressedCount( + buffer, context.getIgnoredStackTraceElementCount(), stackTraceElementSuffix, lineSeparator); } StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } - void renderStackTraceElement( + private void renderStackTraceElement( final StringBuilder buffer, final StackTraceElement stackTraceElement, final C context) { if (!ignoreElement(stackTraceElement, ignoredPackageNames)) { - if (ignoredCount > 0) { - appendSuppressedCount(buffer, ignoredCount, stackTraceElementSuffix, lineSeparator); - ignoredCount = 0; + if (context.getIgnoredStackTraceElementCount() > 0) { + appendSuppressedCount( + buffer, context.getIgnoredStackTraceElementCount(), stackTraceElementSuffix, lineSeparator); + context.setIgnoredStackTraceElementCount(0); } appendEntry(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); } else { - ++ignoredCount; + context.setIgnoredStackTraceElementCount(context.getIgnoredStackTraceElementCount() + 1); } } - protected static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { + private static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { final String message = throwable.getMessage(); buffer.append(throwable.getClass().getName()); if (message != null) { @@ -85,7 +86,7 @@ protected static void renderThrowableMessage(final StringBuilder buffer, final T } } - protected static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { + private static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); for (final String pkg : ignorePackages) { @@ -97,7 +98,7 @@ protected static boolean ignoreElement(final StackTraceElement element, final Li return false; } - protected static void appendSuppressedCount( + private static void appendSuppressedCount( final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { if (count == 1) { buffer.append("\t... "); @@ -110,7 +111,7 @@ protected static void appendSuppressedCount( buffer.append(lineSeparator); } - protected static void appendEntry( + private static void appendEntry( final StackTraceElement stackTraceElement, final StringBuilder buffer, final String suffix, @@ -120,14 +121,26 @@ protected static void appendEntry( buffer.append(lineSeparator); } - protected static void appendSuffix(final StringBuilder buffer, final String suffix) { + private static void appendSuffix(final StringBuilder buffer, final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); buffer.append(suffix); } } - protected static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { + private static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { buffer.append(lineSeparator); } + + static class Context { + private int ignoredStackTraceElementCount; + + public int getIgnoredStackTraceElementCount() { + return ignoredStackTraceElementCount; + } + + public void setIgnoredStackTraceElementCount(int ignoredStackTraceElementCount) { + this.ignoredStackTraceElementCount = ignoredStackTraceElementCount; + } + } } From 0cd5f6baeda237d2265f452b803383afe0224d8c Mon Sep 17 00:00:00 2001 From: alanyu Date: Sat, 13 Jul 2024 11:33:16 +0900 Subject: [PATCH 15/72] Make ThrowableRenderer instance variable of ThrowablePatternConverter --- .../log4j/core/pattern/ThrowableTest.java | 2 +- .../pattern/ThrowablePatternConverter.java | 7 +-- .../log4j/core/pattern/ThrowableRenderer.java | 52 ++++++++----------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index bf37e396fc1..843ed1c0c90 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -94,7 +94,7 @@ private static String buildPattern(String exceptionPattern, String filters, Inte if (filters != null) { buffer.append("{filters("); buffer.append(filters); - buffer.append(")})"); + buffer.append(")}"); } if (depth != null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 17ea41b4e56..dfb2f4ee85d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -41,6 +41,7 @@ public class ThrowablePatternConverter extends LogEventPatternConverter { private String rawOption; private final boolean subShortOption; private final boolean nonStandardLineSeparator; + private final ThrowableRenderer renderer; /** * Options. @@ -81,6 +82,8 @@ protected ThrowablePatternConverter( || ThrowableFormatOptions.METHOD_NAME.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.CLASS_NAME.equalsIgnoreCase(rawOption); nonStandardLineSeparator = !Strings.LINE_SEPARATOR.equals(this.options.getSeparator()); + renderer = new ThrowableRenderer<>( + this.options.getIgnorePackages(), this.options.getSeparator(), this.options.getLines()); } /** @@ -160,9 +163,7 @@ private void formatOption(final Throwable throwable, final String suffix, final buffer.append(' '); } if (requireAdditionalFormatting(suffix)) { - ThrowableRenderer renderer = new ThrowableRenderer<>( - options.getIgnorePackages(), suffix, options.getSeparator(), options.getLines()); - renderer.renderThrowable(buffer, throwable); + renderer.renderThrowable(buffer, throwable, suffix); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 0293ef39e42..dd73a8dcd65 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -22,58 +22,60 @@ class ThrowableRenderer { protected final List ignoredPackageNames; - protected final String stackTraceElementSuffix; protected final String lineSeparator; protected final int maxLineCount; - ThrowableRenderer( - final List ignoredPackageNames, - final String stackTraceElementSuffix, - final String lineSeparator, - final int maxLineCount) { + ThrowableRenderer(final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { this.ignoredPackageNames = ignoredPackageNames; - this.stackTraceElementSuffix = stackTraceElementSuffix; this.lineSeparator = lineSeparator; this.maxLineCount = maxLineCount; } - final void renderThrowable(final StringBuilder buffer, final Throwable throwable) { + final void renderThrowable( + final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { C context = createContext(throwable); - renderThrowable(buffer, throwable, context); + renderThrowable(buffer, throwable, context, stackTraceElementSuffix); } + @SuppressWarnings("unchecked") private C createContext(final Throwable throwable) { return (C) new ThrowableRenderer.Context(); } - private void renderThrowable(final StringBuilder buffer, final Throwable throwable, final C context) { + private void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final String stackTraceElementSuffix) { renderThrowableMessage(buffer, throwable); appendSuffix(buffer, stackTraceElementSuffix); appendLineSeparator(buffer, lineSeparator); - - context.setIgnoredStackTraceElementCount(0); + context.ignoredStackTraceElementCount = 0; final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (final StackTraceElement element : stackTraceElements) { - renderStackTraceElement(buffer, element, context); + renderStackTraceElement(buffer, element, context, stackTraceElementSuffix); } - if (context.getIgnoredStackTraceElementCount() > 0) { + if (context.ignoredStackTraceElementCount > 0) { appendSuppressedCount( - buffer, context.getIgnoredStackTraceElementCount(), stackTraceElementSuffix, lineSeparator); + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); } StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } private void renderStackTraceElement( - final StringBuilder buffer, final StackTraceElement stackTraceElement, final C context) { + final StringBuilder buffer, + final StackTraceElement stackTraceElement, + final C context, + final String stackTraceElementSuffix) { if (!ignoreElement(stackTraceElement, ignoredPackageNames)) { - if (context.getIgnoredStackTraceElementCount() > 0) { + if (context.ignoredStackTraceElementCount > 0) { appendSuppressedCount( - buffer, context.getIgnoredStackTraceElementCount(), stackTraceElementSuffix, lineSeparator); - context.setIgnoredStackTraceElementCount(0); + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + context.ignoredStackTraceElementCount = 0; } appendEntry(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); } else { - context.setIgnoredStackTraceElementCount(context.getIgnoredStackTraceElementCount() + 1); + context.ignoredStackTraceElementCount += 1; } } @@ -133,14 +135,6 @@ private static void appendLineSeparator(final StringBuilder buffer, final String } static class Context { - private int ignoredStackTraceElementCount; - - public int getIgnoredStackTraceElementCount() { - return ignoredStackTraceElementCount; - } - - public void setIgnoredStackTraceElementCount(int ignoredStackTraceElementCount) { - this.ignoredStackTraceElementCount = ignoredStackTraceElementCount; - } + int ignoredStackTraceElementCount; } } From 4e89d6701d86767b3b0378007f31da78d1be3fb4 Mon Sep 17 00:00:00 2001 From: alanyu Date: Sat, 13 Jul 2024 23:28:58 +0900 Subject: [PATCH 16/72] add RootThrowableRenderer and add missing "at" --- .../RootThrowablePatternConverter.java | 33 ++-- .../core/pattern/RootThrowableRenderer.java | 146 ++++++++++++++++++ .../pattern/ThrowablePatternConverter.java | 10 +- .../log4j/core/pattern/ThrowableRenderer.java | 15 +- 4 files changed, 174 insertions(+), 30 deletions(-) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index c0529f0e53e..a5d2be3b595 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -19,7 +19,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; /** * Outputs the Throwable portion of the LoggingEvent as a full stack trace @@ -32,6 +32,7 @@ @Plugin(name = "RootThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"rEx", "rThrowable", "rException"}) public final class RootThrowablePatternConverter extends ThrowablePatternConverter { + private RootThrowableRenderer renderer; /** * Private constructor. @@ -59,25 +60,17 @@ public static RootThrowablePatternConverter newInstance(final Configuration conf * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { - final ThrowableProxy proxy = event.getThrownProxy(); - final Throwable throwable = event.getThrown(); - if (throwable != null && options.anyLines()) { - if (proxy == null) { - super.format(event, toAppendTo); - return; - } - final int len = toAppendTo.length(); - if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { - toAppendTo.append(' '); - } - proxy.formatCauseStackTraceTo( - toAppendTo, - options.getIgnorePackages(), - options.getTextRenderer(), - getSuffix(event), - options.getSeparator(), - options.getLines()); + public void format(final LogEvent event, final StringBuilder buffer) { + final int len = buffer.length(); + if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { + buffer.append(' '); } + renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); + } + + @Override + void createRenderer(final ThrowableFormatOptions options) { + this.renderer = + new RootThrowableRenderer(options.getIgnorePackages(), options.getSeparator(), options.getLines()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java new file mode 100644 index 00000000000..b4ccdf801a0 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -0,0 +1,146 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.logging.log4j.core.util.internal.StringBuilders; + +class RootThrowableRenderer extends ThrowableRenderer { + + static final String WRAPPED_BY_LABEL = "Wrapped by: "; + + RootThrowableRenderer(List ignoredPackageNames, String lineSeparator, int maxLineCount) { + super(ignoredPackageNames, lineSeparator, maxLineCount); + } + + @Override + RootContext createContext(final Throwable throwable) { + final Map map = new HashMap<>(); + final Set visited = new HashSet<>(1); + buildMap(null, throwable, map, visited); + return new RootContext(map); + } + + @Override + void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final RootContext context, + final String stackTraceElementSuffix) { + formatWrapper(buffer, throwable, context, stackTraceElementSuffix); + StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); + } + + private void formatWrapper( + final StringBuilder buffer, + final Throwable throwable, + final RootContext context, + final String stackTraceElementSuffix) { + final Throwable cause = throwable.getCause(); + if (cause != null) { + formatWrapper(buffer, throwable.getCause(), context, stackTraceElementSuffix); + buffer.append(WRAPPED_BY_LABEL); + appendSuffix(buffer, stackTraceElementSuffix); + } + renderThrowableMessage(buffer, throwable); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + formatElements(buffer, throwable, context, stackTraceElementSuffix); + } + + private void formatElements( + final StringBuilder buffer, + final Throwable throwable, + final RootContext context, + final String stackTraceElementSuffix) { + context.ignoredStackTraceElementCount = 0; + final RootContext.ThrowableMetadata metadata = context.throwableMetadataMap.get(throwable); + final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + for (int i = 0; i < metadata.stackLength; i++) { + renderStackTraceElement(buffer, stackTraceElements[i], context, stackTraceElementSuffix); + } + if (context.ignoredStackTraceElementCount > 0) { + appendSuppressedCount( + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + } + if (metadata.commonElementCount != 0) { + buffer.append("\t... "); + buffer.append(metadata.commonElementCount); + buffer.append(" more"); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + } + } + + private void buildMap( + final Throwable rootThrowable, + final Throwable throwable, + final Map map, + final Set visited) { + map.put( + throwable, + getMetadata(rootThrowable == null ? null : rootThrowable.getStackTrace(), throwable.getStackTrace())); + + Throwable throwableCause = throwable.getCause(); + if (throwableCause != null && !visited.contains(throwableCause)) { + visited.add(throwableCause); + buildMap(throwable, throwable.getCause(), map, visited); + } + } + + private RootContext.ThrowableMetadata getMetadata( + final StackTraceElement[] rootTrace, final StackTraceElement[] currentTrace) { + int commonElementCount; + int stackLength; + if (rootTrace != null) { + int rootIndex = rootTrace.length - 1; + int stackIndex = currentTrace.length - 1; + while (rootIndex >= 0 && stackIndex >= 0 && rootTrace[rootIndex].equals(currentTrace[stackIndex])) { + --rootIndex; + --stackIndex; + } + commonElementCount = currentTrace.length - 1 - stackIndex; + stackLength = stackIndex + 1; + } else { + commonElementCount = 0; + stackLength = currentTrace.length; + } + return new RootContext.ThrowableMetadata(commonElementCount, stackLength); + } + + static class RootContext extends ThrowableRenderer.Context { + public RootContext(Map throwableMetadataMap) { + this.throwableMetadataMap = throwableMetadataMap; + } + + Map throwableMetadataMap; + + static class ThrowableMetadata { + public ThrowableMetadata(int commonElementCount, int stackLength) { + this.commonElementCount = commonElementCount; + this.stackLength = stackLength; + } + + int commonElementCount; + int stackLength; + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index dfb2f4ee85d..645d9115069 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -41,7 +41,7 @@ public class ThrowablePatternConverter extends LogEventPatternConverter { private String rawOption; private final boolean subShortOption; private final boolean nonStandardLineSeparator; - private final ThrowableRenderer renderer; + private ThrowableRenderer renderer; /** * Options. @@ -82,8 +82,7 @@ protected ThrowablePatternConverter( || ThrowableFormatOptions.METHOD_NAME.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.CLASS_NAME.equalsIgnoreCase(rawOption); nonStandardLineSeparator = !Strings.LINE_SEPARATOR.equals(this.options.getSeparator()); - renderer = new ThrowableRenderer<>( - this.options.getIgnorePackages(), this.options.getSeparator(), this.options.getLines()); + createRenderer(this.options); } /** @@ -225,4 +224,9 @@ private static Function createSuffixProvider(final String suff return logEvent -> Strings.EMPTY; } } + + void createRenderer(final ThrowableFormatOptions options) { + this.renderer = + new ThrowableRenderer<>(options.getIgnorePackages(), options.getSeparator(), options.getLines()); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index dd73a8dcd65..18089ff8b98 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -38,11 +38,11 @@ final void renderThrowable( } @SuppressWarnings("unchecked") - private C createContext(final Throwable throwable) { + C createContext(final Throwable throwable) { return (C) new ThrowableRenderer.Context(); } - private void renderThrowable( + void renderThrowable( final StringBuilder buffer, final Throwable throwable, final C context, @@ -62,7 +62,7 @@ private void renderThrowable( StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } - private void renderStackTraceElement( + void renderStackTraceElement( final StringBuilder buffer, final StackTraceElement stackTraceElement, final C context, @@ -79,7 +79,7 @@ private void renderStackTraceElement( } } - private static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { + static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { final String message = throwable.getMessage(); buffer.append(throwable.getClass().getName()); if (message != null) { @@ -100,7 +100,7 @@ private static boolean ignoreElement(final StackTraceElement element, final List return false; } - private static void appendSuppressedCount( + static void appendSuppressedCount( final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { if (count == 1) { buffer.append("\t... "); @@ -118,19 +118,20 @@ private static void appendEntry( final StringBuilder buffer, final String suffix, final String lineSeparator) { + buffer.append("\tat "); buffer.append(stackTraceElement.toString()); appendSuffix(buffer, suffix); buffer.append(lineSeparator); } - private static void appendSuffix(final StringBuilder buffer, final String suffix) { + static void appendSuffix(final StringBuilder buffer, final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); buffer.append(suffix); } } - private static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { + static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { buffer.append(lineSeparator); } From 0975f5d5305ba6636136b0277d533e5d126e60d1 Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 16 Jul 2024 20:11:31 +0900 Subject: [PATCH 17/72] Fix ThrowableRenderer --- .../core/pattern/RootThrowableRenderer.java | 104 ++-------------- .../log4j/core/pattern/ThrowableRenderer.java | 115 +++++++++++++++--- 2 files changed, 109 insertions(+), 110 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index b4ccdf801a0..d846a625f5e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -16,14 +16,11 @@ */ package org.apache.logging.log4j.core.pattern; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; + import org.apache.logging.log4j.core.util.internal.StringBuilders; -class RootThrowableRenderer extends ThrowableRenderer { +class RootThrowableRenderer extends ThrowableRenderer { static final String WRAPPED_BY_LABEL = "Wrapped by: "; @@ -31,32 +28,25 @@ class RootThrowableRenderer extends ThrowableRenderer map = new HashMap<>(); - final Set visited = new HashSet<>(1); - buildMap(null, throwable, map, visited); - return new RootContext(map); - } - @Override void renderThrowable( final StringBuilder buffer, final Throwable throwable, - final RootContext context, + final Context context, final String stackTraceElementSuffix) { - formatWrapper(buffer, throwable, context, stackTraceElementSuffix); + format(buffer, throwable, context, stackTraceElementSuffix); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } - private void formatWrapper( + @Override + void format( final StringBuilder buffer, final Throwable throwable, - final RootContext context, + final Context context, final String stackTraceElementSuffix) { final Throwable cause = throwable.getCause(); if (cause != null) { - formatWrapper(buffer, throwable.getCause(), context, stackTraceElementSuffix); + format(buffer, throwable.getCause(), context, stackTraceElementSuffix); buffer.append(WRAPPED_BY_LABEL); appendSuffix(buffer, stackTraceElementSuffix); } @@ -65,82 +55,4 @@ private void formatWrapper( appendLineSeparator(buffer, lineSeparator); formatElements(buffer, throwable, context, stackTraceElementSuffix); } - - private void formatElements( - final StringBuilder buffer, - final Throwable throwable, - final RootContext context, - final String stackTraceElementSuffix) { - context.ignoredStackTraceElementCount = 0; - final RootContext.ThrowableMetadata metadata = context.throwableMetadataMap.get(throwable); - final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); - for (int i = 0; i < metadata.stackLength; i++) { - renderStackTraceElement(buffer, stackTraceElements[i], context, stackTraceElementSuffix); - } - if (context.ignoredStackTraceElementCount > 0) { - appendSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); - } - if (metadata.commonElementCount != 0) { - buffer.append("\t... "); - buffer.append(metadata.commonElementCount); - buffer.append(" more"); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); - } - } - - private void buildMap( - final Throwable rootThrowable, - final Throwable throwable, - final Map map, - final Set visited) { - map.put( - throwable, - getMetadata(rootThrowable == null ? null : rootThrowable.getStackTrace(), throwable.getStackTrace())); - - Throwable throwableCause = throwable.getCause(); - if (throwableCause != null && !visited.contains(throwableCause)) { - visited.add(throwableCause); - buildMap(throwable, throwable.getCause(), map, visited); - } - } - - private RootContext.ThrowableMetadata getMetadata( - final StackTraceElement[] rootTrace, final StackTraceElement[] currentTrace) { - int commonElementCount; - int stackLength; - if (rootTrace != null) { - int rootIndex = rootTrace.length - 1; - int stackIndex = currentTrace.length - 1; - while (rootIndex >= 0 && stackIndex >= 0 && rootTrace[rootIndex].equals(currentTrace[stackIndex])) { - --rootIndex; - --stackIndex; - } - commonElementCount = currentTrace.length - 1 - stackIndex; - stackLength = stackIndex + 1; - } else { - commonElementCount = 0; - stackLength = currentTrace.length; - } - return new RootContext.ThrowableMetadata(commonElementCount, stackLength); - } - - static class RootContext extends ThrowableRenderer.Context { - public RootContext(Map throwableMetadataMap) { - this.throwableMetadataMap = throwableMetadataMap; - } - - Map throwableMetadataMap; - - static class ThrowableMetadata { - public ThrowableMetadata(int commonElementCount, int stackLength) { - this.commonElementCount = commonElementCount; - this.stackLength = stackLength; - } - - int commonElementCount; - int stackLength; - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 18089ff8b98..95ba78b2f88 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -16,11 +16,13 @@ */ package org.apache.logging.log4j.core.pattern; -import java.util.List; +import java.util.*; + import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; class ThrowableRenderer { + static final String CAUSED_BY_LABEL = "Caused by: "; protected final List ignoredPackageNames; protected final String lineSeparator; protected final int maxLineCount; @@ -39,7 +41,10 @@ final void renderThrowable( @SuppressWarnings("unchecked") C createContext(final Throwable throwable) { - return (C) new ThrowableRenderer.Context(); + final Map map = new HashMap<>(); + final Set visited = new HashSet<>(1); + buildMap(null, throwable, map, visited); + return (C) new Context(map); } void renderThrowable( @@ -47,18 +52,7 @@ void renderThrowable( final Throwable throwable, final C context, final String stackTraceElementSuffix) { - renderThrowableMessage(buffer, throwable); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); - context.ignoredStackTraceElementCount = 0; - final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); - for (final StackTraceElement element : stackTraceElements) { - renderStackTraceElement(buffer, element, context, stackTraceElementSuffix); - } - if (context.ignoredStackTraceElementCount > 0) { - appendSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); - } + format(buffer, throwable, context, stackTraceElementSuffix); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @@ -88,6 +82,47 @@ static void renderThrowableMessage(final StringBuilder buffer, final Throwable t } } + void format( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final String stackTraceElementSuffix) { + renderThrowableMessage(buffer, throwable); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + formatElements(buffer, throwable, context, stackTraceElementSuffix); + final Throwable cause = throwable.getCause(); + if (cause != null) { + buffer.append(CAUSED_BY_LABEL); + appendSuffix(buffer, stackTraceElementSuffix); + format(buffer, throwable.getCause(), context, stackTraceElementSuffix); + } + } + + void formatElements( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final String stackTraceElementSuffix) { + context.ignoredStackTraceElementCount = 0; + final Context.ThrowableMetadata metadata = context.throwableMetadataMap.get(throwable); + final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + for (int i = 0; i < metadata.stackLength; i++) { + renderStackTraceElement(buffer, stackTraceElements[i], context, stackTraceElementSuffix); + } + if (context.ignoredStackTraceElementCount > 0) { + appendSuppressedCount( + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + } + if (metadata.commonElementCount != 0) { + buffer.append("\t... "); + buffer.append(metadata.commonElementCount); + buffer.append(" more"); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + } + } + private static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); @@ -135,7 +170,59 @@ static void appendLineSeparator(final StringBuilder buffer, final String lineSep buffer.append(lineSeparator); } + private void buildMap( + final Throwable rootThrowable, + final Throwable throwable, + final Map map, + final Set visited) { + map.put( + throwable, + getMetadata(rootThrowable == null ? null : rootThrowable.getStackTrace(), throwable.getStackTrace())); + + Throwable throwableCause = throwable.getCause(); + if (throwableCause != null && !visited.contains(throwableCause)) { + visited.add(throwableCause); + buildMap(throwable, throwable.getCause(), map, visited); + } + } + + private Context.ThrowableMetadata getMetadata( + final StackTraceElement[] rootTrace, final StackTraceElement[] currentTrace) { + int commonElementCount; + int stackLength; + if (rootTrace != null) { + int rootIndex = rootTrace.length - 1; + int stackIndex = currentTrace.length - 1; + while (rootIndex >= 0 && stackIndex >= 0 && rootTrace[rootIndex].equals(currentTrace[stackIndex])) { + --rootIndex; + --stackIndex; + } + commonElementCount = currentTrace.length - 1 - stackIndex; + stackLength = stackIndex + 1; + } else { + commonElementCount = 0; + stackLength = currentTrace.length; + } + return new Context.ThrowableMetadata(commonElementCount, stackLength); + } + static class Context { int ignoredStackTraceElementCount; + Map throwableMetadataMap; + + public Context(Map throwableMetadataMap) { + this.ignoredStackTraceElementCount = 0; + this.throwableMetadataMap = throwableMetadataMap; + } + + static class ThrowableMetadata { + public ThrowableMetadata(int commonElementCount, int stackLength) { + this.commonElementCount = commonElementCount; + this.stackLength = stackLength; + } + + int commonElementCount; + int stackLength; + } } } From cf28898e8088621e8f7119297894ae1ad6766c7f Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 16 Jul 2024 20:28:23 +0900 Subject: [PATCH 18/72] Remove redundant method --- .../log4j/core/pattern/RootThrowableRenderer.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index d846a625f5e..e557d681b0c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -28,16 +28,6 @@ class RootThrowableRenderer extends ThrowableRenderer super(ignoredPackageNames, lineSeparator, maxLineCount); } - @Override - void renderThrowable( - final StringBuilder buffer, - final Throwable throwable, - final Context context, - final String stackTraceElementSuffix) { - format(buffer, throwable, context, stackTraceElementSuffix); - StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); - } - @Override void format( final StringBuilder buffer, From ca14ed1bf35f85ef25ab9368ecfd693fec14414f Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 16 Jul 2024 20:42:09 +0900 Subject: [PATCH 19/72] Merge methods --- .../core/pattern/RootThrowableRenderer.java | 8 ++--- .../log4j/core/pattern/ThrowableRenderer.java | 32 +++++++------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index e557d681b0c..595656d6e78 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -18,8 +18,6 @@ import java.util.List; -import org.apache.logging.log4j.core.util.internal.StringBuilders; - class RootThrowableRenderer extends ThrowableRenderer { static final String WRAPPED_BY_LABEL = "Wrapped by: "; @@ -29,20 +27,20 @@ class RootThrowableRenderer extends ThrowableRenderer } @Override - void format( + void renderThrowable( final StringBuilder buffer, final Throwable throwable, final Context context, final String stackTraceElementSuffix) { final Throwable cause = throwable.getCause(); if (cause != null) { - format(buffer, throwable.getCause(), context, stackTraceElementSuffix); + renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); buffer.append(WRAPPED_BY_LABEL); appendSuffix(buffer, stackTraceElementSuffix); } renderThrowableMessage(buffer, throwable); appendSuffix(buffer, stackTraceElementSuffix); appendLineSeparator(buffer, lineSeparator); - formatElements(buffer, throwable, context, stackTraceElementSuffix); + formatStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 95ba78b2f88..7fd5042a2d2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -37,6 +37,7 @@ final void renderThrowable( final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { C context = createContext(throwable); renderThrowable(buffer, throwable, context, stackTraceElementSuffix); + StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @SuppressWarnings("unchecked") @@ -52,8 +53,16 @@ void renderThrowable( final Throwable throwable, final C context, final String stackTraceElementSuffix) { - format(buffer, throwable, context, stackTraceElementSuffix); - StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); + renderThrowableMessage(buffer, throwable); + appendSuffix(buffer, stackTraceElementSuffix); + appendLineSeparator(buffer, lineSeparator); + formatStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + final Throwable cause = throwable.getCause(); + if (cause != null) { + buffer.append(CAUSED_BY_LABEL); + appendSuffix(buffer, stackTraceElementSuffix); + renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); + } } void renderStackTraceElement( @@ -82,24 +91,7 @@ static void renderThrowableMessage(final StringBuilder buffer, final Throwable t } } - void format( - final StringBuilder buffer, - final Throwable throwable, - final C context, - final String stackTraceElementSuffix) { - renderThrowableMessage(buffer, throwable); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); - formatElements(buffer, throwable, context, stackTraceElementSuffix); - final Throwable cause = throwable.getCause(); - if (cause != null) { - buffer.append(CAUSED_BY_LABEL); - appendSuffix(buffer, stackTraceElementSuffix); - format(buffer, throwable.getCause(), context, stackTraceElementSuffix); - } - } - - void formatElements( + void formatStackTraceElements( final StringBuilder buffer, final Throwable throwable, final C context, From ca8ab050779fc4ab2ab6a80da42fa0ac925b3a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 16 Jul 2024 21:38:34 +0200 Subject: [PATCH 20/72] Visibility related cosmetic changes to `ThrowableRender` (#2691) --- .../core/pattern/RootThrowableRenderer.java | 14 +- .../log4j/core/pattern/ThrowableRenderer.java | 179 ++++++++++-------- 2 files changed, 111 insertions(+), 82 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 595656d6e78..3f78e79b06c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -18,11 +18,11 @@ import java.util.List; -class RootThrowableRenderer extends ThrowableRenderer { +final class RootThrowableRenderer extends ThrowableRenderer { - static final String WRAPPED_BY_LABEL = "Wrapped by: "; + private static final String WRAPPED_BY_LABEL = "Wrapped by: "; - RootThrowableRenderer(List ignoredPackageNames, String lineSeparator, int maxLineCount) { + RootThrowableRenderer(final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { super(ignoredPackageNames, lineSeparator, maxLineCount); } @@ -36,11 +36,11 @@ void renderThrowable( if (cause != null) { renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); buffer.append(WRAPPED_BY_LABEL); - appendSuffix(buffer, stackTraceElementSuffix); + renderSuffix(buffer, stackTraceElementSuffix); } renderThrowableMessage(buffer, throwable); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); - formatStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + renderSuffix(buffer, stackTraceElementSuffix); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 7fd5042a2d2..48519907375 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -22,10 +22,14 @@ import org.apache.logging.log4j.util.Strings; class ThrowableRenderer { - static final String CAUSED_BY_LABEL = "Caused by: "; - protected final List ignoredPackageNames; - protected final String lineSeparator; - protected final int maxLineCount; + + private static final String CAUSED_BY_LABEL = "Caused by: "; + + final List ignoredPackageNames; + + final String lineSeparator; + + final int maxLineCount; ThrowableRenderer(final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { this.ignoredPackageNames = ignoredPackageNames; @@ -42,10 +46,8 @@ final void renderThrowable( @SuppressWarnings("unchecked") C createContext(final Throwable throwable) { - final Map map = new HashMap<>(); - final Set visited = new HashSet<>(1); - buildMap(null, throwable, map, visited); - return (C) new Context(map); + final Map metadataByThrowable = Context.Metadata.ofThrowable(throwable); + return (C) new Context(0, metadataByThrowable); } void renderThrowable( @@ -54,13 +56,13 @@ void renderThrowable( final C context, final String stackTraceElementSuffix) { renderThrowableMessage(buffer, throwable); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); - formatStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + renderSuffix(buffer, stackTraceElementSuffix); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); final Throwable cause = throwable.getCause(); if (cause != null) { buffer.append(CAUSED_BY_LABEL); - appendSuffix(buffer, stackTraceElementSuffix); + renderSuffix(buffer, stackTraceElementSuffix); renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); } } @@ -70,13 +72,14 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final C context, final String stackTraceElementSuffix) { - if (!ignoreElement(stackTraceElement, ignoredPackageNames)) { + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + if (!stackTraceElementIgnored) { if (context.ignoredStackTraceElementCount > 0) { - appendSuppressedCount( + renderSuppressedCount( buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); context.ignoredStackTraceElementCount = 0; } - appendEntry(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); + renderStackTraceElement(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); } else { context.ignoredStackTraceElementCount += 1; } @@ -91,35 +94,35 @@ static void renderThrowableMessage(final StringBuilder buffer, final Throwable t } } - void formatStackTraceElements( + void renderStackTraceElements( final StringBuilder buffer, final Throwable throwable, final C context, final String stackTraceElementSuffix) { context.ignoredStackTraceElementCount = 0; - final Context.ThrowableMetadata metadata = context.throwableMetadataMap.get(throwable); + final Context.Metadata metadata = context.metadataByThrowable.get(throwable); final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (int i = 0; i < metadata.stackLength; i++) { renderStackTraceElement(buffer, stackTraceElements[i], context, stackTraceElementSuffix); } if (context.ignoredStackTraceElementCount > 0) { - appendSuppressedCount( + renderSuppressedCount( buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); } if (metadata.commonElementCount != 0) { buffer.append("\t... "); buffer.append(metadata.commonElementCount); buffer.append(" more"); - appendSuffix(buffer, stackTraceElementSuffix); - appendLineSeparator(buffer, lineSeparator); + renderSuffix(buffer, stackTraceElementSuffix); + buffer.append(lineSeparator); } } - private static boolean ignoreElement(final StackTraceElement element, final List ignorePackages) { + private static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); - for (final String pkg : ignorePackages) { - if (className.startsWith(pkg)) { + for (final String ignoredPackage : ignorePackages) { + if (className.startsWith(ignoredPackage)) { return true; } } @@ -127,7 +130,7 @@ private static boolean ignoreElement(final StackTraceElement element, final List return false; } - static void appendSuppressedCount( + private static void renderSuppressedCount( final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { if (count == 1) { buffer.append("\t... "); @@ -136,85 +139,111 @@ static void appendSuppressedCount( buffer.append(count); buffer.append(" lines"); } - appendSuffix(buffer, suffix); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } - private static void appendEntry( + private static void renderStackTraceElement( final StackTraceElement stackTraceElement, final StringBuilder buffer, final String suffix, final String lineSeparator) { buffer.append("\tat "); buffer.append(stackTraceElement.toString()); - appendSuffix(buffer, suffix); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } - static void appendSuffix(final StringBuilder buffer, final String suffix) { + static void renderSuffix(final StringBuilder buffer, final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); buffer.append(suffix); } } - static void appendLineSeparator(final StringBuilder buffer, final String lineSeparator) { - buffer.append(lineSeparator); - } + static class Context { - private void buildMap( - final Throwable rootThrowable, - final Throwable throwable, - final Map map, - final Set visited) { - map.put( - throwable, - getMetadata(rootThrowable == null ? null : rootThrowable.getStackTrace(), throwable.getStackTrace())); - - Throwable throwableCause = throwable.getCause(); - if (throwableCause != null && !visited.contains(throwableCause)) { - visited.add(throwableCause); - buildMap(throwable, throwable.getCause(), map, visited); - } - } + /** + * Number of stack trace elements ignored. + *

+ * This value will be reset per {@link Throwable} in the causal chain. + *

+ */ + int ignoredStackTraceElementCount; - private Context.ThrowableMetadata getMetadata( - final StackTraceElement[] rootTrace, final StackTraceElement[] currentTrace) { - int commonElementCount; - int stackLength; - if (rootTrace != null) { - int rootIndex = rootTrace.length - 1; - int stackIndex = currentTrace.length - 1; - while (rootIndex >= 0 && stackIndex >= 0 && rootTrace[rootIndex].equals(currentTrace[stackIndex])) { - --rootIndex; - --stackIndex; - } - commonElementCount = currentTrace.length - 1 - stackIndex; - stackLength = stackIndex + 1; - } else { - commonElementCount = 0; - stackLength = currentTrace.length; + /** + * {@link Metadata} per {@link Throwable} in the causal chain + */ + final Map metadataByThrowable; + + /** + * The canonical constructor. + */ + Context(final int ignoredStackTraceElementCount, final Map metadataByThrowable) { + this.ignoredStackTraceElementCount = ignoredStackTraceElementCount; + this.metadataByThrowable = metadataByThrowable; } - return new Context.ThrowableMetadata(commonElementCount, stackLength); - } - static class Context { - int ignoredStackTraceElementCount; - Map throwableMetadataMap; + /** + * Invariants associated with a {@link Throwable} + */ + final static class Metadata { - public Context(Map throwableMetadataMap) { - this.ignoredStackTraceElementCount = 0; - this.throwableMetadataMap = throwableMetadataMap; - } + /** + * Number of stack trace elements shared with the parent {@link Throwable}'s stack + */ + final int commonElementCount; + + /** + * Number of stack trace elements exclusive to this {@link Throwable}, i.e., not in common with the parent {@link Throwable}'s stack + */ + final int stackLength; - static class ThrowableMetadata { - public ThrowableMetadata(int commonElementCount, int stackLength) { + private Metadata(final int commonElementCount, final int stackLength) { this.commonElementCount = commonElementCount; this.stackLength = stackLength; } - int commonElementCount; - int stackLength; + static Map ofThrowable(final Throwable throwable) { + final Map metadataByThrowable = new HashMap<>(); + populateMetadata(metadataByThrowable, new HashSet<>(), null, throwable); + return metadataByThrowable; + } + + private static void populateMetadata( + final Map metadataByThrowable, + final Set visitedThrowables, + final Throwable parentThrowable, + final Throwable throwable) { + final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); + final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); + metadataByThrowable.put(throwable, metadata); + final Throwable cause = throwable.getCause(); + if (cause != null && !visitedThrowables.contains(cause)) { + visitedThrowables.add(cause); + populateMetadata(metadataByThrowable, visitedThrowables, throwable, cause); + } + } + + private static Metadata populateMetadata( + final StackTraceElement[] parentTrace, final StackTraceElement[] currentTrace) { + int commonElementCount; + int stackLength; + if (parentTrace != null) { + int parentIndex = parentTrace.length - 1; + int currentIndex = currentTrace.length - 1; + while (parentIndex >= 0 && currentIndex >= 0 && parentTrace[parentIndex].equals(currentTrace[currentIndex])) { + --parentIndex; + --currentIndex; + } + commonElementCount = currentTrace.length - 1 - currentIndex; + stackLength = currentIndex + 1; + } else { + commonElementCount = 0; + stackLength = currentTrace.length; + } + return new Metadata(commonElementCount, stackLength); + } } } } From 7e57942946140b3b0cdeb86fd6d36a21a2fc88a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 16 Jul 2024 21:42:49 +0200 Subject: [PATCH 21/72] Arrange method order in `ThrowableRender` (#2691) --- .../log4j/core/pattern/ThrowableRenderer.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 48519907375..05bfd1730fb 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -67,24 +67,6 @@ void renderThrowable( } } - void renderStackTraceElement( - final StringBuilder buffer, - final StackTraceElement stackTraceElement, - final C context, - final String stackTraceElementSuffix) { - final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); - if (!stackTraceElementIgnored) { - if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); - context.ignoredStackTraceElementCount = 0; - } - renderStackTraceElement(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); - } else { - context.ignoredStackTraceElementCount += 1; - } - } - static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { final String message = throwable.getMessage(); buffer.append(throwable.getClass().getName()); @@ -118,6 +100,35 @@ void renderStackTraceElements( } } + void renderStackTraceElement( + final StringBuilder buffer, + final StackTraceElement stackTraceElement, + final C context, + final String stackTraceElementSuffix) { + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + if (!stackTraceElementIgnored) { + if (context.ignoredStackTraceElementCount > 0) { + renderSuppressedCount( + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + context.ignoredStackTraceElementCount = 0; + } + renderStackTraceElement(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); + } else { + context.ignoredStackTraceElementCount += 1; + } + } + + private static void renderStackTraceElement( + final StackTraceElement stackTraceElement, + final StringBuilder buffer, + final String suffix, + final String lineSeparator) { + buffer.append("\tat "); + buffer.append(stackTraceElement.toString()); + renderSuffix(buffer, suffix); + buffer.append(lineSeparator); + } + private static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); @@ -143,17 +154,6 @@ private static void renderSuppressedCount( buffer.append(lineSeparator); } - private static void renderStackTraceElement( - final StackTraceElement stackTraceElement, - final StringBuilder buffer, - final String suffix, - final String lineSeparator) { - buffer.append("\tat "); - buffer.append(stackTraceElement.toString()); - renderSuffix(buffer, suffix); - buffer.append(lineSeparator); - } - static void renderSuffix(final StringBuilder buffer, final String suffix) { if (Strings.isNotBlank(suffix)) { buffer.append(' '); From ce80b72ffec51168e4924e50a91f0c942385cf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 17 Jul 2024 17:03:12 +0200 Subject: [PATCH 22/72] First (untested) draft of `ExtendedThrowableRenderer` (#2691) --- .../log4j/core/pattern/ClassResourceInfo.java | 92 +++++++++ .../pattern/ExtendedThrowableRenderer.java | 184 ++++++++++++++++++ .../log4j/core/pattern/ThrowableRenderer.java | 37 ++-- 3 files changed, 293 insertions(+), 20 deletions(-) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassResourceInfo.java create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassResourceInfo.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassResourceInfo.java new file mode 100644 index 00000000000..a01d1bc5e63 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassResourceInfo.java @@ -0,0 +1,92 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.net.URL; +import java.security.CodeSource; + +/** + * Resource information (i.e., the enclosing JAR file and its version) of a class. + */ +final class ClassResourceInfo { + + static final ClassResourceInfo UNKNOWN = new ClassResourceInfo(); + + private final String text; + + final Class clazz; + + /** + * Constructs an instance modelling an unknown class resource. + */ + private ClassResourceInfo() { + this.text = "~[?:?]"; + this.clazz = null; + } + + /** + * @param clazz the class + * @param exact {@code true}, if the class was obtained via reflection; {@code false}, otherwise + */ + ClassResourceInfo(final Class clazz, final boolean exact) { + this.clazz = clazz; + this.text = getText(clazz, exact); + } + + private static String getText(final Class clazz, final boolean exact) { + final String exactnessPrefix = exact ? "" : "~"; + final String location = getLocation(clazz); + final String version = getVersion(clazz); + return String.format("%s[%s:%s]", exactnessPrefix, location, version); + } + + private static String getLocation(final Class clazz) { + try { + final CodeSource source = clazz.getProtectionDomain().getCodeSource(); + if (source != null) { + final URL locationUrl = source.getLocation(); + if (locationUrl != null) { + final String normalizedLocationUrl = locationUrl.toString().replace('\\', '/'); + int separatorIndex = normalizedLocationUrl.lastIndexOf("/"); + if (separatorIndex >= 0 && separatorIndex == normalizedLocationUrl.length() - 1) { + separatorIndex = normalizedLocationUrl.lastIndexOf("/", separatorIndex - 1); + } + return normalizedLocationUrl.substring(separatorIndex + 1); + } + } + } catch (final Exception ignored) { + // Do nothing + } + return "?"; + } + + private static String getVersion(final Class clazz) { + final Package classPackage = clazz.getPackage(); + if (classPackage != null) { + final String version = classPackage.getImplementationVersion(); + if (version != null) { + return version; + } + } + return "?"; + } + + @Override + public String toString() { + return text; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java new file mode 100644 index 00000000000..b7d6ca6c829 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -0,0 +1,184 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.logging.log4j.util.LoaderUtil; +import org.apache.logging.log4j.util.StackLocatorUtil; + +final class ExtendedThrowableRenderer extends ThrowableRenderer { + + ExtendedThrowableRenderer( + final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { + super(ignoredPackageNames, lineSeparator, maxLineCount); + } + + @Override + ExtendedContext createContext(final Throwable throwable) { + return ExtendedContext.ofThrowable(throwable); + } + + @Override + void renderStackTraceElement( + final StringBuilder buffer, + final StackTraceElement stackTraceElement, + final ExtendedContext context, + final String stackTraceElementSuffix) { + + // Short-circuit on ignored stack trace elements + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + if (stackTraceElementIgnored) { + context.ignoredStackTraceElementCount += 1; + return; + } + + // Render the stack trace element + if (context.ignoredStackTraceElementCount > 0) { + renderSuppressedCount( + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + context.ignoredStackTraceElementCount = 0; + } + buffer.append("\tat "); + buffer.append(stackTraceElement.toString()); + final ClassResourceInfo classResourceInfo = + context.classResourceInfoByName.get(stackTraceElement.getClassName()); + if (classResourceInfo != null) { + buffer.append(' '); + buffer.append(classResourceInfo); + } + renderSuffix(buffer, stackTraceElementSuffix); + buffer.append(lineSeparator); + } + + static final class ExtendedContext extends ThrowableRenderer.Context { + + private final Map classResourceInfoByName; + + private ExtendedContext( + final int ignoredStackTraceElementCount, + final Map metadataByThrowable, + final Map classResourceInfoByName) { + super(ignoredStackTraceElementCount, metadataByThrowable); + this.classResourceInfoByName = classResourceInfoByName; + } + + private static ExtendedContext ofThrowable(final Throwable throwable) { + final Map metadataByThrowable = Metadata.ofThrowable(throwable); + final Map classResourceInfoByName = + createClassResourceInfoByName(throwable, metadataByThrowable); + return new ExtendedContext(0, metadataByThrowable, classResourceInfoByName); + } + + private static Map createClassResourceInfoByName( + final Throwable rootThrowable, final Map metadataByThrowable) { + + // Stack trace elements of a `Throwable` only contain the class name. + // But we need the associated `Class` to extract its resource information, i.e., JAR file and version. + // We are capturing the current stack to find suitable class loaders. + // We will use this as a bootstrap to go from a class names in a stack trace to a `Class`. + final Map classResourceInfoByName = + StackLocatorUtil.getCurrentStackTrace().stream() + .collect(Collectors.toMap(Class::getName, clazz -> new ClassResourceInfo(clazz, true))); + + // Walk over the causal chain + final Set visitedThrowables = new HashSet<>(); + final Queue pendingThrowables = new ArrayDeque<>(Collections.singleton(rootThrowable)); + Throwable throwable; + while ((throwable = pendingThrowables.poll()) != null && visitedThrowables.add(throwable)) { + + // Add the cause to the processing queue + final Throwable cause = throwable.getCause(); + if (cause != null) { + pendingThrowables.offer(cause); + } + + // Short-circuit if there are no associated metadata + final Metadata metadata = metadataByThrowable.get(throwable); + if (metadata == null) { + continue; + } + + ClassLoader lastLoader = null; + final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + for (int throwableStackIndex = metadata.stackLength - 1; + throwableStackIndex >= 0; + --throwableStackIndex) { + + // Skip if the current class name is either known, or already visited and is unknown + final StackTraceElement stackTraceElement = stackTraceElements[throwableStackIndex]; + final String stackTraceElementClassName = stackTraceElement.getClassName(); + ClassResourceInfo classResourceInfo = classResourceInfoByName.get(stackTraceElementClassName); + if (classResourceInfo != null) { + if (classResourceInfo.clazz != null) { + lastLoader = classResourceInfo.clazz.getClassLoader(); + } + continue; + } + + // Try to determine the stack trace element class, and register the result to the lookup table + final Class stackTraceElementClass = loadClass(lastLoader, stackTraceElementClassName); + classResourceInfo = stackTraceElementClass != null + ? new ClassResourceInfo(stackTraceElementClass, false) + : ClassResourceInfo.UNKNOWN; + classResourceInfoByName.put(stackTraceElementClassName, classResourceInfo); + } + } + return classResourceInfoByName; + } + + @FunctionalInterface + private interface ThrowingSupplier { + + V supply() throws Exception; + } + + private static Class loadClass(final ClassLoader loader, final String className) { + return Stream.>>of( + // 1. Try the passed class loader + () -> loader != null ? loader.loadClass(className) : null, + // 2. Try the `LoaderUtil` magic + () -> LoaderUtil.loadClass(className), + // 3. Try the current class loader + () -> ExtendedThrowableRenderer.class + .getClassLoader() + .loadClass(className)) + .map(provider -> { + try { + final Class clazz = provider.supply(); + if (clazz != null) { + return clazz; + } + } catch (final Exception ignored) { + // Do nothing + } + return null; + }) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 05bfd1730fb..743b9f96034 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.pattern; import java.util.*; - import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; @@ -105,31 +104,27 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final C context, final String stackTraceElementSuffix) { + + // Short-circuit on ignored stack trace elements final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); - if (!stackTraceElementIgnored) { - if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); - context.ignoredStackTraceElementCount = 0; - } - renderStackTraceElement(stackTraceElement, buffer, stackTraceElementSuffix, lineSeparator); - } else { + if (stackTraceElementIgnored) { context.ignoredStackTraceElementCount += 1; + return; } - } - private static void renderStackTraceElement( - final StackTraceElement stackTraceElement, - final StringBuilder buffer, - final String suffix, - final String lineSeparator) { + // Render the stack trace element + if (context.ignoredStackTraceElementCount > 0) { + renderSuppressedCount( + buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + context.ignoredStackTraceElementCount = 0; + } buffer.append("\tat "); buffer.append(stackTraceElement.toString()); - renderSuffix(buffer, suffix); + renderSuffix(buffer, stackTraceElementSuffix); buffer.append(lineSeparator); } - private static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { + static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { if (ignorePackages != null) { final String className = element.getClassName(); for (final String ignoredPackage : ignorePackages) { @@ -141,7 +136,7 @@ private static boolean isStackTraceElementIgnored(final StackTraceElement elemen return false; } - private static void renderSuppressedCount( + static void renderSuppressedCount( final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { if (count == 1) { buffer.append("\t... "); @@ -187,7 +182,7 @@ static class Context { /** * Invariants associated with a {@link Throwable} */ - final static class Metadata { + static final class Metadata { /** * Number of stack trace elements shared with the parent {@link Throwable}'s stack @@ -232,7 +227,9 @@ private static Metadata populateMetadata( if (parentTrace != null) { int parentIndex = parentTrace.length - 1; int currentIndex = currentTrace.length - 1; - while (parentIndex >= 0 && currentIndex >= 0 && parentTrace[parentIndex].equals(currentTrace[currentIndex])) { + while (parentIndex >= 0 + && currentIndex >= 0 + && parentTrace[parentIndex].equals(currentTrace[currentIndex])) { --parentIndex; --currentIndex; } From 4962f435085babcbd790426138ca71b244d74e6c Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 19 Jul 2024 00:31:46 +0900 Subject: [PATCH 23/72] Fix import --- .../logging/log4j/core/pattern/ThrowableRenderer.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 743b9f96034..f8923a7be2c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -16,7 +16,11 @@ */ package org.apache.logging.log4j.core.pattern; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; From 44d6c51be7b9285424fed8b5f206992a6a51490d Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 8 Aug 2024 22:42:44 +0900 Subject: [PATCH 24/72] add render about suppressedThrowables --- .../log4j/core/pattern/ThrowableRenderer.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index f8923a7be2c..4829c7cae24 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -28,6 +28,8 @@ class ThrowableRenderer { private static final String CAUSED_BY_LABEL = "Caused by: "; + private static final String SUPPRESSED_LABEL = "Suppressed: "; + final List ignoredPackageNames; final String lineSeparator; @@ -62,6 +64,16 @@ void renderThrowable( renderSuffix(buffer, stackTraceElementSuffix); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + + final Throwable[] suppressedThrowables = throwable.getSuppressed(); + if (suppressedThrowables != null && suppressedThrowables.length != 0) { + buffer.append(SUPPRESSED_LABEL); + renderSuffix(buffer, stackTraceElementSuffix); + for (final Throwable suppresedThrowable : suppressedThrowables) { + renderThrowable(buffer, suppresedThrowable, context, stackTraceElementSuffix); + } + } + final Throwable cause = throwable.getCause(); if (cause != null) { buffer.append(CAUSED_BY_LABEL); From 54c8e2bb316edc3cae906d432f9efbce28411f04 Mon Sep 17 00:00:00 2001 From: alanyu Date: Fri, 9 Aug 2024 00:02:40 +0900 Subject: [PATCH 25/72] update for %xEx --- .../pattern/ExtendedThrowableRenderer.java | 52 +++++++++++++++++++ .../log4j/core/pattern/ThrowableRenderer.java | 13 +---- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index b7d6ca6c829..b1010d9770c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -31,6 +31,9 @@ final class ExtendedThrowableRenderer extends ThrowableRenderer { + private static final String SUPPRESSED_LABEL = "Suppressed: "; + private static final String TAB = "\t"; + ExtendedThrowableRenderer( final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { super(ignoredPackageNames, lineSeparator, maxLineCount); @@ -73,6 +76,55 @@ void renderStackTraceElement( buffer.append(lineSeparator); } + @Override + void renderThrowable( + StringBuilder buffer, Throwable throwable, ExtendedContext context, String stackTraceElementSuffix) { + renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); + } + + void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final ExtendedContext context, + final String stackTraceElementSuffix, + final String prefix, + final String label) { + if (throwable == null) { + return; + } + buffer.append(prefix); + buffer.append(label); + renderThrowableMessage(buffer, throwable); + renderSuffix(buffer, stackTraceElementSuffix); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + renderSuppressedThrowables(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); + renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); + } + + private void renderSuppressedThrowables( + final StringBuilder buffer, + final Throwable[] suppressedThrowables, + final ExtendedContext context, + final String stackTraceElementSuffix, + final String prefix) { + if (suppressedThrowables == null) { + return; + } + for (final Throwable suppressedThrowable : suppressedThrowables) { + renderThrowable(buffer, suppressedThrowable, context, stackTraceElementSuffix, prefix, SUPPRESSED_LABEL); + } + } + + private void renderCause( + final StringBuilder buffer, + final Throwable cause, + final ExtendedContext context, + final String stackTraceElementSuffix, + final String prefix) { + renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, CAUSED_BY_LABEL); + } + static final class ExtendedContext extends ThrowableRenderer.Context { private final Map classResourceInfoByName; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 4829c7cae24..2e2098f66c5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -26,9 +26,7 @@ class ThrowableRenderer { - private static final String CAUSED_BY_LABEL = "Caused by: "; - - private static final String SUPPRESSED_LABEL = "Suppressed: "; + static final String CAUSED_BY_LABEL = "Caused by: "; final List ignoredPackageNames; @@ -65,15 +63,6 @@ void renderThrowable( buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); - final Throwable[] suppressedThrowables = throwable.getSuppressed(); - if (suppressedThrowables != null && suppressedThrowables.length != 0) { - buffer.append(SUPPRESSED_LABEL); - renderSuffix(buffer, stackTraceElementSuffix); - for (final Throwable suppresedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppresedThrowable, context, stackTraceElementSuffix); - } - } - final Throwable cause = throwable.getCause(); if (cause != null) { buffer.append(CAUSED_BY_LABEL); From 8bf1d29a63fda7fc35a1892f77c9c29853d04300 Mon Sep 17 00:00:00 2001 From: alanyu Date: Mon, 12 Aug 2024 12:44:40 +0900 Subject: [PATCH 26/72] update render --- .../pattern/ExtendedThrowableRenderer.java | 55 +--------------- .../core/pattern/RootThrowableRenderer.java | 28 ++++++--- .../log4j/core/pattern/ThrowableRenderer.java | 62 ++++++++++++++----- 3 files changed, 70 insertions(+), 75 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index b1010d9770c..c3379cf59fa 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -31,9 +31,6 @@ final class ExtendedThrowableRenderer extends ThrowableRenderer { - private static final String SUPPRESSED_LABEL = "Suppressed: "; - private static final String TAB = "\t"; - ExtendedThrowableRenderer( final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { super(ignoredPackageNames, lineSeparator, maxLineCount); @@ -49,6 +46,7 @@ void renderStackTraceElement( final StringBuilder buffer, final StackTraceElement stackTraceElement, final ExtendedContext context, + final String prefix, final String stackTraceElementSuffix) { // Short-circuit on ignored stack trace elements @@ -61,7 +59,7 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append("\tat "); @@ -76,55 +74,6 @@ void renderStackTraceElement( buffer.append(lineSeparator); } - @Override - void renderThrowable( - StringBuilder buffer, Throwable throwable, ExtendedContext context, String stackTraceElementSuffix) { - renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); - } - - void renderThrowable( - final StringBuilder buffer, - final Throwable throwable, - final ExtendedContext context, - final String stackTraceElementSuffix, - final String prefix, - final String label) { - if (throwable == null) { - return; - } - buffer.append(prefix); - buffer.append(label); - renderThrowableMessage(buffer, throwable); - renderSuffix(buffer, stackTraceElementSuffix); - buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); - renderSuppressedThrowables(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); - renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); - } - - private void renderSuppressedThrowables( - final StringBuilder buffer, - final Throwable[] suppressedThrowables, - final ExtendedContext context, - final String stackTraceElementSuffix, - final String prefix) { - if (suppressedThrowables == null) { - return; - } - for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppressedThrowable, context, stackTraceElementSuffix, prefix, SUPPRESSED_LABEL); - } - } - - private void renderCause( - final StringBuilder buffer, - final Throwable cause, - final ExtendedContext context, - final String stackTraceElementSuffix, - final String prefix) { - renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, CAUSED_BY_LABEL); - } - static final class ExtendedContext extends ThrowableRenderer.Context { private final Map classResourceInfoByName; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 3f78e79b06c..6d233bd1c54 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -31,16 +31,28 @@ void renderThrowable( final StringBuilder buffer, final Throwable throwable, final Context context, - final String stackTraceElementSuffix) { - final Throwable cause = throwable.getCause(); + final String stackTraceElementSuffix, + final String prefix, + final String caption) { + renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); + buffer.append(prefix); + buffer.append(caption); + renderThrowableMessage(buffer, throwable); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); + renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); + } + + @Override + void renderCause( + final StringBuilder buffer, + final Throwable cause, + final Context context, + final String stackTraceElementSuffix, + final String prefix) { if (cause != null) { - renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); + renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, ""); buffer.append(WRAPPED_BY_LABEL); - renderSuffix(buffer, stackTraceElementSuffix); } - renderThrowableMessage(buffer, throwable); - renderSuffix(buffer, stackTraceElementSuffix); - buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 2e2098f66c5..6867a309ab9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -26,7 +26,9 @@ class ThrowableRenderer { - static final String CAUSED_BY_LABEL = "Caused by: "; + private static final String CAUSED_BY_CAPTION = "Caused by: "; + private static final String SUPPRESSED_CAPTION = "Suppressed: "; + static final String TAB = "\t"; final List ignoredPackageNames; @@ -43,7 +45,7 @@ class ThrowableRenderer { final void renderThrowable( final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { C context = createContext(throwable); - renderThrowable(buffer, throwable, context, stackTraceElementSuffix); + renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @@ -57,17 +59,37 @@ void renderThrowable( final StringBuilder buffer, final Throwable throwable, final C context, - final String stackTraceElementSuffix) { + final String stackTraceElementSuffix, + final String prefix, + final String caption) { + buffer.append(prefix); + buffer.append(caption); renderThrowableMessage(buffer, throwable); - renderSuffix(buffer, stackTraceElementSuffix); buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, stackTraceElementSuffix); + renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); + renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); + renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); + } + + void renderSuppressed( + final StringBuilder buffer, + final Throwable[] suppressedThrowables, + final C context, + final String stackTraceElementSuffix, + final String prefix) { + for (final Throwable suppressedThrowable : suppressedThrowables) { + renderThrowable(buffer, suppressedThrowable, context, stackTraceElementSuffix, prefix, SUPPRESSED_CAPTION); + } + } - final Throwable cause = throwable.getCause(); + void renderCause( + final StringBuilder buffer, + final Throwable cause, + final C context, + final String stackTraceElementSuffix, + final String prefix) { if (cause != null) { - buffer.append(CAUSED_BY_LABEL); - renderSuffix(buffer, stackTraceElementSuffix); - renderThrowable(buffer, throwable.getCause(), context, stackTraceElementSuffix); + renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, CAUSED_BY_CAPTION); } } @@ -84,18 +106,20 @@ void renderStackTraceElements( final StringBuilder buffer, final Throwable throwable, final C context, + final String prefix, final String stackTraceElementSuffix) { context.ignoredStackTraceElementCount = 0; final Context.Metadata metadata = context.metadataByThrowable.get(throwable); final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (int i = 0; i < metadata.stackLength; i++) { - renderStackTraceElement(buffer, stackTraceElements[i], context, stackTraceElementSuffix); + renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, stackTraceElementSuffix); } if (context.ignoredStackTraceElementCount > 0) { renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); } if (metadata.commonElementCount != 0) { + buffer.append(prefix); buffer.append("\t... "); buffer.append(metadata.commonElementCount); buffer.append(" more"); @@ -108,6 +132,7 @@ void renderStackTraceElement( final StringBuilder buffer, final StackTraceElement stackTraceElement, final C context, + final String prefix, final String stackTraceElementSuffix) { // Short-circuit on ignored stack trace elements @@ -120,9 +145,10 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, stackTraceElementSuffix, lineSeparator); + buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } + buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); renderSuffix(buffer, stackTraceElementSuffix); @@ -142,7 +168,8 @@ static boolean isStackTraceElementIgnored(final StackTraceElement element, final } static void renderSuppressedCount( - final StringBuilder buffer, final int count, final String suffix, final String lineSeparator) { + final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { + buffer.append(prefix); if (count == 1) { buffer.append("\t... "); } else { @@ -150,7 +177,6 @@ static void renderSuppressedCount( buffer.append(count); buffer.append(" lines"); } - renderSuffix(buffer, suffix); buffer.append(lineSeparator); } @@ -218,6 +244,14 @@ private static void populateMetadata( final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); metadataByThrowable.put(throwable, metadata); + + for (final Throwable suppressed : throwable.getSuppressed()) { + if (!visitedThrowables.contains(suppressed)) { + visitedThrowables.add(suppressed); + populateMetadata(metadataByThrowable, visitedThrowables, throwable, suppressed); + } + } + final Throwable cause = throwable.getCause(); if (cause != null && !visitedThrowables.contains(cause)) { visitedThrowables.add(cause); From 2ec0bc4c635e43c7f95dfc17113a23f6e3762e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 09:57:29 +0200 Subject: [PATCH 27/72] Inline `TAB` --- .../logging/log4j/core/pattern/RootThrowableRenderer.java | 2 +- .../apache/logging/log4j/core/pattern/ThrowableRenderer.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 6d233bd1c54..eb2856f3463 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -40,7 +40,7 @@ void renderThrowable( renderThrowableMessage(buffer, throwable); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); + renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + '\t'); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 6867a309ab9..004c3d61466 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -27,8 +27,8 @@ class ThrowableRenderer { private static final String CAUSED_BY_CAPTION = "Caused by: "; + private static final String SUPPRESSED_CAPTION = "Suppressed: "; - static final String TAB = "\t"; final List ignoredPackageNames; @@ -67,7 +67,7 @@ void renderThrowable( renderThrowableMessage(buffer, throwable); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + TAB); + renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + '\t'); renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); } From 1b16ec1fb1215b80c7d0477c4b9ccdf2cebd799f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 10:06:48 +0200 Subject: [PATCH 28/72] Add comments --- .../apache/logging/log4j/core/pattern/ThrowableRenderer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 004c3d61466..03096989815 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -241,10 +241,13 @@ private static void populateMetadata( final Set visitedThrowables, final Throwable parentThrowable, final Throwable throwable) { + + // Populate metadata of the current throwable final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); metadataByThrowable.put(throwable, metadata); + // Populate metadata of suppressed exceptions for (final Throwable suppressed : throwable.getSuppressed()) { if (!visitedThrowables.contains(suppressed)) { visitedThrowables.add(suppressed); @@ -252,6 +255,7 @@ private static void populateMetadata( } } + // Populate metadata of the causal chain final Throwable cause = throwable.getCause(); if (cause != null && !visitedThrowables.contains(cause)) { visitedThrowables.add(cause); From 75e24b57b73e67879d7b20fda539e64497d116e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 10:11:07 +0200 Subject: [PATCH 29/72] Rename `WRAPPED_BY_LABEL` to `WRAPPED_BY_CAPTION` --- .../logging/log4j/core/pattern/RootThrowableRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index eb2856f3463..f92f9858a50 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -20,7 +20,7 @@ final class RootThrowableRenderer extends ThrowableRenderer { - private static final String WRAPPED_BY_LABEL = "Wrapped by: "; + private static final String WRAPPED_BY_CAPTION = "Wrapped by: "; RootThrowableRenderer(final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { super(ignoredPackageNames, lineSeparator, maxLineCount); @@ -52,7 +52,7 @@ void renderCause( final String prefix) { if (cause != null) { renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, ""); - buffer.append(WRAPPED_BY_LABEL); + buffer.append(WRAPPED_BY_CAPTION); } } } From b4630b92834cb75d066683352362cf54f777bd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 10:15:43 +0200 Subject: [PATCH 30/72] Make `ThrowableRenderer` more strict --- .../apache/logging/log4j/core/pattern/ThrowableRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 03096989815..1e48f47b62b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -71,7 +71,7 @@ void renderThrowable( renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); } - void renderSuppressed( + final void renderSuppressed( final StringBuilder buffer, final Throwable[] suppressedThrowables, final C context, @@ -102,7 +102,7 @@ static void renderThrowableMessage(final StringBuilder buffer, final Throwable t } } - void renderStackTraceElements( + final void renderStackTraceElements( final StringBuilder buffer, final Throwable throwable, final C context, From cf55e42587893cbcd8700afa6e3ab3a686b382c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 11:29:30 +0200 Subject: [PATCH 31/72] Fix stack trace indentation in `ExtendedThrowableRenderer` --- .../logging/log4j/core/pattern/ExtendedThrowableRenderer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index c3379cf59fa..1756f69e54d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -62,6 +62,7 @@ void renderStackTraceElement( buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } + buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); final ClassResourceInfo classResourceInfo = From a3ccf352dc7a0d3264059939460f200244cb1fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 11:29:51 +0200 Subject: [PATCH 32/72] Fix map key conflict in `ExtendedThrowableRenderer` --- .../log4j/core/pattern/ExtendedThrowableRenderer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index 1756f69e54d..15155ec0a5d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -100,10 +100,13 @@ private static Map createClassResourceInfoByName( // Stack trace elements of a `Throwable` only contain the class name. // But we need the associated `Class` to extract its resource information, i.e., JAR file and version. // We are capturing the current stack to find suitable class loaders. - // We will use this as a bootstrap to go from a class names in a stack trace to a `Class`. + // We will use this as a bootstrap to go from a class name in a stack trace to a `Class`. final Map classResourceInfoByName = StackLocatorUtil.getCurrentStackTrace().stream() - .collect(Collectors.toMap(Class::getName, clazz -> new ClassResourceInfo(clazz, true))); + .collect(Collectors.toMap( + Class::getName, + clazz -> new ClassResourceInfo(clazz, true), + (classResourceInfo1, classResourceInfo2) -> classResourceInfo1)); // Walk over the causal chain final Set visitedThrowables = new HashSet<>(); From 91e6110db6a5b0c1dd3f6cb7722b1cbb3d479fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 11:30:02 +0200 Subject: [PATCH 33/72] Fix Spotless failures --- .../log4j/core/pattern/ExtendedThrowableRenderer.java | 3 +-- .../logging/log4j/core/pattern/ThrowableRenderer.java | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index 15155ec0a5d..99e75cb1264 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -58,8 +58,7 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 1e48f47b62b..69aae1673de 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -115,8 +115,7 @@ final void renderStackTraceElements( renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, stackTraceElementSuffix); } if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); } if (metadata.commonElementCount != 0) { buffer.append(prefix); @@ -144,8 +143,7 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount( - buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); From f91620afc27edb8e9453def006bb38e0b7f3fe0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 12 Aug 2024 11:42:45 +0200 Subject: [PATCH 34/72] Add `ThrowableTestMain` test application --- .../log4j/core/pattern/ThrowableTestMain.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java new file mode 100644 index 00000000000..dc18dc7b23f --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java @@ -0,0 +1,57 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.util.Collections; + +public class ThrowableTestMain { + + public static void main(String[] args) { + Throwable r = createException("r", 1, 3); + renderException(r, null); + renderException( + r, + new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException( + r, + new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException( + r, + new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + } + + private static Throwable createException(String name, int depth, int maxDepth) { + Exception r = new Exception(name); + if (depth < maxDepth) { + r.initCause(createException(name + "_c", depth + 1, maxDepth)); + r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); + } + return r; + } + + private static void renderException(Throwable throwable, ThrowableRenderer renderer) { + if (renderer == null) { + System.out.format("%n=== %-25s ==============================%n%n", "Throwable"); + throwable.printStackTrace(); + } else { + System.out.format("%n=== %-25s ==============================%n%n", renderer.getClass().getSimpleName()); + final StringBuilder stringBuilder = new StringBuilder(); + renderer.renderThrowable(stringBuilder, throwable, ""); + System.out.println(stringBuilder); + } + } +} From 7d9e87bd9baba3ea45c66cd734e3268f338d5f70 Mon Sep 17 00:00:00 2001 From: alanyu Date: Mon, 12 Aug 2024 23:42:28 +0900 Subject: [PATCH 35/72] fix rEx --- .../core/pattern/RootThrowableRenderer.java | 30 +++++++++++++++---- .../log4j/core/pattern/ThrowableRenderer.java | 15 ++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index f92f9858a50..8eb5c915ec4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -27,16 +27,17 @@ final class RootThrowableRenderer extends ThrowableRenderer { private static final String CAUSED_BY_CAPTION = "Caused by: "; - private static final String SUPPRESSED_CAPTION = "Suppressed: "; + static final String SUPPRESSED_CAPTION = "Suppressed: "; final List ignoredPackageNames; @@ -45,7 +45,7 @@ class ThrowableRenderer { final void renderThrowable( final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { C context = createContext(throwable); - renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); + renderThrowable(buffer, throwable, context, stackTraceElementSuffix); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @@ -56,6 +56,15 @@ C createContext(final Throwable throwable) { } void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final String stackTraceElementSuffix) + { + renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); + } + + private void renderThrowable( final StringBuilder buffer, final Throwable throwable, final C context, @@ -71,7 +80,7 @@ void renderThrowable( renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); } - final void renderSuppressed( + void renderSuppressed( final StringBuilder buffer, final Throwable[] suppressedThrowables, final C context, From 4b5325ae9846515a67c335e76df4b70694abde22 Mon Sep 17 00:00:00 2001 From: alanyu Date: Mon, 12 Aug 2024 23:45:33 +0900 Subject: [PATCH 36/72] fix formatting --- .../core/pattern/RootThrowableRenderer.java | 16 ++++++++++------ .../log4j/core/pattern/ThrowableRenderer.java | 3 +-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 8eb5c915ec4..c043084ccab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -27,7 +27,11 @@ final class RootThrowableRenderer extends ThrowableRenderer Date: Mon, 12 Aug 2024 17:15:28 +0200 Subject: [PATCH 37/72] Update `ThrowableTestMain` --- .../log4j/core/pattern/ThrowableTestMain.java | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java index dc18dc7b23f..842061e838d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java @@ -17,21 +17,22 @@ package org.apache.logging.log4j.core.pattern; import java.util.Collections; +import java.util.List; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; public class ThrowableTestMain { public static void main(String[] args) { Throwable r = createException("r", 1, 3); - renderException(r, null); + renderException(r); + renderException(r, new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException(r, "%ex"); renderException( - r, - new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException(r, "%xEx"); renderException( - r, - new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); - renderException( - r, - new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException(r, "%rEx"); } private static Throwable createException(String name, int depth, int maxDepth) { @@ -43,15 +44,31 @@ private static Throwable createException(String name, int depth, int maxDepth) { return r; } + private static void renderException(Throwable throwable) { + System.out.format("%n=== %-25s ==============================%n%n", "Throwable"); + throwable.printStackTrace(System.out); + } + private static void renderException(Throwable throwable, ThrowableRenderer renderer) { - if (renderer == null) { - System.out.format("%n=== %-25s ==============================%n%n", "Throwable"); - throwable.printStackTrace(); - } else { - System.out.format("%n=== %-25s ==============================%n%n", renderer.getClass().getSimpleName()); - final StringBuilder stringBuilder = new StringBuilder(); - renderer.renderThrowable(stringBuilder, throwable, ""); - System.out.println(stringBuilder); + System.out.format( + "%n=== %-25s ==============================%n%n", + renderer.getClass().getSimpleName()); + final StringBuilder stringBuilder = new StringBuilder(); + renderer.renderThrowable(stringBuilder, throwable, ""); + System.out.println(stringBuilder); + } + + private static void renderException(Throwable throwable, String pattern) { + System.out.format("%n=== %-25s ==============================%n%n", String.format("pattern(\"%s\")", pattern)); + PatternParser parser = new PatternParser(PatternConverter.CATEGORY); + List formatters = parser.parse(pattern); + if (formatters.size() != 1) { + throw new IllegalArgumentException("was expecting a single formatter, found " + formatters.size()); } + PatternFormatter formatter = formatters.get(0); + Log4jLogEvent logEvent = Log4jLogEvent.newBuilder().setThrown(throwable).build(); + StringBuilder stringBuilder = new StringBuilder(); + formatter.format(logEvent, stringBuilder); + System.out.println(stringBuilder); } } From ede1cd91a9af9073e9bde8a290b3b27b03a482ea Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 13 Aug 2024 20:07:13 +0900 Subject: [PATCH 38/72] add visited for rendering --- .../core/pattern/RootThrowableRenderer.java | 21 ++++++++++---- .../log4j/core/pattern/ThrowableRenderer.java | 29 +++++++++++++++---- .../log4j/core/pattern/ThrowableTestMain.java | 14 ++++----- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index c043084ccab..34da8f61022 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -17,6 +17,7 @@ package org.apache.logging.log4j.core.pattern; import java.util.List; +import java.util.Set; final class RootThrowableRenderer extends ThrowableRenderer { @@ -31,21 +32,28 @@ void renderThrowable( final StringBuilder buffer, final Throwable throwable, final Context context, + final Set visitedThrowables, final String stackTraceElementSuffix) { - renderThrowable(buffer, throwable, context, stackTraceElementSuffix, ""); + renderThrowable(buffer, throwable, context, visitedThrowables, stackTraceElementSuffix, ""); } private void renderThrowable( final StringBuilder buffer, final Throwable throwable, final Context context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix) { - renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); + if (visitedThrowables.contains(throwable)) { + return; + } + visitedThrowables.add(throwable); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, stackTraceElementSuffix, prefix); renderThrowableMessage(buffer, throwable); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + '\t'); + renderSuppressed( + buffer, throwable.getSuppressed(), context, visitedThrowables, stackTraceElementSuffix, prefix + '\t'); } @Override @@ -53,10 +61,11 @@ void renderCause( final StringBuilder buffer, final Throwable cause, final Context context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix) { if (cause != null) { - renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix); + renderThrowable(buffer, cause, context, visitedThrowables, stackTraceElementSuffix, prefix); buffer.append(prefix); buffer.append(WRAPPED_BY_CAPTION); } @@ -67,13 +76,15 @@ void renderSuppressed( final StringBuilder buffer, final Throwable[] suppressedThrowables, final Context context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix) { if (suppressedThrowables != null && suppressedThrowables.length != 0) { buffer.append(prefix); buffer.append(SUPPRESSED_CAPTION); for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppressedThrowable, context, stackTraceElementSuffix, prefix); + renderThrowable( + buffer, suppressedThrowable, context, visitedThrowables, stackTraceElementSuffix, prefix); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index b169c325343..c05ca80771f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -45,7 +45,7 @@ class ThrowableRenderer { final void renderThrowable( final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { C context = createContext(throwable); - renderThrowable(buffer, throwable, context, stackTraceElementSuffix); + renderThrowable(buffer, throwable, context, new HashSet<>(), stackTraceElementSuffix); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @@ -59,34 +59,49 @@ void renderThrowable( final StringBuilder buffer, final Throwable throwable, final C context, + final Set visitedThrowables, final String stackTraceElementSuffix) { - renderThrowable(buffer, throwable, context, stackTraceElementSuffix, "", ""); + renderThrowable(buffer, throwable, context, visitedThrowables, stackTraceElementSuffix, "", ""); } private void renderThrowable( final StringBuilder buffer, final Throwable throwable, final C context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix, final String caption) { + if (visitedThrowables.contains(throwable)) { + return; + } + visitedThrowables.add(throwable); buffer.append(prefix); buffer.append(caption); renderThrowableMessage(buffer, throwable); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, stackTraceElementSuffix, prefix + '\t'); - renderCause(buffer, throwable.getCause(), context, stackTraceElementSuffix, prefix); + renderSuppressed( + buffer, throwable.getSuppressed(), context, visitedThrowables, stackTraceElementSuffix, prefix + '\t'); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, stackTraceElementSuffix, prefix); } void renderSuppressed( final StringBuilder buffer, final Throwable[] suppressedThrowables, final C context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix) { for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppressedThrowable, context, stackTraceElementSuffix, prefix, SUPPRESSED_CAPTION); + renderThrowable( + buffer, + suppressedThrowable, + context, + visitedThrowables, + stackTraceElementSuffix, + prefix, + SUPPRESSED_CAPTION); } } @@ -94,10 +109,12 @@ void renderCause( final StringBuilder buffer, final Throwable cause, final C context, + final Set visitedThrowables, final String stackTraceElementSuffix, final String prefix) { if (cause != null) { - renderThrowable(buffer, cause, context, stackTraceElementSuffix, prefix, CAUSED_BY_CAPTION); + renderThrowable( + buffer, cause, context, visitedThrowables, stackTraceElementSuffix, prefix, CAUSED_BY_CAPTION); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java index dc18dc7b23f..fdb2d219c6f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java @@ -23,15 +23,11 @@ public class ThrowableTestMain { public static void main(String[] args) { Throwable r = createException("r", 1, 3); renderException(r, null); + renderException(r, new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); renderException( - r, - new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); renderException( - r, - new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); - renderException( - r, - new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); } private static Throwable createException(String name, int depth, int maxDepth) { @@ -48,7 +44,9 @@ private static void renderException(Throwable throwable, ThrowableRenderer re System.out.format("%n=== %-25s ==============================%n%n", "Throwable"); throwable.printStackTrace(); } else { - System.out.format("%n=== %-25s ==============================%n%n", renderer.getClass().getSimpleName()); + System.out.format( + "%n=== %-25s ==============================%n%n", + renderer.getClass().getSimpleName()); final StringBuilder stringBuilder = new StringBuilder(); renderer.renderThrowable(stringBuilder, throwable, ""); System.out.println(stringBuilder); From bd4e2f2905b0875211d7012b1dc8d1c1349f49d7 Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 13 Aug 2024 20:20:16 +0900 Subject: [PATCH 39/72] set %xEx using ExtendedThrowableRenderer --- .../ExtendedThrowablePatternConverter.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index 6c2944e123f..4287719e0d0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -19,7 +19,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; /** * Outputs the Throwable portion of the LoggingEvent as a full stack trace @@ -32,6 +32,7 @@ @Plugin(name = "ExtendedThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"xEx", "xThrowable", "xException"}) public final class ExtendedThrowablePatternConverter extends ThrowablePatternConverter { + private ExtendedThrowableRenderer renderer; /** * Private constructor. @@ -59,25 +60,17 @@ public static ExtendedThrowablePatternConverter newInstance(final Configuration * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { - final ThrowableProxy proxy = event.getThrownProxy(); - final Throwable throwable = event.getThrown(); - if ((throwable != null || proxy != null) && options.anyLines()) { - if (proxy == null) { - super.format(event, toAppendTo); - return; - } - final int len = toAppendTo.length(); - if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { - toAppendTo.append(' '); - } - proxy.formatExtendedStackTraceTo( - toAppendTo, - options.getIgnorePackages(), - options.getTextRenderer(), - getSuffix(event), - options.getSeparator(), - options.getLines()); + public void format(final LogEvent event, final StringBuilder buffer) { + final int len = buffer.length(); + if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { + buffer.append(' '); } + renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); + } + + @Override + void createRenderer(final ThrowableFormatOptions options) { + this.renderer = + new ExtendedThrowableRenderer(options.getIgnorePackages(), options.getSeparator(), options.getLines()); } } From c489190bab7f9ce74b3a23d0aec4bd7b8e8bdd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 13 Aug 2024 14:36:33 +0200 Subject: [PATCH 40/72] Fix `bnd-baseline` failures --- .../logging/log4j/core/impl/package-info.java | 2 +- .../pattern/ThrowablePatternConverter.java | 57 +++++++++++-------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java index c50504a8726..0c3b08f43a7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java @@ -18,7 +18,7 @@ * Log4j 2 private implementation classes. */ @Export -@Version("2.23.0") +@Version("2.24.0") package org.apache.logging.log4j.core.impl; import org.osgi.annotation.bundle.Export; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 645d9115069..f5cf83c5e45 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -19,6 +19,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.Function; import org.apache.logging.log4j.core.LogEvent; @@ -37,15 +38,25 @@ @Plugin(name = "ThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"ex", "throwable", "exception"}) public class ThrowablePatternConverter extends LogEventPatternConverter { + + /** + * Returns the list of formatters used to render the suffix. + * + * @deprecated Kept for binary backward compatibility. + */ + @Deprecated + protected final List formatters; + private final Function suffixProvider; + private String rawOption; + private final boolean subShortOption; + private final boolean nonStandardLineSeparator; + private ThrowableRenderer renderer; - /** - * Options. - */ protected final ThrowableFormatOptions options; /** @@ -74,7 +85,9 @@ protected ThrowablePatternConverter( if (options != null && options.length > 0) { rawOption = options[0]; } - this.suffixProvider = createSuffixProvider(this.options.getSuffix(), config); + final List suffixFormatters = new ArrayList<>(); + this.suffixProvider = createSuffixProvider(this.options.getSuffix(), config, suffixFormatters); + this.formatters = Collections.unmodifiableList(suffixFormatters); subShortOption = ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.FILE_NAME.equalsIgnoreCase(rawOption) @@ -190,36 +203,30 @@ private boolean requireAdditionalFormatting(final String suffix) { return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); } - private static Function createSuffixProvider(final String suffix, final Configuration config) { + private static Function createSuffixProvider( + final String suffix, final Configuration config, final List suffixFormatters) { if (suffix != null) { + + // Suffix is allowed to be a Pattern Layout conversion pattern, hence we need to parse it final PatternParser parser = PatternLayout.createPatternParser(config); final List parsedSuffixFormatters = parser.parse(suffix); - // filter out nested formatters that will handle throwable - boolean hasThrowableSuffixFormatter = false; + + // Collect formatters excluding ones handling throwables for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { - if (suffixFormatter.handlesThrowable()) { - hasThrowableSuffixFormatter = true; + if (!suffixFormatter.handlesThrowable()) { + suffixFormatters.add(suffixFormatter); } } - List finalFormatters; - if (!hasThrowableSuffixFormatter) { - finalFormatters = parsedSuffixFormatters; - } else { - final List suffixFormatters = new ArrayList<>(); - for (final PatternFormatter suffixFormatter : parsedSuffixFormatters) { - if (!suffixFormatter.handlesThrowable()) { - suffixFormatters.add(suffixFormatter); - } - } - finalFormatters = suffixFormatters; - } + + // Create the lambda accepting a `LogEvent` to invoke collected formatters return logEvent -> { - final StringBuilder toAppendTo = new StringBuilder(); - for (int i = 0, size = finalFormatters.size(); i < size; i++) { - finalFormatters.get(i).format(logEvent, toAppendTo); + final StringBuilder buffer = new StringBuilder(); + for (PatternFormatter suffixFormatter : suffixFormatters) { + suffixFormatter.format(logEvent, buffer); } - return toAppendTo.toString(); + return buffer.toString(); }; + } else { return logEvent -> Strings.EMPTY; } From 2afc7fa943bb72f03eb7dc08377950b090e37ed3 Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 13 Aug 2024 23:26:58 +0900 Subject: [PATCH 41/72] fix tests and add suffix for every line --- ...ExtendedThrowablePatternConverterTest.java | 6 +-- .../ExtendedThrowablePatternConverter.java | 10 ++-- .../pattern/ExtendedThrowableRenderer.java | 6 +-- .../RootThrowablePatternConverter.java | 10 ++-- .../core/pattern/RootThrowableRenderer.java | 29 +++++----- .../log4j/core/pattern/ThrowableRenderer.java | 54 +++++++++---------- 6 files changed, 56 insertions(+), 59 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java index efeead57e50..af38e52e16a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java @@ -29,7 +29,6 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; @@ -104,15 +103,12 @@ public void testSuffixWillIgnoreThrowablePattern() { public void testDeserializedLogEventWithThrowableProxyButNoThrowable() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, null); final Throwable originalThrowable = new Exception("something bad happened"); - final ThrowableProxy throwableProxy = new ThrowableProxy(originalThrowable); - final Throwable deserializedThrowable = null; final Log4jLogEvent event = Log4jLogEvent.newBuilder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("")) // - .setThrown(deserializedThrowable) // - .setThrownProxy(throwableProxy) // + .setThrown(originalThrowable) // .setTimeMillis(0) .build(); final StringBuilder sb = new StringBuilder(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index 4287719e0d0..a139c0dced8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -61,11 +61,13 @@ public static ExtendedThrowablePatternConverter newInstance(final Configuration */ @Override public void format(final LogEvent event, final StringBuilder buffer) { - final int len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { - buffer.append(' '); + if (event.getThrown() != null && options.anyLines()) { + final int len = buffer.length(); + if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { + buffer.append(' '); + } + renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); } - renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index 99e75cb1264..20d0474ca19 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -47,7 +47,7 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final ExtendedContext context, final String prefix, - final String stackTraceElementSuffix) { + final String suffix) { // Short-circuit on ignored stack trace elements final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); @@ -58,7 +58,7 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); @@ -70,7 +70,7 @@ void renderStackTraceElement( buffer.append(' '); buffer.append(classResourceInfo); } - renderSuffix(buffer, stackTraceElementSuffix); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index a5d2be3b595..119f22354d5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -61,11 +61,13 @@ public static RootThrowablePatternConverter newInstance(final Configuration conf */ @Override public void format(final LogEvent event, final StringBuilder buffer) { - final int len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { - buffer.append(' '); + if (event.getThrown() != null && options.anyLines()) { + final int len = buffer.length(); + if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { + buffer.append(' '); + } + renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); } - renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 34da8f61022..56b62b19404 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -33,8 +33,8 @@ void renderThrowable( final Throwable throwable, final Context context, final Set visitedThrowables, - final String stackTraceElementSuffix) { - renderThrowable(buffer, throwable, context, visitedThrowables, stackTraceElementSuffix, ""); + final String suffix) { + renderThrowable(buffer, throwable, context, visitedThrowables, "", suffix); } private void renderThrowable( @@ -42,18 +42,18 @@ private void renderThrowable( final Throwable throwable, final Context context, final Set visitedThrowables, - final String stackTraceElementSuffix, - final String prefix) { + final String prefix, + final String suffix) { if (visitedThrowables.contains(throwable)) { return; } visitedThrowables.add(throwable); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, stackTraceElementSuffix, prefix); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, suffix); renderThrowableMessage(buffer, throwable); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed( - buffer, throwable.getSuppressed(), context, visitedThrowables, stackTraceElementSuffix, prefix + '\t'); + renderStackTraceElements(buffer, throwable, context, prefix, suffix); + renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', suffix); } @Override @@ -62,10 +62,10 @@ void renderCause( final Throwable cause, final Context context, final Set visitedThrowables, - final String stackTraceElementSuffix, - final String prefix) { + final String prefix, + final String suffix) { if (cause != null) { - renderThrowable(buffer, cause, context, visitedThrowables, stackTraceElementSuffix, prefix); + renderThrowable(buffer, cause, context, visitedThrowables, prefix, suffix); buffer.append(prefix); buffer.append(WRAPPED_BY_CAPTION); } @@ -77,14 +77,13 @@ void renderSuppressed( final Throwable[] suppressedThrowables, final Context context, final Set visitedThrowables, - final String stackTraceElementSuffix, - final String prefix) { + final String prefix, + final String suffix) { if (suppressedThrowables != null && suppressedThrowables.length != 0) { buffer.append(prefix); buffer.append(SUPPRESSED_CAPTION); for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable( - buffer, suppressedThrowable, context, visitedThrowables, stackTraceElementSuffix, prefix); + renderThrowable(buffer, suppressedThrowable, context, visitedThrowables, prefix, suffix); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index c05ca80771f..5bc4586dfef 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -60,8 +60,8 @@ void renderThrowable( final Throwable throwable, final C context, final Set visitedThrowables, - final String stackTraceElementSuffix) { - renderThrowable(buffer, throwable, context, visitedThrowables, stackTraceElementSuffix, "", ""); + final String suffix) { + renderThrowable(buffer, throwable, context, visitedThrowables, "", suffix, ""); } private void renderThrowable( @@ -69,8 +69,8 @@ private void renderThrowable( final Throwable throwable, final C context, final Set visitedThrowables, - final String stackTraceElementSuffix, final String prefix, + final String suffix, final String caption) { if (visitedThrowables.contains(throwable)) { return; @@ -79,11 +79,11 @@ private void renderThrowable( buffer.append(prefix); buffer.append(caption); renderThrowableMessage(buffer, throwable); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, stackTraceElementSuffix); - renderSuppressed( - buffer, throwable.getSuppressed(), context, visitedThrowables, stackTraceElementSuffix, prefix + '\t'); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, stackTraceElementSuffix, prefix); + renderStackTraceElements(buffer, throwable, context, prefix, suffix); + renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', suffix); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, suffix); } void renderSuppressed( @@ -91,17 +91,11 @@ void renderSuppressed( final Throwable[] suppressedThrowables, final C context, final Set visitedThrowables, - final String stackTraceElementSuffix, - final String prefix) { + final String prefix, + final String suffix) { for (final Throwable suppressedThrowable : suppressedThrowables) { renderThrowable( - buffer, - suppressedThrowable, - context, - visitedThrowables, - stackTraceElementSuffix, - prefix, - SUPPRESSED_CAPTION); + buffer, suppressedThrowable, context, visitedThrowables, prefix, suffix, SUPPRESSED_CAPTION); } } @@ -110,11 +104,10 @@ void renderCause( final Throwable cause, final C context, final Set visitedThrowables, - final String stackTraceElementSuffix, - final String prefix) { + final String prefix, + final String suffix) { if (cause != null) { - renderThrowable( - buffer, cause, context, visitedThrowables, stackTraceElementSuffix, prefix, CAUSED_BY_CAPTION); + renderThrowable(buffer, cause, context, visitedThrowables, prefix, suffix, CAUSED_BY_CAPTION); } } @@ -132,22 +125,22 @@ final void renderStackTraceElements( final Throwable throwable, final C context, final String prefix, - final String stackTraceElementSuffix) { + final String suffix) { context.ignoredStackTraceElementCount = 0; final Context.Metadata metadata = context.metadataByThrowable.get(throwable); final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (int i = 0; i < metadata.stackLength; i++) { - renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, stackTraceElementSuffix); + renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, suffix); } if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); } if (metadata.commonElementCount != 0) { buffer.append(prefix); buffer.append("\t... "); buffer.append(metadata.commonElementCount); buffer.append(" more"); - renderSuffix(buffer, stackTraceElementSuffix); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } } @@ -157,7 +150,7 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final C context, final String prefix, - final String stackTraceElementSuffix) { + final String suffix) { // Short-circuit on ignored stack trace elements final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); @@ -168,13 +161,13 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); - renderSuffix(buffer, stackTraceElementSuffix); + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } @@ -191,7 +184,11 @@ static boolean isStackTraceElementIgnored(final StackTraceElement element, final } static void renderSuppressedCount( - final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { + final StringBuilder buffer, + final int count, + final String prefix, + final String suffix, + final String lineSeparator) { buffer.append(prefix); if (count == 1) { buffer.append("\t... "); @@ -200,6 +197,7 @@ static void renderSuppressedCount( buffer.append(count); buffer.append(" lines"); } + renderSuffix(buffer, suffix); buffer.append(lineSeparator); } From 0d6aedc8170c389c23b47badfd99be90a9fba55a Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 15 Aug 2024 00:30:50 +0900 Subject: [PATCH 42/72] update suffix and separator --- .../ExtendedThrowablePatternConverter.java | 5 +- .../pattern/ExtendedThrowableRenderer.java | 9 ++-- .../RootThrowablePatternConverter.java | 5 +- .../core/pattern/RootThrowableRenderer.java | 25 +++++---- .../pattern/ThrowablePatternConverter.java | 39 ++++++++++---- .../log4j/core/pattern/ThrowableRenderer.java | 52 +++++++------------ .../log4j/core/pattern/ThrowableTestMain.java | 8 +-- 7 files changed, 71 insertions(+), 72 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index a139c0dced8..43d6af76188 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -66,13 +66,12 @@ public void format(final LogEvent event, final StringBuilder buffer) { if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { buffer.append(' '); } - renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); + renderer.renderThrowable(buffer, event.getThrown(), getLineSeparator(event)); } } @Override void createRenderer(final ThrowableFormatOptions options) { - this.renderer = - new ExtendedThrowableRenderer(options.getIgnorePackages(), options.getSeparator(), options.getLines()); + this.renderer = new ExtendedThrowableRenderer(options.getIgnorePackages(), options.getLines()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index 20d0474ca19..1ec4d80a6c2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -32,8 +32,8 @@ final class ExtendedThrowableRenderer extends ThrowableRenderer { ExtendedThrowableRenderer( - final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { - super(ignoredPackageNames, lineSeparator, maxLineCount); + final List ignoredPackageNames, final int maxLineCount) { + super(ignoredPackageNames, maxLineCount); } @Override @@ -47,7 +47,7 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final ExtendedContext context, final String prefix, - final String suffix) { + final String lineSeparator) { // Short-circuit on ignored stack trace elements final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); @@ -58,7 +58,7 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); @@ -70,7 +70,6 @@ void renderStackTraceElement( buffer.append(' '); buffer.append(classResourceInfo); } - renderSuffix(buffer, suffix); buffer.append(lineSeparator); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index 119f22354d5..777dfaa331a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -66,13 +66,12 @@ public void format(final LogEvent event, final StringBuilder buffer) { if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { buffer.append(' '); } - renderer.renderThrowable(buffer, event.getThrown(), getSuffix(event)); + renderer.renderThrowable(buffer, event.getThrown(), getLineSeparator(event)); } } @Override void createRenderer(final ThrowableFormatOptions options) { - this.renderer = - new RootThrowableRenderer(options.getIgnorePackages(), options.getSeparator(), options.getLines()); + this.renderer = new RootThrowableRenderer(options.getIgnorePackages(), options.getLines()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java index 56b62b19404..17e36738f3b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java @@ -23,8 +23,8 @@ final class RootThrowableRenderer extends ThrowableRenderer ignoredPackageNames, final String lineSeparator, final int maxLineCount) { - super(ignoredPackageNames, lineSeparator, maxLineCount); + RootThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { + super(ignoredPackageNames, maxLineCount); } @Override @@ -33,8 +33,8 @@ void renderThrowable( final Throwable throwable, final Context context, final Set visitedThrowables, - final String suffix) { - renderThrowable(buffer, throwable, context, visitedThrowables, "", suffix); + final String lineSeparator) { + renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator); } private void renderThrowable( @@ -43,17 +43,16 @@ private void renderThrowable( final Context context, final Set visitedThrowables, final String prefix, - final String suffix) { + final String lineSeparator) { if (visitedThrowables.contains(throwable)) { return; } visitedThrowables.add(throwable); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, suffix); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); renderThrowableMessage(buffer, throwable); - renderSuffix(buffer, suffix); buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, suffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', suffix); + renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); + renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); } @Override @@ -63,9 +62,9 @@ void renderCause( final Context context, final Set visitedThrowables, final String prefix, - final String suffix) { + final String lineSeparator) { if (cause != null) { - renderThrowable(buffer, cause, context, visitedThrowables, prefix, suffix); + renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator); buffer.append(prefix); buffer.append(WRAPPED_BY_CAPTION); } @@ -78,12 +77,12 @@ void renderSuppressed( final Context context, final Set visitedThrowables, final String prefix, - final String suffix) { + final String lineSeparator) { if (suppressedThrowables != null && suppressedThrowables.length != 0) { buffer.append(prefix); buffer.append(SUPPRESSED_CAPTION); for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppressedThrowable, context, visitedThrowables, prefix, suffix); + renderThrowable(buffer, suppressedThrowable, context, visitedThrowables, prefix, lineSeparator); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index f5cf83c5e45..1b3f9e60a53 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -118,13 +118,13 @@ public void format(final LogEvent event, final StringBuilder buffer) { final Throwable t = event.getThrown(); if (subShortOption) { - formatSubShortOption(t, getSuffix(event), buffer); + formatSubShortOption(t, getLineSeparator(event), buffer); } else if (t != null && options.anyLines()) { formatOption(t, getSuffix(event), buffer); } } - private void formatSubShortOption(final Throwable t, final String suffix, final StringBuilder buffer) { + private void formatSubShortOption(final Throwable t, final String lineSeparator, final StringBuilder buffer) { StackTraceElement[] trace; StackTraceElement throwingMethod = null; int len; @@ -159,10 +159,7 @@ private void formatSubShortOption(final Throwable t, final String suffix, final } buffer.append(toAppend); - if (Strings.isNotBlank(suffix)) { - buffer.append(' '); - buffer.append(suffix); - } + buffer.append(lineSeparator); } } @@ -175,7 +172,7 @@ private void formatOption(final Throwable throwable, final String suffix, final buffer.append(' '); } if (requireAdditionalFormatting(suffix)) { - renderer.renderThrowable(buffer, throwable, suffix); + renderer.renderThrowable(buffer, throwable, getLineSeparator(suffix)); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -191,7 +188,7 @@ public boolean handlesThrowable() { return true; } - protected String getSuffix(final LogEvent event) { + private String getSuffix(final LogEvent event) { return suffixProvider.apply(event); } @@ -233,7 +230,29 @@ private static Function createSuffixProvider( } void createRenderer(final ThrowableFormatOptions options) { - this.renderer = - new ThrowableRenderer<>(options.getIgnorePackages(), options.getSeparator(), options.getLines()); + this.renderer = new ThrowableRenderer<>(options.getIgnorePackages(), options.getLines()); + } + + private String getLineSeparator(final String suffix) { + final StringBuilder builder = new StringBuilder(); + + if (Strings.isNotBlank(suffix)) { + builder.append(" "); + builder.append(suffix); + } + builder.append(options.getSeparator()); + return builder.toString(); + } + + String getLineSeparator(final LogEvent logEvent) { + final StringBuilder builder = new StringBuilder(); + + String suffix = getSuffix(logEvent); + if (Strings.isNotBlank(suffix)) { + builder.append(" "); + builder.append(suffix); + } + builder.append(options.getSeparator()); + return builder.toString(); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 5bc4586dfef..5ae55647d0c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -22,7 +22,6 @@ import java.util.Map; import java.util.Set; import org.apache.logging.log4j.core.util.internal.StringBuilders; -import org.apache.logging.log4j.util.Strings; class ThrowableRenderer { @@ -32,20 +31,17 @@ class ThrowableRenderer { final List ignoredPackageNames; - final String lineSeparator; - final int maxLineCount; - ThrowableRenderer(final List ignoredPackageNames, final String lineSeparator, final int maxLineCount) { + ThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { this.ignoredPackageNames = ignoredPackageNames; - this.lineSeparator = lineSeparator; this.maxLineCount = maxLineCount; } final void renderThrowable( - final StringBuilder buffer, final Throwable throwable, final String stackTraceElementSuffix) { + final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { C context = createContext(throwable); - renderThrowable(buffer, throwable, context, new HashSet<>(), stackTraceElementSuffix); + renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); } @@ -60,8 +56,8 @@ void renderThrowable( final Throwable throwable, final C context, final Set visitedThrowables, - final String suffix) { - renderThrowable(buffer, throwable, context, visitedThrowables, "", suffix, ""); + final String lineSeparator) { + renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator, ""); } private void renderThrowable( @@ -70,7 +66,7 @@ private void renderThrowable( final C context, final Set visitedThrowables, final String prefix, - final String suffix, + final String lineSeparator, final String caption) { if (visitedThrowables.contains(throwable)) { return; @@ -79,11 +75,10 @@ private void renderThrowable( buffer.append(prefix); buffer.append(caption); renderThrowableMessage(buffer, throwable); - renderSuffix(buffer, suffix); buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, suffix); - renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', suffix); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, suffix); + renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); + renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); } void renderSuppressed( @@ -92,10 +87,10 @@ void renderSuppressed( final C context, final Set visitedThrowables, final String prefix, - final String suffix) { + final String lineSeparator) { for (final Throwable suppressedThrowable : suppressedThrowables) { renderThrowable( - buffer, suppressedThrowable, context, visitedThrowables, prefix, suffix, SUPPRESSED_CAPTION); + buffer, suppressedThrowable, context, visitedThrowables, prefix, lineSeparator, SUPPRESSED_CAPTION); } } @@ -105,9 +100,9 @@ void renderCause( final C context, final Set visitedThrowables, final String prefix, - final String suffix) { + final String lineSeparator) { if (cause != null) { - renderThrowable(buffer, cause, context, visitedThrowables, prefix, suffix, CAUSED_BY_CAPTION); + renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator, CAUSED_BY_CAPTION); } } @@ -125,22 +120,21 @@ final void renderStackTraceElements( final Throwable throwable, final C context, final String prefix, - final String suffix) { + final String lineSeparator) { context.ignoredStackTraceElementCount = 0; final Context.Metadata metadata = context.metadataByThrowable.get(throwable); final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); for (int i = 0; i < metadata.stackLength; i++) { - renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, suffix); + renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, lineSeparator); } if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); } if (metadata.commonElementCount != 0) { buffer.append(prefix); buffer.append("\t... "); buffer.append(metadata.commonElementCount); buffer.append(" more"); - renderSuffix(buffer, suffix); buffer.append(lineSeparator); } } @@ -150,7 +144,7 @@ void renderStackTraceElement( final StackTraceElement stackTraceElement, final C context, final String prefix, - final String suffix) { + final String lineSeparator) { // Short-circuit on ignored stack trace elements final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); @@ -161,13 +155,12 @@ void renderStackTraceElement( // Render the stack trace element if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, suffix, lineSeparator); + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); - renderSuffix(buffer, suffix); buffer.append(lineSeparator); } @@ -187,7 +180,6 @@ static void renderSuppressedCount( final StringBuilder buffer, final int count, final String prefix, - final String suffix, final String lineSeparator) { buffer.append(prefix); if (count == 1) { @@ -197,17 +189,9 @@ static void renderSuppressedCount( buffer.append(count); buffer.append(" lines"); } - renderSuffix(buffer, suffix); buffer.append(lineSeparator); } - static void renderSuffix(final StringBuilder buffer, final String suffix) { - if (Strings.isNotBlank(suffix)) { - buffer.append(' '); - buffer.append(suffix); - } - } - static class Context { /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java index 842061e838d..ce839179c99 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java @@ -25,13 +25,13 @@ public class ThrowableTestMain { public static void main(String[] args) { Throwable r = createException("r", 1, 3); renderException(r); - renderException(r, new ThrowableRenderer<>(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + renderException(r, new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%ex"); renderException( - r, new ExtendedThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%xEx"); renderException( - r, new RootThrowableRenderer(Collections.emptyList(), System.lineSeparator(), Integer.MAX_VALUE)); + r, new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%rEx"); } @@ -54,7 +54,7 @@ private static void renderException(Throwable throwable, ThrowableRenderer re "%n=== %-25s ==============================%n%n", renderer.getClass().getSimpleName()); final StringBuilder stringBuilder = new StringBuilder(); - renderer.renderThrowable(stringBuilder, throwable, ""); + renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); System.out.println(stringBuilder); } From 1e3dbcffb10a7fd2268409bc7514a79abab9d229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 14 Aug 2024 19:04:03 +0200 Subject: [PATCH 43/72] Simplify `ThrowablePatternConverter` and document the awesome Log4j feature acceptance process --- .../ExtendedThrowablePatternConverter.java | 2 +- .../RootThrowablePatternConverter.java | 2 +- .../pattern/ThrowablePatternConverter.java | 111 ++++++++++-------- .../ROOT/pages/manual/pattern-layout.adoc | 21 +++- 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index 43d6af76188..a859b87aee8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -66,7 +66,7 @@ public void format(final LogEvent event, final StringBuilder buffer) { if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { buffer.append(' '); } - renderer.renderThrowable(buffer, event.getThrown(), getLineSeparator(event)); + renderer.renderThrowable(buffer, event.getThrown(), effectiveLineSeparator(event)); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index 777dfaa331a..8fd62ac97cf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -66,7 +66,7 @@ public void format(final LogEvent event, final StringBuilder buffer) { if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { buffer.append(' '); } - renderer.renderThrowable(buffer, event.getThrown(), getLineSeparator(event)); + renderer.renderThrowable(buffer, event.getThrown(), effectiveLineSeparator(event)); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 1b3f9e60a53..0ad0bc71a84 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -47,14 +47,12 @@ public class ThrowablePatternConverter extends LogEventPatternConverter { @Deprecated protected final List formatters; - private final Function suffixProvider; + private final Function effectiveLineSeparatorProvider; private String rawOption; private final boolean subShortOption; - private final boolean nonStandardLineSeparator; - private ThrowableRenderer renderer; protected final ThrowableFormatOptions options; @@ -86,7 +84,7 @@ protected ThrowablePatternConverter( rawOption = options[0]; } final List suffixFormatters = new ArrayList<>(); - this.suffixProvider = createSuffixProvider(this.options.getSuffix(), config, suffixFormatters); + this.effectiveLineSeparatorProvider = createEffectiveLineSeparator(this.options.getSeparator(), this.options.getSuffix(), config, suffixFormatters); this.formatters = Collections.unmodifiableList(suffixFormatters); subShortOption = ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption) @@ -94,7 +92,6 @@ protected ThrowablePatternConverter( || ThrowableFormatOptions.LINE_NUMBER.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.METHOD_NAME.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.CLASS_NAME.equalsIgnoreCase(rawOption); - nonStandardLineSeparator = !Strings.LINE_SEPARATOR.equals(this.options.getSeparator()); createRenderer(this.options); } @@ -115,12 +112,12 @@ public static ThrowablePatternConverter newInstance(final Configuration config, */ @Override public void format(final LogEvent event, final StringBuilder buffer) { - final Throwable t = event.getThrown(); - + final Throwable throwable = event.getThrown(); + final String effectiveLineSeparator = effectiveLineSeparator(event); if (subShortOption) { - formatSubShortOption(t, getLineSeparator(event), buffer); - } else if (t != null && options.anyLines()) { - formatOption(t, getSuffix(event), buffer); + formatSubShortOption(throwable, effectiveLineSeparator, buffer); + } else if (throwable != null && options.anyLines()) { + formatOption(throwable, effectiveLineSeparator, buffer); } } @@ -166,13 +163,14 @@ private void formatSubShortOption(final Throwable t, final String lineSeparator, @SuppressFBWarnings( value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", justification = "Formatting a throwable is the main purpose of this class.") - private void formatOption(final Throwable throwable, final String suffix, final StringBuilder buffer) { - final int len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { + private void formatOption(final Throwable throwable, final String effectiveLineSeparator, final StringBuilder buffer) { + final int bufferLength = buffer.length(); + if (bufferLength > 0 && !Character.isWhitespace(buffer.charAt(bufferLength - 1))) { buffer.append(' '); } - if (requireAdditionalFormatting(suffix)) { - renderer.renderThrowable(buffer, throwable, getLineSeparator(suffix)); + final boolean customRenderingRequired = isCustomRenderingRequired(effectiveLineSeparator); + if (customRenderingRequired) { + renderer.renderThrowable(buffer, throwable, effectiveLineSeparator); } else { throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); } @@ -188,20 +186,46 @@ public boolean handlesThrowable() { return true; } - private String getSuffix(final LogEvent event) { - return suffixProvider.apply(event); - } - public ThrowableFormatOptions getOptions() { return options; } - private boolean requireAdditionalFormatting(final String suffix) { - return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages(); + private boolean isCustomRenderingRequired(final String effectiveLineSeparator) { + return !options.allLines() || !System.lineSeparator().equals(effectiveLineSeparator) || options.hasPackages(); } - private static Function createSuffixProvider( - final String suffix, final Configuration config, final List suffixFormatters) { + /** + * Creates a lambda that returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator}. + *

+ * At the beginning, there was only {@code separator} used as a terminator at the end of every rendered line. + * Its content was rendered literally without any processing. + *

+ *

+ * Later on, {@code suffix} was added in #61. + * {@code suffix} is functionally identical to {@code separator} with the exception that it contains a Pattern Layout conversion pattern. + * In an ideal world, {@code separator} should have been extended to accept patterns. + * But without giving it a second of thought, just like almost any other Log4j feature, we cheerfully accepted the feature. + *

+ *

+ * Given two overlapping features, how do we determine the effective line separator? + *

+ *
{@code
+     * String effectiveLineSeparator(String separator, String suffix, LogEvent event) {
+     *     String formattedSuffix = format(suffix, event);
+     *     return isNotBlank(formattedSuffix)
+     *            ? (' ' + formattedSuffix + lineSeparator)
+     *            : lineSeparator;
+     * }
+     * }
+ * + * @param separator the user-provided {@code separator} option + * @param suffix the user-provided {@code suffix} option containing a Pattern Layout conversion pattern + * @param config the configuration to create the Pattern Layout conversion pattern parser + * @param suffixFormatters the list of pattern formatters to format the suffix + * @return a lambda that returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator} + */ + private static Function createEffectiveLineSeparator( + final String separator, final String suffix, final Configuration config, final List suffixFormatters) { if (suffix != null) { // Suffix is allowed to be a Pattern Layout conversion pattern, hence we need to parse it @@ -218,14 +242,21 @@ private static Function createSuffixProvider( // Create the lambda accepting a `LogEvent` to invoke collected formatters return logEvent -> { final StringBuilder buffer = new StringBuilder(); + buffer.append(' '); for (PatternFormatter suffixFormatter : suffixFormatters) { suffixFormatter.format(logEvent, buffer); } - return buffer.toString(); + final boolean blankSuffix = buffer.length() == 1; + if (blankSuffix) { + return separator; + } else { + buffer.append(separator); + return buffer.toString(); + } }; } else { - return logEvent -> Strings.EMPTY; + return logEvent -> separator; } } @@ -233,26 +264,14 @@ void createRenderer(final ThrowableFormatOptions options) { this.renderer = new ThrowableRenderer<>(options.getIgnorePackages(), options.getLines()); } - private String getLineSeparator(final String suffix) { - final StringBuilder builder = new StringBuilder(); - - if (Strings.isNotBlank(suffix)) { - builder.append(" "); - builder.append(suffix); - } - builder.append(options.getSeparator()); - return builder.toString(); - } - - String getLineSeparator(final LogEvent logEvent) { - final StringBuilder builder = new StringBuilder(); - - String suffix = getSuffix(logEvent); - if (Strings.isNotBlank(suffix)) { - builder.append(" "); - builder.append(suffix); - } - builder.append(options.getSeparator()); - return builder.toString(); + /** + * Returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator}. + * + * @param logEvent the log event to use while formatting the suffix pattern + * @return the concatenation of the formatted {@code suffix} with the {@code separator} + * @see #createEffectiveLineSeparator(String, String, Configuration, List) + */ + String effectiveLineSeparator(final LogEvent logEvent) { + return effectiveLineSeparatorProvider.apply(logEvent); } } diff --git a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc index dcf5b29b530..adccb098e42 100644 --- a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc @@ -648,10 +648,25 @@ Specifying `%throwable\{none}` or `%throwable\{0}` suppresses output of the exce Use `{filters(packages)}` where _packages_ is a list of package names to suppress matching stack frames from stack traces. -Use `{suffix(pattern)}` to add the output of _pattern_ at the end of each stack frame. +You can change the used line separator in multiple ways: -Use a `{separator(...)}` as the end-of-line string, e.g., `separator(\|)`. -The default value is the `line.separator` system property, which is operating system dependent. +* Use `{separator(separator)}` to set the separator string literal. +It defaults to `System.lineSeparator()`. +The contents of `separator` will be rendered verbatim without being subject to any processing. + +* `{suffix(pattern)}` is identical to `{separator(separator)}` with the exception that the provided `pattern` will be processed as a xref:manual/pattern-layout.adoc[] conversion pattern before being rendered. + +`{separator(...)}` and `{suffix(pattern)}` get concatenated to produce _the effective line separator_ as follows: + +[source,java] +---- +String effectiveLineSeparator(String separator, String suffix, LogEvent event) { + String formattedSuffix = format(suffix, event); + return isNotBlank(formattedSuffix) + ? (' ' + formattedSuffix + lineSeparator) + : lineSeparator; +} +---- [WARNING] ==== From deb25130bfd80593fbd7bb3c275c01c66a5d9969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 14 Aug 2024 19:05:01 +0200 Subject: [PATCH 44/72] Fix Spotless failures --- .../log4j/core/pattern/ExtendedThrowableRenderer.java | 3 +-- .../log4j/core/pattern/ThrowablePatternConverter.java | 11 ++++++++--- .../logging/log4j/core/pattern/ThrowableRenderer.java | 8 ++------ .../logging/log4j/core/pattern/ThrowableTestMain.java | 6 ++---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java index 1ec4d80a6c2..cfbae3d70f2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java @@ -31,8 +31,7 @@ final class ExtendedThrowableRenderer extends ThrowableRenderer { - ExtendedThrowableRenderer( - final List ignoredPackageNames, final int maxLineCount) { + ExtendedThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { super(ignoredPackageNames, maxLineCount); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 0ad0bc71a84..9d0f3ce829a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -84,7 +84,8 @@ protected ThrowablePatternConverter( rawOption = options[0]; } final List suffixFormatters = new ArrayList<>(); - this.effectiveLineSeparatorProvider = createEffectiveLineSeparator(this.options.getSeparator(), this.options.getSuffix(), config, suffixFormatters); + this.effectiveLineSeparatorProvider = createEffectiveLineSeparator( + this.options.getSeparator(), this.options.getSuffix(), config, suffixFormatters); this.formatters = Collections.unmodifiableList(suffixFormatters); subShortOption = ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption) || ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption) @@ -163,7 +164,8 @@ private void formatSubShortOption(final Throwable t, final String lineSeparator, @SuppressFBWarnings( value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", justification = "Formatting a throwable is the main purpose of this class.") - private void formatOption(final Throwable throwable, final String effectiveLineSeparator, final StringBuilder buffer) { + private void formatOption( + final Throwable throwable, final String effectiveLineSeparator, final StringBuilder buffer) { final int bufferLength = buffer.length(); if (bufferLength > 0 && !Character.isWhitespace(buffer.charAt(bufferLength - 1))) { buffer.append(' '); @@ -225,7 +227,10 @@ private boolean isCustomRenderingRequired(final String effectiveLineSeparator) { * @return a lambda that returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator} */ private static Function createEffectiveLineSeparator( - final String separator, final String suffix, final Configuration config, final List suffixFormatters) { + final String separator, + final String suffix, + final Configuration config, + final List suffixFormatters) { if (suffix != null) { // Suffix is allowed to be a Pattern Layout conversion pattern, hence we need to parse it diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 5ae55647d0c..7920b830773 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -38,8 +38,7 @@ class ThrowableRenderer { this.maxLineCount = maxLineCount; } - final void renderThrowable( - final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { + final void renderThrowable(final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { C context = createContext(throwable); renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); @@ -177,10 +176,7 @@ static boolean isStackTraceElementIgnored(final StackTraceElement element, final } static void renderSuppressedCount( - final StringBuilder buffer, - final int count, - final String prefix, - final String lineSeparator) { + final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { buffer.append(prefix); if (count == 1) { buffer.append("\t... "); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java index ce839179c99..f5ce4c2e053 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java @@ -27,11 +27,9 @@ public static void main(String[] args) { renderException(r); renderException(r, new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%ex"); - renderException( - r, new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); + renderException(r, new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%xEx"); - renderException( - r, new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); + renderException(r, new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); renderException(r, "%rEx"); } From e15c48f801cb47cba07bcf98a2e3a7d2fb0c8fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 14 Aug 2024 19:21:46 +0200 Subject: [PATCH 45/72] Fix `bnd-baseline` failures --- .../pattern/ThrowablePatternConverter.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 9d0f3ce829a..17782e8b652 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -279,4 +279,24 @@ void createRenderer(final ThrowableFormatOptions options) { String effectiveLineSeparator(final LogEvent logEvent) { return effectiveLineSeparatorProvider.apply(logEvent); } + + /** + * Returns the formatted suffix pattern. + * + * @param logEvent the log event to use while formatting the suffix pattern + * @return the formatted suffix + * @deprecated Use {@link #effectiveLineSeparator(LogEvent)} instead + */ + @Deprecated + protected String getSuffix(final LogEvent logEvent) { + final String effectiveLineSeparator = effectiveLineSeparator(logEvent); + if (options.getSeparator().equals(effectiveLineSeparator)) { + return ""; + } + return effectiveLineSeparator.substring( + // Skip whitespace prefix: + 1, + // Remove the separator: + effectiveLineSeparator.length() - options.getSeparator().length()); + } } From 483ed391b1a9f99ec808127aafe9e38a7d945ea7 Mon Sep 17 00:00:00 2001 From: alanyu Date: Thu, 15 Aug 2024 23:47:59 +0900 Subject: [PATCH 46/72] fix tests related to separator --- .../log4j/core/EventParameterMemoryLeakTest.java | 10 ++++++++-- .../rolling/RollingAppenderOnStartupTest.java | 2 +- .../NestedLoggingFromThrowableMessageTest.java | 2 +- .../pattern/ThrowablePatternConverterTest.java | 10 +++++----- .../logging/log4j/taglib/CatchingTagTest.java | 2 +- .../taglib/LoggingMessageTagSupportTest.java | 16 +++++++++------- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java index 0688fcbb350..8ceaf0450b2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java @@ -18,6 +18,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -63,15 +64,20 @@ public void testParametersAreNotLeaked() throws Exception { final String line1 = reader.readLine(); final String line2 = reader.readLine(); final String line3 = reader.readLine(); + // line4 is empty line because of the line separator after throwable pattern final String line4 = reader.readLine(); final String line5 = reader.readLine(); + final String line6 = reader.readLine(); + final String line7 = reader.readLine(); reader.close(); file.delete(); assertThat(line1, containsString("Message with parameter paramValue")); assertThat(line2, containsString("paramValue")); assertThat(line3, containsString("paramValue")); - assertThat(line4, containsString("paramValue")); - assertNull(line5, "Expected only three lines"); + assertThat(line4, is("")); + assertThat(line5, containsString("paramValue")); + assertThat(line6, is("")); + assertNull(line7, "Expected only six lines"); final GarbageCollectionHelper gcHelper = new GarbageCollectionHelper(); gcHelper.run(); try { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupTest.java index 9aa469aa7f2..3e419755c8c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupTest.java @@ -51,7 +51,7 @@ public class RollingAppenderOnStartupTest { @BeforeAll public static void setup() throws Exception { final Path target = loggingPath.resolve(FILENAME); - Files.copy(Paths.get(SOURCE, FILENAME), target, StandardCopyOption.COPY_ATTRIBUTES); + Files.copy(Paths.get(SOURCE, FILENAME), target, StandardCopyOption.REPLACE_EXISTING); final FileTime newTime = FileTime.from(Instant.now().minus(1, ChronoUnit.DAYS)); final BasicFileAttributeView attrs = Files.getFileAttributeView(target, BasicFileAttributeView.class); attrs.setTimes(newTime, newTime, newTime); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java index 89158fd2ee7..42f8f58c21a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java @@ -80,7 +80,7 @@ public void testNestedLoggingInLastArgument() throws Exception { final Set lines2 = readUniqueLines(file2); assertEquals("Expected the same data from both appenders", lines1, lines2); - assertEquals(2, lines1.size()); + assertEquals(3, lines1.size()); assertTrue(lines1.contains("INFO NestedLoggingFromThrowableMessageTest Logging in getMessage ")); assertTrue(lines1.contains("ERROR NestedLoggingFromThrowableMessageTest Test message")); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index aa0e574ac8f..8b6c750f32e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -105,7 +105,7 @@ public void testShortClassName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals(packageName + "ThrowablePatternConverterTest", result, "The class names should be same"); + assertEquals(packageName + "ThrowablePatternConverterTest\n", result, "The class names should be same"); } @Test @@ -124,7 +124,7 @@ public void testShortFileName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("ThrowablePatternConverterTest.java", result, "The file names should be same"); + assertEquals("ThrowablePatternConverterTest.java\n", result, "The file names should be same"); } @Test @@ -164,7 +164,7 @@ public void testShortLocalizedMessage() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("I am localized.", result, "The messages should be same"); + assertEquals("I am localized.\n", result, "The messages should be same"); } @Test @@ -183,7 +183,7 @@ public void testShortMessage() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("IllegalArgument", result, "The messages should be same"); + assertEquals("IllegalArgument\n", result, "The messages should be same"); } @Test @@ -202,7 +202,7 @@ public void testShortMethodName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("testShortMethodName", result, "The method names should be same"); + assertEquals("testShortMethodName\n", result, "The method names should be same"); } @Test diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java index 7bf7c795cff..adbdbe66289 100644 --- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java +++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java @@ -79,7 +79,7 @@ private void verify(final String expected) { final List events = listApp.getMessages(); try { assertEquals("Incorrect number of messages.", 1, events.size()); - assertEquals("Incorrect message.", "o.a.l.l.t.CatchingTagTest " + expected, events.get(0)); + assertEquals("Incorrect message.", "o.a.l.l.t.CatchingTagTest " + expected + "\n", events.get(0)); } finally { listApp.clear(); } diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java index 9826603000f..d3db4bd62a7 100644 --- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java +++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java @@ -136,7 +136,7 @@ public void testDoEndTagStringMessageNoMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify( - "Another message for testDoEndTagStringMessageNoMarkerException ERROR M- E java.lang.Exception: This is a test"); + "Another message for testDoEndTagStringMessageNoMarkerException ERROR M- E java.lang.Exception: This is a test\n"); } @Test @@ -149,7 +149,7 @@ public void testDoEndTagStringMessageMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify( - "Final message for testDoEndTagStringMessageMarkerException TRACE M-F02 E java.lang.RuntimeException: This is another test"); + "Final message for testDoEndTagStringMessageMarkerException TRACE M-F02 E java.lang.RuntimeException: This is another test\n"); } @Test @@ -175,7 +175,7 @@ public void testDoEndTagStringWithParametersMarkerAndException() throws Exceptio this.tag.setMessage("Final message with [{}] parameter of [{}]"); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify("Final message with [Z] parameter of [SECONDS] DEBUG M-N03 E java.lang.Error: This is the last test"); + verify("Final message with [Z] parameter of [SECONDS] DEBUG M-N03 E java.lang.Error: This is the last test\n"); } @Test @@ -210,7 +210,8 @@ public void testDoEndTagMessageNoMarkerException() throws Exception { logger.getMessageFactory().newMessage("Third message for testDoEndTagMessageNoMarkerException")); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify("Third message for testDoEndTagMessageNoMarkerException TRACE M- E java.lang.Exception: This is a test"); + verify( + "Third message for testDoEndTagMessageNoMarkerException TRACE M- E java.lang.Exception: This is a test\n"); } @Test @@ -224,7 +225,7 @@ public void testDoEndTagMessageMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify("Final message for testDoEndTagMessageMarkerException ERROR M-F02 E java.lang.RuntimeException: " - + "This is another test"); + + "This is another test\n"); } @Test @@ -256,7 +257,8 @@ public void testDoEndTagObjectNoMarkerException() throws Exception { this.tag.setMessage(new MyMessage("Third message for testDoEndTagObjectNoMarkerException")); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify("Third message for testDoEndTagObjectNoMarkerException TRACE M- E java.lang.Exception: This is a test"); + verify( + "Third message for testDoEndTagObjectNoMarkerException TRACE M- E java.lang.Exception: This is a test\n"); } @Test @@ -269,7 +271,7 @@ public void testDoEndTagObjectMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify("Final message for testDoEndTagObjectMarkerException ERROR M-F02 E java.lang.RuntimeException: " - + "This is another test"); + + "This is another test\n"); } private void verify(final String expected) { From 5bee486c44c60ebe07bed700821e11b639068879 Mon Sep 17 00:00:00 2001 From: alanyu Date: Sat, 17 Aug 2024 10:25:24 +0900 Subject: [PATCH 47/72] add tests --- .../log4j/core/pattern/ThrowableTest.java | 161 ++++++++++++++++-- .../ExtendedThrowableRenderer.txt | 155 +++++++++++++++++ .../RootThrowableRenderer.txt | 155 +++++++++++++++++ .../throwableRenderer/ThrowableRenderer.txt | 155 +++++++++++++++++ 4 files changed, 614 insertions(+), 12 deletions(-) create mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt create mode 100644 log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt create mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 843ed1c0c90..f2961ea669a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -18,6 +18,13 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.Collections; +import java.util.Objects; import java.util.stream.Stream; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; @@ -29,6 +36,8 @@ import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.util.StringBuilderWriter; +import org.junit.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -42,20 +51,23 @@ static Stream testConverter_dataSource() { final Integer depth = 5; return Stream.of( // Throwable - Arguments.of("%ex", filters, null), - Arguments.of("%ex", null, depth), + Arguments.of("%ex", filters, null, null, null), + Arguments.of("%ex", null, depth, null, null), + Arguments.of("%ex", null, null, "I am suffix", "#"), // RootThrowable - Arguments.of("%rEx", filters, null), - Arguments.of("%rEx", null, depth), + Arguments.of("%rEx", filters, null, null, null), + Arguments.of("%rEx", null, depth, null, null), + Arguments.of("%rEx", null, null, "I am suffix", "#"), // ExtendedThrowable - Arguments.of("%xEx", filters, null), - Arguments.of("%xEx", null, depth)); + Arguments.of("%xEx", filters, null, null, null), + Arguments.of("%xEx", null, depth, null, null), + Arguments.of("%xEx", null, null, "I am suffix", "#")); } @ParameterizedTest @MethodSource("testConverter_dataSource") - void testConverter(String exceptionPattern, String filters, Integer depth) { - final String pattern = buildPattern(exceptionPattern, filters, depth); + void testConverter(String exceptionPattern, String filters, Integer depth, String suffix, String lineSeparator) { + final String pattern = buildPattern(exceptionPattern, filters, depth, suffix, lineSeparator); final ConfigurationBuilder configBuilder = ConfigurationBuilderFactory.newConfigurationBuilder(); @@ -73,22 +85,118 @@ void testConverter(String exceptionPattern, String filters, Integer depth) { loggerContext.start(); loggerContext.reconfigure(config); } - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); + final Throwable r = createException("r", 1, 3); final Logger logger = loggerContext.getLogger(LoggerTest.class); final ListAppender appender = loggerContext.getConfiguration().getAppender(appenderName); - logger.error("Exception", parent); + logger.error("Exception", r); assertThat(appender.getMessages()).hasSize(1); final String message = appender.getMessages().get(0); assertThat(message).isNotNull(); verifyFilters(message, filters); verifyDepth(message, depth); + verifySuffix(message, suffix, lineSeparator); } } - private static String buildPattern(String exceptionPattern, String filters, Integer depth) { + static Stream testFull_dataSource() { + return Stream.of( + Arguments.of( + new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE), "ThrowableRenderer.txt"), + Arguments.of( + new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), + "RootThrowableRenderer.txt"), + Arguments.of( + new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), + "ExtendedThrowableRenderer.txt")); + } + + @ParameterizedTest + @MethodSource("testFull_dataSource") + void testFull(final ThrowableRenderer renderer, final String expectedFilePath) throws IOException { + final Throwable throwable = createException("r", 1, 3); + final String expected = getContentFromResource(expectedFilePath); + final String actual = render(renderer, throwable); + assertThat(actual).isEqualTo(expected); + } + + static Stream renderers_dataSource() { + return Stream.of( + Arguments.of(new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)), + Arguments.of(new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)), + Arguments.of(new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE))); + } + + @ParameterizedTest + @MethodSource("renderers_dataSource") + void testCircularSuppressedExceptions(final ThrowableRenderer renderer) { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(); + e2.addSuppressed(e1); + e1.addSuppressed(e2); + + render(renderer, e1); + } + + @ParameterizedTest + @MethodSource("renderers_dataSource") + void testCircularSuppressedNestedException(final ThrowableRenderer renderer) { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(e1); + e2.addSuppressed(e1); + e1.addSuppressed(e2); + + render(renderer, e1); + } + + @ParameterizedTest + @MethodSource("renderers_dataSource") + void testCircularCauseExceptions(final ThrowableRenderer renderer) { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(e1); + e1.initCause(e2); + render(renderer, e1); + } + + /** + * Default setting ThrowableRenderer render output should equal to throwable.printStackTrace(). + */ + @Test + public void testThrowableRenderer() { + final Throwable throwable = createException("r", 1, 3); + final ThrowableRenderer renderer = new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE); + String actual = render(renderer, throwable); + assertThat(actual).isEqualTo(getStandardThrowableStackTrace(throwable)); + } + + private static String getContentFromResource(String fileName) throws IOException { + fileName = "throwableRenderer/" + fileName; + String path = Objects.requireNonNull( + ThrowableTest.class.getClassLoader().getResource(fileName)) + .getPath(); + return new String(Files.readAllBytes(FileSystems.getDefault().getPath(path)), StandardCharsets.UTF_8); + } + + private static String render(final ThrowableRenderer renderer, final Throwable throwable) { + final StringBuilder stringBuilder = new StringBuilder(); + renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); + return stringBuilder.toString(); + } + + private static String getStandardThrowableStackTrace(final Throwable throwable) { + final StringBuilder buffer = new StringBuilder(); + final PrintWriter printWriter = new PrintWriter(new StringBuilderWriter(buffer)); + throwable.printStackTrace(printWriter); + return buffer.toString(); + } + + private static String buildPattern( + final String exceptionPattern, + final String filters, + final Integer depth, + final String suffix, + final String lineSeparator) { final StringBuilder buffer = new StringBuilder("%m"); buffer.append(exceptionPattern); if (filters != null) { @@ -102,6 +210,18 @@ private static String buildPattern(String exceptionPattern, String filters, Inte buffer.append(depth); buffer.append("}"); } + + if (suffix != null) { + buffer.append("{suffix("); + buffer.append(suffix); + buffer.append(")}"); + } + + if (lineSeparator != null) { + buffer.append("{separator("); + buffer.append(lineSeparator); + buffer.append(")}"); + } return buffer.toString(); } @@ -122,4 +242,21 @@ private static void verifyDepth(final String message, final Integer depth) { assertThat(message).hasLineCount(depth); } } + + private static void verifySuffix(final String message, final String suffix, final String lineSeparator) { + if (suffix != null && lineSeparator != null) { + for (String line : message.split(lineSeparator)) { + assertThat(line).endsWith(suffix); + } + } + } + + private static Throwable createException(final String name, int depth, int maxDepth) { + Exception r = new Exception(name); + if (depth < maxDepth) { + r.initCause(createException(name + "_c", depth + 1, maxDepth)); + r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); + } + return r; + } } diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt new file mode 100644 index 00000000000..d888c71cd5c --- /dev/null +++ b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt @@ -0,0 +1,155 @@ +java.lang.Exception: r + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) [test-classes/:?] + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] + at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) [junit-platform-commons-1.10.3.jar:1.10.3] + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] + at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) [?:?] + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) [junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) [junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) [surefire-junit-platform-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.3.1.jar:3.3.1] + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.3.1.jar:3.3.1] + Suppressed: java.lang.Exception: r_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + ... 129 more + Suppressed: java.lang.Exception: r_s_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + ... 130 more + Caused by: java.lang.Exception: r_s_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + ... 130 more +Caused by: java.lang.Exception: r_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + ... 129 more + Suppressed: java.lang.Exception: r_c_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + ... 130 more +Caused by: java.lang.Exception: r_c_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt new file mode 100644 index 00000000000..e8d86c940a2 --- /dev/null +++ b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt @@ -0,0 +1,155 @@ +java.lang.Exception: r_c_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 130 more +Wrapped by: java.lang.Exception: r_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 129 more + Suppressed: java.lang.Exception: r_c_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 130 more +Wrapped by: java.lang.Exception: r + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) + at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) + Suppressed: java.lang.Exception: r_s_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 130 more + Wrapped by: java.lang.Exception: r_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 129 more + Suppressed: java.lang.Exception: r_s_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt new file mode 100644 index 00000000000..c47e532eab7 --- /dev/null +++ b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt @@ -0,0 +1,155 @@ +java.lang.Exception: r + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) + at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) + at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) + at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) + Suppressed: java.lang.Exception: r_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 129 more + Suppressed: java.lang.Exception: r_s_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 130 more + Caused by: java.lang.Exception: r_s_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 130 more +Caused by: java.lang.Exception: r_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 129 more + Suppressed: java.lang.Exception: r_c_s + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + ... 130 more +Caused by: java.lang.Exception: r_c_c + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) + at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + ... 130 more From b3d53ca2febeb369a9238e2ac954d2effea18d9d Mon Sep 17 00:00:00 2001 From: alanyu Date: Sat, 17 Aug 2024 10:45:38 +0900 Subject: [PATCH 48/72] Deprecate ThrowableProxy related classes and tests --- .../core/impl/ThrowableProxyHelperTest.java | 79 --- .../core/impl/ThrowableProxyRendererTest.java | 39 -- .../log4j/core/impl/ThrowableProxyTest.java | 462 ------------------ .../log4j/core/impl/ExtendedClassInfo.java | 1 + .../core/impl/ExtendedStackTraceElement.java | 1 + .../log4j/core/impl/ThrowableProxy.java | 3 +- .../log4j/core/impl/ThrowableProxyHelper.java | 1 + .../core/impl/ThrowableProxyRenderer.java | 1 + .../ExtendedStackTraceElementMixIn.java | 1 + .../core/jackson/ThrowableProxyMixIn.java | 1 + ...wableProxyWithStacktraceAsStringMixIn.java | 1 + .../ThrowableProxyWithoutStacktraceMixIn.java | 1 + 12 files changed, 10 insertions(+), 581 deletions(-) delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelperTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelperTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelperTest.java deleted file mode 100644 index 0d95d83ff52..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelperTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.apache.logging.log4j.core.impl; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.Map; -import org.junit.Test; - -/** - * Tests ThrowableProxyHelper. - */ -public class ThrowableProxyHelperTest { - - /** - * We populate dummy stack trace and array of stack trace elements in the right order - * It supposed to always trigger fast path so cache won't be populated - * This simulates the case when current thread's and throwable stack traces have the same elements - */ - @Test - public void testSuccessfulCacheHit() { - final Map map = new HashMap<>(); - final Deque> stack = new ArrayDeque<>(3); - final StackTraceElement[] stackTraceElements = new StackTraceElement[3]; - stackTraceElements[0] = new StackTraceElement(Integer.class.getName(), "toString", "Integer.java", 1); - stack.addLast(Integer.class); - stackTraceElements[1] = new StackTraceElement(Float.class.getName(), "toString", "Float.java", 1); - stack.addLast(Float.class); - stackTraceElements[2] = new StackTraceElement(Double.class.getName(), "toString", "Double.java", 1); - stack.addLast(Double.class); - final Throwable throwable = new IllegalStateException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - ThrowableProxyHelper.toExtendedStackTrace(proxy, stack, map, null, stackTraceElements); - assertTrue(map.isEmpty()); - } - - /** - * We populate dummy stack trace and array of stack trace elements in the wrong order - * It will trigger fast path only once so cache will have two items - */ - @Test - public void testFailedCacheHit() { - final Map map = new HashMap<>(); - final Deque> stack = new ArrayDeque<>(3); - final StackTraceElement[] stackTraceElements = new StackTraceElement[3]; - stackTraceElements[0] = new StackTraceElement(Integer.class.getName(), "toString", "Integer.java", 1); - stack.addFirst(Integer.class); - stackTraceElements[1] = new StackTraceElement(Float.class.getName(), "toString", "Float.java", 1); - stack.addFirst(Float.class); - stackTraceElements[2] = new StackTraceElement(Double.class.getName(), "toString", "Double.java", 1); - stack.addFirst(Double.class); - final Throwable throwable = new IllegalStateException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - ThrowableProxyHelper.toExtendedStackTrace(proxy, stack, map, null, stackTraceElements); - assertFalse(map.isEmpty()); - // Integer will match, so fast path won't cache it, only Float and Double will appear in cache after class - // loading - assertTrue(map.containsKey(Double.class.getName())); - assertTrue(map.containsKey(Float.class.getName())); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java deleted file mode 100644 index 397d9a4d57d..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.apache.logging.log4j.core.impl; - -import java.util.ArrayList; -import org.apache.logging.log4j.core.pattern.PlainTextRenderer; -import org.junit.jupiter.api.Test; - -/** - * Tests ThrowableProxyRenderer. - */ -public class ThrowableProxyRendererTest { - - @Test - public void test_formatExtendedStackTraceTo() { - ThrowableProxyRenderer.formatExtendedStackTraceTo( - new ThrowableProxy(), - new StringBuilder(), - new ArrayList<>(), - new PlainTextRenderer(), - "", - System.lineSeparator(), - Integer.MAX_VALUE); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java deleted file mode 100644 index 13246f19c61..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * 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.apache.logging.log4j.core.impl; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.BindException; -import java.net.InetSocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.security.Permission; -import java.security.SecureRandom; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.Map; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.spec.IvParameterSpec; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; -import org.apache.logging.log4j.core.pattern.PlainTextRenderer; -import org.apache.logging.log4j.util.Constants; -import org.apache.logging.log4j.util.Strings; -import org.junit.jupiter.api.Test; - -/** - * - */ -public class ThrowableProxyTest { - - public static class AlwaysThrowsError { - static { - if (true) { - throw new Error("I always throw an Error when initialized"); - } - } - } - - static class Fixture { - @JsonProperty - ThrowableProxy proxy = new ThrowableProxy(new IOException("test")); - } - - private ThrowableProxy deserialize(final byte[] binary) throws IOException, ClassNotFoundException { - final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new ObjectInputStream(inArr); - return (ThrowableProxy) in.readObject(); - } - - private byte[] serialize(final ThrowableProxy proxy) throws IOException { - final ByteArrayOutputStream arr = new ByteArrayOutputStream(); - final ObjectOutputStream out = new ObjectOutputStream(arr); - out.writeObject(proxy); - return arr.toByteArray(); - } - - private boolean allLinesContain(final String text, final String containedText) { - final String[] lines = text.split("\n"); - for (final String line : lines) { - if (line.isEmpty()) { - continue; - } - if (!line.contains(containedText)) { - return false; - } - } - return true; - } - - private boolean lastLineContains(final String text, final String containedText) { - final String[] lines = text.split("\n"); - final String lastLine = lines[lines.length - 1]; - return lastLine.contains(containedText); - } - - private void testIoContainer(final ObjectMapper objectMapper) throws IOException { - final Fixture expected = new Fixture(); - final String s = objectMapper.writeValueAsString(expected); - final Fixture actual = objectMapper.readValue(s, Fixture.class); - assertEquals(expected.proxy.getName(), actual.proxy.getName()); - assertEquals(expected.proxy.getMessage(), actual.proxy.getMessage()); - assertEquals(expected.proxy.getLocalizedMessage(), actual.proxy.getLocalizedMessage()); - assertEquals(expected.proxy.getCommonElementCount(), actual.proxy.getCommonElementCount()); - assertArrayEquals(expected.proxy.getExtendedStackTrace(), actual.proxy.getExtendedStackTrace()); - assertEquals(expected.proxy, actual.proxy); - } - - @Test - public void testIoContainerAsJson() throws IOException { - testIoContainer(new Log4jJsonObjectMapper()); - } - - @Test - public void testIoContainerAsXml() throws IOException { - testIoContainer(new Log4jXmlObjectMapper()); - } - - /** - * Attempts to instantiate a class that cannot initialize and then logs the stack trace of the Error. The logger - * must not fail when using {@link ThrowableProxy} to inspect the frames of the stack trace. - */ - @Test - public void testLogStackTraceWithClassThatCannotInitialize() { - final Error e = assertThrows(Error.class, AlwaysThrowsError::new); - // Print the stack trace to System.out for informational purposes - // System.err.println("### Here's the stack trace that we'll log with log4j ###"); - // e.printStackTrace(); - // System.err.println("### End stack trace ###"); - - final Logger logger = LogManager.getLogger(getClass()); - - assertDoesNotThrow(() -> { - // This is the critical portion of the test. The log message must be printed without - // throwing a java.lang.Error when introspecting the AlwaysThrowError class in the - // stack trace. - logger.error(e.getMessage(), e); - logger.error(e); - }); - } - - @Test - public void testLogStackTraceWithClassThatWillCauseSecurityException() throws IOException { - final SecurityManager sm = System.getSecurityManager(); - try { - System.setSecurityManager(new SecurityManager() { - @Override - public void checkPermission(final Permission perm) { - if (perm instanceof RuntimePermission) { - // deny access to the class to trigger the security exception - if ("accessClassInPackage.sun.nio.ch".equals(perm.getName())) { - throw new SecurityException(perm.toString()); - } - } - } - }); - final BindException e = assertThrows(BindException.class, () -> { - ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); - ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); - }); - assertDoesNotThrow(() -> new ThrowableProxy(e)); - } finally { - // restore the security manager - System.setSecurityManager(sm); - } - } - - @Test - public void testLogStackTraceWithClassLoaderThatWithCauseSecurityException() throws Exception { - final SecurityManager sm = System.getSecurityManager(); - try { - System.setSecurityManager(new SecurityManager() { - @Override - public void checkPermission(final Permission perm) { - if (perm instanceof RuntimePermission) { - // deny access to the classloader to trigger the security exception - if ("getClassLoader".equals(perm.getName())) { - throw new SecurityException(perm.toString()); - } - } - } - }); - final String algorithm = "AES/CBC/PKCS5Padding"; - final Cipher ec = Cipher.getInstance(algorithm); - final byte[] bytes = new byte[16]; // initialization vector - final SecureRandom secureRandom = new SecureRandom(); - secureRandom.nextBytes(bytes); - final KeyGenerator generator = KeyGenerator.getInstance("AES"); - generator.init(128); - final IvParameterSpec algorithmParameterSpec = new IvParameterSpec(bytes); - ec.init(Cipher.ENCRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); - final byte[] raw = Constants.EMPTY_BYTE_ARRAY; - final byte[] encrypted = ec.doFinal(raw); - final Cipher dc = Cipher.getInstance(algorithm); - dc.init(Cipher.DECRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); - final BadPaddingException e = assertThrows(BadPaddingException.class, () -> dc.doFinal(encrypted)); - assertDoesNotThrow(() -> new ThrowableProxy(e)); - } finally { - // restore the existing security manager - System.setSecurityManager(sm); - } - } - - // DO NOT REMOVE THIS COMMENT: - // UNCOMMENT WHEN GENERATING SERIALIZED THROWABLEPROXY FOR #testSerializationWithUnknownThrowable - // public static class DeletedException extends Exception { - // private static final long serialVersionUID = 1L; - // - // public DeletedException(String msg) { - // super(msg); - // } - // }; - - @Test - public void testSerialization() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals(proxy.getName(), proxy2.getName()); - assertEquals(proxy.getMessage(), proxy2.getMessage()); - assertEquals(proxy.getCauseProxy(), proxy2.getCauseProxy()); - assertArrayEquals(proxy.getExtendedStackTrace(), proxy2.getExtendedStackTrace()); - } - - @Test - public void testSerialization_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals( - proxy.getExtendedStackTraceAsString(Strings.EMPTY), - proxy2.getExtendedStackTraceAsString(Strings.EMPTY)); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth1() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth2() throws Exception { - final Throwable throwable = - new RuntimeException(new IllegalArgumentException("This is a test", new IOException("level 2"))); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth3() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException( - "level 1", new IOException("level 2", new IllegalStateException("level 3")))); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - private void testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(final Throwable throwable) - throws Exception { - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals( - proxy.getExtendedStackTraceAsString(Strings.EMPTY), - proxy2.getExtendedStackTraceAsString(Strings.EMPTY)); - } - - @Test - public void testSerializationWithUnknownThrowable() throws Exception { - - final String msg = "OMG I've been deleted!"; - - // DO NOT DELETE THIS COMMENT: - // UNCOMMENT TO RE-GENERATE SERIALIZED EVENT WHEN UPDATING THIS TEST. - // final Exception thrown = new DeletedException(msg); - // final ThrowableProxy proxy = new ThrowableProxy(thrown); - // final byte[] binary = serialize(proxy); - // String base64 = DatatypeConverter.printBase64Binary(binary); - // System.out.println("final String base64 = \"" + base64.replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") + "\";"); - - final String base64 = - "rO0ABXNyADFvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLlRocm93YWJsZVByb3h52cww1Zp7rPoCAAdJABJjb21tb25FbGVtZW50Q291bnRMAApjYXVzZVByb3h5dAAzTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvVGhyb3dhYmxlUHJveHk7WwASZXh0ZW5kZWRTdGFja1RyYWNldAA/W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7TAAQbG9jYWxpemVkTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAB21lc3NhZ2VxAH4AA0wABG5hbWVxAH4AA1sAEXN1cHByZXNzZWRQcm94aWVzdAA0W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL1Rocm93YWJsZVByb3h5O3hwAAAAAHB1cgA/W0xvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7ys+II6XHz7wCAAB4cAAAABhzcgA8b3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5FeHRlbmRlZFN0YWNrVHJhY2VFbGVtZW504d7Pusa2kAcCAAJMAA5leHRyYUNsYXNzSW5mb3QANkxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkQ2xhc3NJbmZvO0wAEXN0YWNrVHJhY2VFbGVtZW50dAAdTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDt4cHNyADRvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVkQ2xhc3NJbmZvAAAAAAAAAAECAANaAAVleGFjdEwACGxvY2F0aW9ucQB+AANMAAd2ZXJzaW9ucQB+AAN4cAF0AA10ZXN0LWNsYXNzZXMvdAABP3NyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgADTAAIZmlsZU5hbWVxAH4AA0wACm1ldGhvZE5hbWVxAH4AA3hwAAAAaHQANW9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuVGhyb3dhYmxlUHJveHlUZXN0dAAXVGhyb3dhYmxlUHJveHlUZXN0LmphdmF0ACV0ZXN0U2VyaWFsaXphdGlvbldpdGhVbmtub3duVGhyb3dhYmxlc3EAfgAIc3EAfgAMAHEAfgAPdAAIMS43LjBfNTVzcQB+ABD////+dAAkc3VuLnJlZmxlY3QuTmF0aXZlTWV0aG9kQWNjZXNzb3JJbXBscHQAB2ludm9rZTBzcQB+AAhzcQB+AAwAcQB+AA9xAH4AF3NxAH4AEP////9xAH4AGXB0AAZpbnZva2VzcQB+AAhzcQB+AAwAcQB+AA9xAH4AF3NxAH4AEP////90AChzdW4ucmVmbGVjdC5EZWxlZ2F0aW5nTWV0aG9kQWNjZXNzb3JJbXBscHEAfgAec3EAfgAIc3EAfgAMAHEAfgAPcQB+ABdzcQB+ABD/////dAAYamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kcHEAfgAec3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAvdAApb3JnLmp1bml0LnJ1bm5lcnMubW9kZWwuRnJhbWV3b3JrTWV0aG9kJDF0ABRGcmFtZXdvcmtNZXRob2QuamF2YXQAEXJ1blJlZmxlY3RpdmVDYWxsc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAMdAAzb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMubW9kZWwuUmVmbGVjdGl2ZUNhbGxhYmxldAAXUmVmbGVjdGl2ZUNhbGxhYmxlLmphdmF0AANydW5zcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAACx0ACdvcmcuanVuaXQucnVubmVycy5tb2RlbC5GcmFtZXdvcmtNZXRob2RxAH4ALHQAEWludm9rZUV4cGxvc2l2ZWx5c3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAARdAAyb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMuc3RhdGVtZW50cy5JbnZva2VNZXRob2R0ABFJbnZva2VNZXRob2QuamF2YXQACGV2YWx1YXRlc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAEPdAAeb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVydAARUGFyZW50UnVubmVyLmphdmF0AAdydW5MZWFmc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAABGdAAob3JnLmp1bml0LnJ1bm5lcnMuQmxvY2tKVW5pdDRDbGFzc1J1bm5lcnQAG0Jsb2NrSlVuaXQ0Q2xhc3NSdW5uZXIuamF2YXQACHJ1bkNoaWxkc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAycQB+AE1xAH4ATnEAfgBPc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAADudAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDNxAH4AR3EAfgA0c3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAA/dAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDFxAH4AR3QACHNjaGVkdWxlc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAADscQB+AEZxAH4AR3QAC3J1bkNoaWxkcmVuc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAA1cQB+AEZxAH4AR3QACmFjY2VzcyQwMDBzcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAAOV0ACBvcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXIkMnEAfgBHcQB+AEFzcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAATVxAH4ARnEAfgBHcQB+ADRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAAAMnQAOm9yZy5lY2xpcHNlLmpkdC5pbnRlcm5hbC5qdW5pdDQucnVubmVyLkpVbml0NFRlc3RSZWZlcmVuY2V0ABhKVW5pdDRUZXN0UmVmZXJlbmNlLmphdmFxAH4ANHNxAH4ACHNxAH4ADAF0AAQuY3AvcQB+AA9zcQB+ABAAAAAmdAAzb3JnLmVjbGlwc2UuamR0LmludGVybmFsLmp1bml0LnJ1bm5lci5UZXN0RXhlY3V0aW9udAASVGVzdEV4ZWN1dGlvbi5qYXZhcQB+ADRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAAB03QANm9yZy5lY2xpcHNlLmpkdC5pbnRlcm5hbC5qdW5pdC5ydW5uZXIuUmVtb3RlVGVzdFJ1bm5lcnQAFVJlbW90ZVRlc3RSdW5uZXIuamF2YXQACHJ1blRlc3Rzc3EAfgAIc3EAfgAMAXQABC5jcC9xAH4AD3NxAH4AEAAAAqtxAH4AgnEAfgCDcQB+AIRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAABhnEAfgCCcQB+AINxAH4ANHNxAH4ACHNxAH4ADAF0AAQuY3AvcQB+AA9zcQB+ABAAAADFcQB+AIJxAH4Ag3QABG1haW50ABZPTUcgSSd2ZSBiZWVuIGRlbGV0ZWQhcQB+AJJ0AEZvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLlRocm93YWJsZVByb3h5VGVzdCREZWxldGVkRXhjZXB0aW9udXIANFtMb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5UaHJvd2FibGVQcm94eTv67QHghaLrOQIAAHhwAAAAAA=="; - - final byte[] binaryDecoded = Base64Converter.parseBase64Binary(base64); - final ThrowableProxy proxy2 = deserialize(binaryDecoded); - - assertEquals(this.getClass().getName() + "$DeletedException", proxy2.getName()); - assertEquals(msg, proxy2.getMessage()); - } - - @Test - public void testSeparator_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String separator = " | "; - final String extendedStackTraceAsString = - proxy.getExtendedStackTraceAsString(null, PlainTextRenderer.getInstance(), " | ", Strings.EMPTY); - assertTrue(allLinesContain(extendedStackTraceAsString, separator), extendedStackTraceAsString); - } - - @Test - public void testSuffix_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString(suffix); - assertTrue(lastLineContains(extendedStackTraceAsString, suffix), extendedStackTraceAsString); - } - - @Test - public void testSuffix_getExtendedStackTraceAsStringWithCausedThrowable() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getExtendedStackTraceAsStringWithSuppressedThrowable() throws Exception { - final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); - final Throwable throwable = new RuntimeException(cause); - throwable.addSuppressed(new IOException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsStringWithCausedThrowable() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsStringWithSuppressedThrowable() throws Exception { - final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); - final Throwable throwable = new RuntimeException(cause); - throwable.addSuppressed(new IOException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testStack() { - final Map map = new HashMap<>(); - final Deque> stack = new ArrayDeque<>(); - final Throwable throwable = new IllegalStateException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final ExtendedStackTraceElement[] callerPackageData = - ThrowableProxyHelper.toExtendedStackTrace(proxy, stack, map, null, throwable.getStackTrace()); - assertNotNull(callerPackageData, "No package data returned"); - } - - /** - * Asserts that LOG4J2-834 is solved by constructing a ThrowableProxy over a RuntimeException object thrown at a - * unloaded known class (already compiled and available as a test resource: - * org.apache.logging.log4j.core.impl.ForceNoDefClassFoundError.class). - */ - @Test - public void testStackWithUnloadableClass() throws Exception { - final Deque> stack = new ArrayDeque<>(); - final Map map = new HashMap<>(); - - final String runtimeExceptionThrownAtUnloadableClass_base64 = - "rO0ABXNyABpqYXZhLmxhbmcuUnVudGltZUV4Y2VwdGlvbp5fBkcKNIPlAgAAeHIAE2phdmEubGFuZy5FeGNlcHRpb27Q/R8+GjscxAIAAHhyABNqYXZhLmxhbmcuVGhyb3dhYmxl1cY1Jzl3uMsDAANMAAVjYXVzZXQAFUxqYXZhL2xhbmcvVGhyb3dhYmxlO0wADWRldGFpbE1lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApzdGFja1RyYWNldAAeW0xqYXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7eHBxAH4ABnB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnQ7AkYqPDz9IjkCAAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50YQnFmiY23YUCAARJAApsaW5lTnVtYmVyTAAOZGVjbGFyaW5nQ2xhc3NxAH4ABEwACGZpbGVOYW1lcQB+AARMAAptZXRob2ROYW1lcQB+AAR4cAAAAAZ0ADxvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkZvcmNlTm9EZWZDbGFzc0ZvdW5kRXJyb3J0AB5Gb3JjZU5vRGVmQ2xhc3NGb3VuZEVycm9yLmphdmF0AARtYWlueA=="; - final byte[] binaryDecoded = Base64Converter.parseBase64Binary(runtimeExceptionThrownAtUnloadableClass_base64); - final ByteArrayInputStream inArr = new ByteArrayInputStream(binaryDecoded); - final ObjectInputStream in = new ObjectInputStream(inArr); - final Throwable throwable = (Throwable) in.readObject(); - final ThrowableProxy subject = new ThrowableProxy(throwable); - - ThrowableProxyHelper.toExtendedStackTrace(subject, stack, map, null, throwable.getStackTrace()); - } - - /** - * Tests LOG4J2-934. - */ - @Test - public void testCircularSuppressedExceptions() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(); - e2.addSuppressed(e1); - e1.addSuppressed(e2); - LogManager.getLogger().error("Error", e1); - } - - @Test - public void testSuppressedExceptions() { - final Exception e = new Exception("Root exception"); - e.addSuppressed(new IOException("Suppressed #1")); - e.addSuppressed(new IOException("Suppressed #2")); - LogManager.getLogger().error("Error", e); - final ThrowableProxy proxy = new ThrowableProxy(e); - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - } - - @Test - public void testCauseSuppressedExceptions() { - final Exception cause = new Exception("Nested exception"); - cause.addSuppressed(new IOException("Suppressed #1")); - cause.addSuppressed(new IOException("Suppressed #2")); - LogManager.getLogger().error("Error", new Exception(cause)); - final ThrowableProxy proxy = new ThrowableProxy(new Exception("Root exception", cause)); - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - } - - /** - * Tests LOG4J2-934. - */ - @Test - public void testCircularSuppressedNestedException() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(e1); - e2.addSuppressed(e1); - e1.addSuppressed(e2); - LogManager.getLogger().error("Error", e1); - } - - /** - * . - */ - @Test - public void testCircularCauseExceptions() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(e1); - e1.initCause(e2); - LogManager.getLogger().error("Error", e1); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java index 73e1f18a2b3..2237b1ec31a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java @@ -24,6 +24,7 @@ /** * Class and package data used with a {@link StackTraceElement} in a {@link ExtendedStackTraceElement}. */ +@Deprecated public final class ExtendedClassInfo implements Serializable { private static final long serialVersionUID = 1L; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java index 0301e440972..134ad90f14a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java @@ -32,6 +32,7 @@ *
  • version
  • * */ +@Deprecated public final class ExtendedStackTraceElement implements Serializable { static final ExtendedStackTraceElement[] EMPTY_ARRAY = {}; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 3d6822600fc..6d4730b5ca5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -47,6 +47,7 @@ * TODO: Deserialize: Try to rebuild Throwable if the target exception is in this class loader? *

    */ +@Deprecated public class ThrowableProxy implements Serializable { private static final char EOL = Chars.LF; @@ -423,7 +424,7 @@ public String getExtendedStackTraceAsString( * @param textRenderer The message renderer. * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. - * @deprecated since 2.24.0. Use {@link #formatExtendedStackTraceTo(StringBuilder, List, TextRenderer, String, String, Integer)}. + * @deprecated since 2.24.0. Use {@link #formatExtendedStackTraceTo(StringBuilder, List, TextRenderer, String, String, int)}. */ @Deprecated public void formatExtendedStackTraceTo( diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java index 504bc6a11f9..d35fc881275 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java @@ -32,6 +32,7 @@ * {@link ThrowableProxyHelper} provides utilities required to initialize a new {@link ThrowableProxy} * instance. */ +@Deprecated final class ThrowableProxyHelper { private ThrowableProxyHelper() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index 6979c8d66f8..ab6f32ca4b6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -25,6 +25,7 @@ * {@link ThrowableProxyRenderer} is an internal utility providing the code to render a {@link ThrowableProxy} * to a {@link StringBuilder}. */ +@Deprecated final class ThrowableProxyRenderer { private static final String TAB = "\t"; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java index 13fbaede617..1ddd00d0a2e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java @@ -39,6 +39,7 @@ ExtendedStackTraceElementMixIn.ATTR_VERSION // @formatter:on }) +@Deprecated abstract class ExtendedStackTraceElementMixIn implements Serializable { protected static final String ATTR_CLASS_LOADER_NAME = StackTraceElementConstants.ATTR_CLASS_LOADER_NAME; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java index 4b2b4292a1c..44996a3ade7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java @@ -26,6 +26,7 @@ /** * Mix-in for {@link ThrowableProxy}. */ +@Deprecated abstract class ThrowableProxyMixIn { @JsonProperty(JsonConstants.ELT_CAUSE) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java index 3400a8c1070..eda9bcf32f2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java @@ -26,6 +26,7 @@ /** * Mix-in for {@link org.apache.logging.log4j.core.impl.ThrowableProxy}. */ +@Deprecated abstract class ThrowableProxyWithStacktraceAsStringMixIn { @JsonProperty(JsonConstants.ELT_CAUSE) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java index b7590015365..2ea10d3e1d1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java @@ -26,6 +26,7 @@ /** * Mix-in for {@link ThrowableProxy}. */ +@Deprecated abstract class ThrowableProxyWithoutStacktraceMixIn { @JsonProperty(JsonConstants.ELT_CAUSE) From c0b06b66767417d07a95b3ad36605ec6bc235e3b Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 21 Aug 2024 19:32:57 +0900 Subject: [PATCH 49/72] add golden samples --- .../log4j/core/pattern/ThrowableFullTest.java | 80 +++++++++++++++++++ .../log4j/core/pattern/ThrowableTest.java | 34 -------- .../ExtendedThrowableRenderer.txt | 28 +++---- .../RootThrowableRenderer.txt | 28 +++---- .../throwableRenderer/ThrowableRenderer.txt | 28 +++---- 5 files changed, 122 insertions(+), 76 deletions(-) create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java new file mode 100644 index 00000000000..a36cb4cdb78 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java @@ -0,0 +1,80 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.Collections; +import java.util.Objects; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Compare the full output of a renderer with expected golden sample. Therefore, changing the method name or + * changing the position(line count) where the exception created will cause the test fail. + */ +public class ThrowableFullTest { + @ParameterizedTest + @MethodSource("testFull_dataSource") + void testFull(final ThrowableRenderer renderer, final String expectedFilePath) throws IOException { + final Throwable throwable = createException("r", 1, 3); + final String actual = render(renderer, throwable); + final String expected = getContentFromResource(expectedFilePath); + assertThat(actual).isEqualTo(expected); + } + + static Stream testFull_dataSource() { + return Stream.of( + Arguments.of( + new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE), "ThrowableRenderer.txt"), + Arguments.of( + new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), + "RootThrowableRenderer.txt"), + Arguments.of( + new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), + "ExtendedThrowableRenderer.txt")); + } + + private static Throwable createException(final String name, int depth, int maxDepth) { + Exception r = new Exception(name); + if (depth < maxDepth) { + r.initCause(createException(name + "_c", depth + 1, maxDepth)); + r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); + } + return r; + } + + private static String getContentFromResource(String fileName) throws IOException { + fileName = "throwableRenderer/" + fileName; + String path = Objects.requireNonNull( + ThrowableTest.class.getClassLoader().getResource(fileName)) + .getPath(); + return new String(Files.readAllBytes(FileSystems.getDefault().getPath(path)), StandardCharsets.UTF_8); + } + + private static String render(final ThrowableRenderer renderer, final Throwable throwable) { + final StringBuilder stringBuilder = new StringBuilder(); + renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); + return stringBuilder.toString(); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index f2961ea669a..0154025f8da 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -18,13 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.IOException; import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; -import java.nio.file.Files; import java.util.Collections; -import java.util.Objects; import java.util.stream.Stream; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; @@ -100,27 +95,6 @@ void testConverter(String exceptionPattern, String filters, Integer depth, Strin } } - static Stream testFull_dataSource() { - return Stream.of( - Arguments.of( - new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE), "ThrowableRenderer.txt"), - Arguments.of( - new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "RootThrowableRenderer.txt"), - Arguments.of( - new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "ExtendedThrowableRenderer.txt")); - } - - @ParameterizedTest - @MethodSource("testFull_dataSource") - void testFull(final ThrowableRenderer renderer, final String expectedFilePath) throws IOException { - final Throwable throwable = createException("r", 1, 3); - final String expected = getContentFromResource(expectedFilePath); - final String actual = render(renderer, throwable); - assertThat(actual).isEqualTo(expected); - } - static Stream renderers_dataSource() { return Stream.of( Arguments.of(new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)), @@ -170,14 +144,6 @@ public void testThrowableRenderer() { assertThat(actual).isEqualTo(getStandardThrowableStackTrace(throwable)); } - private static String getContentFromResource(String fileName) throws IOException { - fileName = "throwableRenderer/" + fileName; - String path = Objects.requireNonNull( - ThrowableTest.class.getClassLoader().getResource(fileName)) - .getPath(); - return new String(Files.readAllBytes(FileSystems.getDefault().getPath(path)), StandardCharsets.UTF_8); - } - private static String render(final ThrowableRenderer renderer, final Throwable throwable) { final StringBuilder stringBuilder = new StringBuilder(); renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt index d888c71cd5c..1b307e83b8b 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt @@ -1,6 +1,6 @@ java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) [test-classes/:?] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] @@ -130,26 +130,26 @@ java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.3.1.jar:3.3.1] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.3.1.jar:3.3.1] Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt index e8d86c940a2..6e6d276177e 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt @@ -1,18 +1,18 @@ java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 130 more Wrapped by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 130 more Wrapped by: java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -142,14 +142,14 @@ Wrapped by: java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) Suppressed: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 130 more Wrapped by: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt index c47e532eab7..e2f70fdd28d 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt @@ -1,6 +1,6 @@ java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.testFullOutput(ThrowableTest.java:123) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -130,26 +130,26 @@ java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 130 more Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 130 more Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:248) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) ... 130 more Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:245) - at org.apache.logging.log4j.core.pattern.ThrowableTest.createException(ThrowableTest.java:247) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) ... 130 more From 08ba30ddc1c13eefa19e7cc6146c9ad7d377e422 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 21 Aug 2024 21:24:49 +0900 Subject: [PATCH 50/72] fix tests --- .../ExtendedThrowableRenderer.txt | 28 +++++++++---------- .../RootThrowableRenderer.txt | 28 +++++++++---------- .../throwableRenderer/ThrowableRenderer.txt | 28 +++++++++---------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt index 1b307e83b8b..cadd1c3984f 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt @@ -1,6 +1,6 @@ java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) [test-classes/:?] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] @@ -130,26 +130,26 @@ java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.3.1.jar:3.3.1] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.3.1.jar:3.3.1] Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] ... 130 more Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt index 6e6d276177e..3123fd5118c 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt @@ -1,18 +1,18 @@ java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 130 more Wrapped by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 130 more Wrapped by: java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -142,14 +142,14 @@ Wrapped by: java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) Suppressed: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 130 more Wrapped by: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt index e2f70fdd28d..2f77198c2e7 100644 --- a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt +++ b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt @@ -1,6 +1,6 @@ java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:25) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -130,26 +130,26 @@ java.lang.Exception: r at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 129 more Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 130 more Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 130 more Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 129 more Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:47) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) ... 130 more Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:44) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:46) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) + at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) ... 130 more From 0a36a46acc74f1dfb731d99a61bb3c2f7c31cb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 23 Sep 2024 13:19:35 +0200 Subject: [PATCH 51/72] Add tests --- .../test/java/foo/TestFriendlyException.java | 82 ++++++++ .../ExtendedThrowableRendererTest.java | 152 ++++++++++++++ .../pattern/RootThrowableRendererTest.java | 152 ++++++++++++++ .../core/pattern/ThrowableRendererTest.java | 186 ++++++++++++++++++ .../log4j/core/pattern/ThrowableTestMain.java | 72 ------- 5 files changed, 572 insertions(+), 72 deletions(-) create mode 100644 log4j-core-test/src/test/java/foo/TestFriendlyException.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java create mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java diff --git a/log4j-core-test/src/test/java/foo/TestFriendlyException.java b/log4j-core-test/src/test/java/foo/TestFriendlyException.java new file mode 100644 index 00000000000..2799ca1ced8 --- /dev/null +++ b/log4j-core-test/src/test/java/foo/TestFriendlyException.java @@ -0,0 +1,82 @@ +/* + * 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 foo; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +/** + * A testing friendly exception featuring + *
      + *
    • Non-Log4j package origin1
    • + *
    • Sufficient causal chain depth
    • + *
    • Decorated with suppressed exceptions
    • + *
    • A stack trace free of clutter (i.e., elements from JUnit, JDK, etc.)
    • + *
    + *

    + * 1 This becomes handy for tests observing stack trace manipulation effects of Log4j. + *

    + */ +public final class TestFriendlyException extends RuntimeException { + + private static final String[] EXCLUDED_CLASS_NAME_PREFIXES = { + "java.lang", "jdk.internal", "org.junit", "sun.reflect" + }; + + public static final TestFriendlyException INSTANCE = create("r", 0, 2); + + static { + // Ensure the distinct packaging + assertThat(TestFriendlyException.class.getPackage().getName()).doesNotStartWith("org.apache"); + } + + private static TestFriendlyException create(final String name, final int depth, final int maxDepth) { + final TestFriendlyException error = new TestFriendlyException(name); + if (depth < maxDepth) { + error.initCause(create(name + "_c", depth + 1, maxDepth)); + error.addSuppressed(create(name + "_s", depth + 1, maxDepth)); + } + return error; + } + + private TestFriendlyException(final String message) { + super(message); + removeExcludedStackTraceElements(); + } + + private void removeExcludedStackTraceElements() { + final StackTraceElement[] oldStackTrace = getStackTrace(); + final boolean[] seenExcludedStackTraceElement = {false}; + final StackTraceElement[] newStackTrace = Arrays.stream(oldStackTrace) + .filter(stackTraceElement -> { + if (seenExcludedStackTraceElement[0]) { + return false; + } + final String className = stackTraceElement.getClassName(); + for (final String excludedClassNamePrefix : EXCLUDED_CLASS_NAME_PREFIXES) { + if (className.startsWith(excludedClassNamePrefix)) { + seenExcludedStackTraceElement[0] = true; + return false; + } + } + return true; + }) + .toArray(StackTraceElement[]::new); + setStackTrace(newStackTrace); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java new file mode 100644 index 00000000000..4141d314f28 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java @@ -0,0 +1,152 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.assertStackTraceLineMatches; + +import foo.TestFriendlyException; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class ExtendedThrowableRendererTest { + + static final String NEWLINE = System.lineSeparator(); + + static final Exception EXCEPTION = TestFriendlyException.INSTANCE; + + static int[] maxLineCounts() { + return ThrowableRendererTest.maxLineCounts(); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_maxLineCount_should_match(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingLog4j(emptyList(), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + asList( + "foo.TestFriendlyException: r", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at org.apache.logging.log4j.core.pattern.ExtendedThrowableRendererTest.(ExtendedThrowableRendererTest.java:%DIGITS%) [test-classes/:?]", + " Suppressed: foo.TestFriendlyException: r_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more")); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingLog4j(singletonList("foo"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + asList( + "foo.TestFriendlyException: r", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ExtendedThrowableRendererTest.(ExtendedThrowableRendererTest.java:%DIGITS%) [test-classes/:?]", + " Suppressed: foo.TestFriendlyException: r_s", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " ... suppressed 2 lines", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c", + " ... suppressed 2 lines", + " ... 3 more")); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingLog4j(singletonList("org.apache"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + asList( + "foo.TestFriendlyException: r", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... ", + " Suppressed: foo.TestFriendlyException: r_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", + " ... 3 more")); + } + + private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { + final ThrowableRenderer renderer = new ExtendedThrowableRenderer(ignoredPackageNames, maxLineCount); + final StringBuilder rendererOutputBuilder = new StringBuilder(); + renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); + return rendererOutputBuilder.toString(); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java new file mode 100644 index 00000000000..c8b062e7e94 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java @@ -0,0 +1,152 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.EXCEPTION; +import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.NEWLINE; +import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.assertStackTraceLineMatches; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class RootThrowableRendererTest { + + static int[] maxLineCounts() { + return ThrowableRendererTest.maxLineCounts(); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_maxLineCount_should_match(final int maxLineCount) { + final String stackTrace = renderStackTrace(emptyList(), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + Arrays.asList( + "foo.TestFriendlyException: r_c_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.RootThrowableRendererTest.maxLineCounts(RootThrowableRendererTest.java:%DIGITS%)", + " Suppressed: foo.TestFriendlyException: r_s_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + " Wrapped by: foo.TestFriendlyException: r_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more")); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { + final String stackTrace = renderStackTrace(singletonList("foo"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + Arrays.asList( + "foo.TestFriendlyException: r_c_c", + " ... suppressed 2 lines", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r_c", + " ... suppressed 2 lines", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " ... suppressed 2 lines", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.RootThrowableRendererTest.maxLineCounts(RootThrowableRendererTest.java:%DIGITS%)", + " Suppressed: foo.TestFriendlyException: r_s_c", + " ... suppressed 2 lines", + " ... 4 more", + " Wrapped by: foo.TestFriendlyException: r_s", + " ... suppressed 2 lines", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " ... suppressed 2 lines", + " ... 4 more")); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { + final String stackTrace = renderStackTrace(singletonList("org.apache"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + Arrays.asList( + "foo.TestFriendlyException: r_c_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + "Wrapped by: foo.TestFriendlyException: r", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", + " ... suppressed 2 lines", + " Suppressed: foo.TestFriendlyException: r_s_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more", + " Wrapped by: foo.TestFriendlyException: r_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 4 more")); + } + + private static String renderStackTrace(final List ignoredPackageNames, final int maxLineCount) { + final ThrowableRenderer renderer = + new RootThrowableRenderer(ignoredPackageNames, maxLineCount); + final StringBuilder rendererOutputBuilder = new StringBuilder(); + renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); + return rendererOutputBuilder.toString(); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java new file mode 100644 index 00000000000..05478b52d71 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java @@ -0,0 +1,186 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +import foo.TestFriendlyException; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class ThrowableRendererTest { + + static final String NEWLINE = System.lineSeparator(); + + static final Exception EXCEPTION = TestFriendlyException.INSTANCE; + + @Test + void output_should_match_Throwable_printStackTrace() { + final String log4jOutput = renderStackTraceUsingLog4j(emptyList(), Integer.MAX_VALUE); + final String javaOutput = renderStackTraceUsingJava(); + assertThat(log4jOutput).isEqualTo(javaOutput); + } + + static int[] maxLineCounts() { + return new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, Integer.MAX_VALUE}; + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_maxLineCount_should_match_Throwable_printStackTrace(final int maxLineCount) { + final String log4jOutput = renderStackTraceUsingLog4j(emptyList(), maxLineCount); + final String javaOutput = renderStackTraceUsingJava(maxLineCount); + assertThat(log4jOutput).isEqualTo(javaOutput); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingLog4j(singletonList("foo"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + asList( + "foo.TestFriendlyException: r", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", + " Suppressed: foo.TestFriendlyException: r_s", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " ... suppressed 2 lines", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c", + " ... suppressed 2 lines", + " ... 3 more")); + } + + @ParameterizedTest + @MethodSource("maxLineCounts") + void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingLog4j(singletonList("org.apache"), maxLineCount); + assertStackTraceLineMatches( + stackTrace, + maxLineCount, + asList( + "foo.TestFriendlyException: r", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", + " ... ", + " Suppressed: foo.TestFriendlyException: r_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", + " ... 3 more")); + } + + private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { + final ThrowableRenderer renderer = + new ThrowableRenderer<>(ignoredPackageNames, maxLineCount); + final StringBuilder rendererOutputBuilder = new StringBuilder(); + renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); + return rendererOutputBuilder.toString(); + } + + private static String renderStackTraceUsingJava(final int maxLineCount) { + final String stackTrace = renderStackTraceUsingJava(); + if (maxLineCount == Integer.MAX_VALUE) { + return stackTrace; + } + return splitLines(stackTrace).stream().limit(maxLineCount).collect(Collectors.joining()); + } + + @SuppressWarnings("SameParameterValue") + private static String renderStackTraceUsingJava() { + final Charset charset = StandardCharsets.UTF_8; + try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final PrintStream printStream = new PrintStream(outputStream, false, charset.name())) { + EXCEPTION.printStackTrace(printStream); + printStream.flush(); + return new String(outputStream.toByteArray(), charset); + } catch (final Exception error) { + throw new RuntimeException(error); + } + } + + static void assertStackTraceLineMatches( + final String actualStackTrace, final int maxLineCount, final List expectedStackTraceLineRegexes) { + final List actualStackTraceLines = splitLines(actualStackTrace); + final int expectedLineCount = Math.min(maxLineCount, expectedStackTraceLineRegexes.size()); + assertThat(actualStackTraceLines).hasSize(expectedLineCount); + for (int lineIndex = 0; lineIndex < expectedLineCount; lineIndex++) { + final String actualStackTraceLine = actualStackTraceLines.get(lineIndex); + final String expectedStackTraceLineRegex = expectedStackTraceLineRegexes.get(lineIndex); + final String interpolatedExpectedStackTraceLineRegex = + expectedStackTraceLineRegex.replaceAll("%DIGITS%", "\\\\E\\\\d+\\\\Q"); + assertThat(actualStackTraceLine) + .as("line at index %d of stack trace:%n%s", lineIndex, actualStackTrace) + .matches("^\\Q" + interpolatedExpectedStackTraceLineRegex + NEWLINE + "\\E$"); + } + } + + private static List splitLines(final String text) { + final List lines = new ArrayList<>(); + int startIndex = 0; + int lfIndex; + while ((lfIndex = text.indexOf('\n', startIndex)) != -1) { + final String line = text.substring(startIndex, lfIndex + 1); + lines.add(line); + startIndex = lfIndex + 1; + } + return lines; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java deleted file mode 100644 index f5ce4c2e053..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableTestMain.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import java.util.Collections; -import java.util.List; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; - -public class ThrowableTestMain { - - public static void main(String[] args) { - Throwable r = createException("r", 1, 3); - renderException(r); - renderException(r, new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)); - renderException(r, "%ex"); - renderException(r, new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); - renderException(r, "%xEx"); - renderException(r, new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)); - renderException(r, "%rEx"); - } - - private static Throwable createException(String name, int depth, int maxDepth) { - Exception r = new Exception(name); - if (depth < maxDepth) { - r.initCause(createException(name + "_c", depth + 1, maxDepth)); - r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); - } - return r; - } - - private static void renderException(Throwable throwable) { - System.out.format("%n=== %-25s ==============================%n%n", "Throwable"); - throwable.printStackTrace(System.out); - } - - private static void renderException(Throwable throwable, ThrowableRenderer renderer) { - System.out.format( - "%n=== %-25s ==============================%n%n", - renderer.getClass().getSimpleName()); - final StringBuilder stringBuilder = new StringBuilder(); - renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); - System.out.println(stringBuilder); - } - - private static void renderException(Throwable throwable, String pattern) { - System.out.format("%n=== %-25s ==============================%n%n", String.format("pattern(\"%s\")", pattern)); - PatternParser parser = new PatternParser(PatternConverter.CATEGORY); - List formatters = parser.parse(pattern); - if (formatters.size() != 1) { - throw new IllegalArgumentException("was expecting a single formatter, found " + formatters.size()); - } - PatternFormatter formatter = formatters.get(0); - Log4jLogEvent logEvent = Log4jLogEvent.newBuilder().setThrown(throwable).build(); - StringBuilder stringBuilder = new StringBuilder(); - formatter.format(logEvent, stringBuilder); - System.out.println(stringBuilder); - } -} From 3fa309d6b95473ed786090517306d361b08c0b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 23 Sep 2024 13:27:58 +0200 Subject: [PATCH 52/72] Fix `bnd-baseline` failures --- log4j-api-test/pom.xml | 5 +++++ log4j-core-test/pom.xml | 5 +++++ .../org/apache/logging/log4j/core/impl/package-info.java | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/log4j-api-test/pom.xml b/log4j-api-test/pom.xml index e1fb806b9b4..aef8a1b5d64 100644 --- a/log4j-api-test/pom.xml +++ b/log4j-api-test/pom.xml @@ -144,6 +144,11 @@ mockito-inline test + + org.jspecify + jspecify + test + org.osgi diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml index f770ea88703..1c1f771c5d2 100644 --- a/log4j-core-test/pom.xml +++ b/log4j-core-test/pom.xml @@ -225,6 +225,11 @@ javax.jms-api test + + org.jspecify + jspecify + test + com.sun.mail javax.mail diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java index 0c3b08f43a7..2d4bdcd199c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java @@ -18,7 +18,7 @@ * Log4j 2 private implementation classes. */ @Export -@Version("2.24.0") +@Version("2.25.0") package org.apache.logging.log4j.core.impl; import org.osgi.annotation.bundle.Export; From 9f9da1a5a9d57cf5bc49b4dfce5d2bacf925846f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 23 Sep 2024 22:07:58 +0200 Subject: [PATCH 53/72] Remove deprecated `ThrowableFullTest` --- .../log4j/core/pattern/ThrowableFullTest.java | 80 --------- .../util/internal/StringBuildersTest.java | 13 +- .../ExtendedThrowableRenderer.txt | 155 ------------------ .../RootThrowableRenderer.txt | 155 ------------------ .../throwableRenderer/ThrowableRenderer.txt | 155 ------------------ 5 files changed, 7 insertions(+), 551 deletions(-) delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java deleted file mode 100644 index a36cb4cdb78..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.util.Collections; -import java.util.Objects; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -/** - * Compare the full output of a renderer with expected golden sample. Therefore, changing the method name or - * changing the position(line count) where the exception created will cause the test fail. - */ -public class ThrowableFullTest { - @ParameterizedTest - @MethodSource("testFull_dataSource") - void testFull(final ThrowableRenderer renderer, final String expectedFilePath) throws IOException { - final Throwable throwable = createException("r", 1, 3); - final String actual = render(renderer, throwable); - final String expected = getContentFromResource(expectedFilePath); - assertThat(actual).isEqualTo(expected); - } - - static Stream testFull_dataSource() { - return Stream.of( - Arguments.of( - new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE), "ThrowableRenderer.txt"), - Arguments.of( - new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "RootThrowableRenderer.txt"), - Arguments.of( - new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "ExtendedThrowableRenderer.txt")); - } - - private static Throwable createException(final String name, int depth, int maxDepth) { - Exception r = new Exception(name); - if (depth < maxDepth) { - r.initCause(createException(name + "_c", depth + 1, maxDepth)); - r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); - } - return r; - } - - private static String getContentFromResource(String fileName) throws IOException { - fileName = "throwableRenderer/" + fileName; - String path = Objects.requireNonNull( - ThrowableTest.class.getClassLoader().getResource(fileName)) - .getPath(); - return new String(Files.readAllBytes(FileSystems.getDefault().getPath(path)), StandardCharsets.UTF_8); - } - - private static String render(final ThrowableRenderer renderer, final Throwable throwable) { - final StringBuilder stringBuilder = new StringBuilder(); - renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); - return stringBuilder.toString(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java index d2fd4ecfc7b..4b6099e82e5 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java @@ -28,7 +28,7 @@ class StringBuildersTest { - static Stream testTruncateLines_happyCases() { + static Stream truncateAfterDelimiter_should_succeed_inputs() { return Stream.of( // maxOccurrenceCount < lines count Arguments.of("abc#def#ghi#jkl#", "#", 2), @@ -64,8 +64,9 @@ static Stream testTruncateLines_happyCases() { } @ParameterizedTest - @MethodSource("testTruncateLines_happyCases") - void testTruncateLinesHappyCases(final String input, final String delimiter, final int maxOccurrenceCount) { + @MethodSource("truncateAfterDelimiter_should_succeed_inputs") + void truncateAfterDelimiter_should_succeed( + final String input, final String delimiter, final int maxOccurrenceCount) { final StringBuilder buffer = new StringBuilder(input); StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount); final String expected; @@ -81,7 +82,7 @@ void testTruncateLinesHappyCases(final String input, final String delimiter, fin assertThat(buffer.toString()).isEqualTo(expected); } - static Stream testTruncateLines_failCases() { + static Stream truncateAfterDelimiter_should_fail_inputs() { return Stream.of( // negative maxOccurrenceCount Arguments.of("abc#def#ghi#jkl#", "#", -1, IllegalArgumentException.class), @@ -92,8 +93,8 @@ static Stream testTruncateLines_failCases() { } @ParameterizedTest - @MethodSource("testTruncateLines_failCases") - void testTruncateLinesFailCases( + @MethodSource("truncateAfterDelimiter_should_fail_inputs") + void truncateAfterDelimiter_should_fail( final String input, final String delimiter, final int maxOccurrenceCount, final Class expected) { final StringBuilder buffer = input == null ? null : new StringBuilder(input); assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)) diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt deleted file mode 100644 index cadd1c3984f..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) [test-classes/:?] - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] - at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) [junit-platform-commons-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.3.1.jar:3.3.1] - Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 130 more - Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 130 more -Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 130 more -Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt deleted file mode 100644 index 3123fd5118c..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more -Wrapped by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more -Wrapped by: java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) - Suppressed: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more - Wrapped by: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt deleted file mode 100644 index 2f77198c2e7..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) - Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more - Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more -Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more -Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more From 97fd136878a9fc4b943251866dff22355890c4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 23 Sep 2024 22:13:34 +0200 Subject: [PATCH 54/72] Add changelog entries --- .../2691_change_PatternLayout_exception_rendering.xml | 8 ++++++++ src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml | 8 ++++++++ .../2691_fix_PatternLayout_exception_rendering.xml | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml create mode 100644 src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml create mode 100644 src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml diff --git a/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml b/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml new file mode 100644 index 00000000000..74d9671bcdb --- /dev/null +++ b/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml @@ -0,0 +1,8 @@ + + + + Consolidate exception rendering in Pattern Layout + diff --git a/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml b/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml new file mode 100644 index 00000000000..b7c39d48c8c --- /dev/null +++ b/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml @@ -0,0 +1,8 @@ + + + + `ThrowableProxy` and its usages are deprecated + diff --git a/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml b/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml new file mode 100644 index 00000000000..937bbb61c21 --- /dev/null +++ b/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml @@ -0,0 +1,10 @@ + + + + + + Fix certain exception rendering issues in Pattern Layout + From 9e55f5c66ca46fa2e36054e789ecd5f06b252e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 24 Sep 2024 11:42:36 +0200 Subject: [PATCH 55/72] Revert redundant `ThrowableProxy` and `ThrowableProxyRenderer` fixes --- .../log4j/core/impl/ThrowableProxy.java | 51 ++----------------- .../core/impl/ThrowableProxyRenderer.java | 21 ++++---- 2 files changed, 12 insertions(+), 60 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 6d4730b5ca5..61d292dc487 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -298,32 +298,10 @@ public String getCauseStackTraceAsString( final String suffix, final String lineSeparator) { final StringBuilder sb = new StringBuilder(); - ThrowableProxyRenderer.formatCauseStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); + ThrowableProxyRenderer.formatCauseStackTrace(this, sb, ignorePackages, textRenderer, suffix, lineSeparator); return sb.toString(); } - /** - * Formats the stack trace with cause exception. - * - * @param sb Destination. - * @param ignorePackages List of packages to be ignored in the trace. - * @param textRenderer The message renderer. - * @param suffix Append this to the end of each stack frame. - * @param lineSeparator The end-of-line separator. - * @param maxLineCount The total line count of final result - */ - public void formatCauseStackTraceTo( - final StringBuilder sb, - final List ignorePackages, - final TextRenderer textRenderer, - final String suffix, - final String lineSeparator, - final int maxLineCount) { - ThrowableProxyRenderer.formatCauseStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); - } - /** * Returns the number of elements that are being omitted because they are common with the parent Throwable's stack * trace. @@ -412,7 +390,7 @@ public String getExtendedStackTraceAsString( final String suffix, final String lineSeparator) { final StringBuilder sb = new StringBuilder(1024); - formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); + formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator); return sb.toString(); } @@ -424,9 +402,7 @@ public String getExtendedStackTraceAsString( * @param textRenderer The message renderer. * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. - * @deprecated since 2.24.0. Use {@link #formatExtendedStackTraceTo(StringBuilder, List, TextRenderer, String, String, int)}. */ - @Deprecated public void formatExtendedStackTraceTo( final StringBuilder sb, final List ignorePackages, @@ -434,28 +410,7 @@ public void formatExtendedStackTraceTo( final String suffix, final String lineSeparator) { ThrowableProxyRenderer.formatExtendedStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, Integer.MAX_VALUE); - } - - /** - * Formats the stack trace including packaging information. - * - * @param sb Destination. - * @param ignorePackages List of packages to be ignored in the trace. - * @param textRenderer The message renderer. - * @param suffix Append this to the end of each stack frame. - * @param lineSeparator The end-of-line separator. - * @param maxLineCount The total line count of final result - */ - public void formatExtendedStackTraceTo( - final StringBuilder sb, - final List ignorePackages, - final TextRenderer textRenderer, - final String suffix, - final String lineSeparator, - final int maxLineCount) { - ThrowableProxyRenderer.formatExtendedStackTraceTo( - this, sb, ignorePackages, textRenderer, suffix, lineSeparator, maxLineCount); + this, sb, ignorePackages, textRenderer, suffix, lineSeparator); } public String getLocalizedMessage() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java index ab6f32ca4b6..431442095bf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java @@ -18,7 +18,6 @@ import java.util.List; import org.apache.logging.log4j.core.pattern.TextRenderer; -import org.apache.logging.log4j.core.util.internal.StringBuilders; import org.apache.logging.log4j.util.Strings; /** @@ -242,9 +241,10 @@ static void formatExtendedStackTraceTo( final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator, - final int maxLineCount) { - renderOn(src, sb, textRenderer); + final String lineSeparator) { + textRenderer.render(src.getName(), sb, "Name"); + textRenderer.render(": ", sb, "NameMessageSeparator"); + textRenderer.render(src.getMessage(), sb, "Message"); renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); final StackTraceElement[] causedTrace = @@ -261,7 +261,6 @@ static void formatExtendedStackTraceTo( lineSeparator); formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator); formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator); - StringBuilders.truncateAfterDelimiter(sb, lineSeparator, maxLineCount); } /** @@ -274,24 +273,23 @@ static void formatExtendedStackTraceTo( * @param suffix Append this to the end of each stack frame. * @param lineSeparator The end-of-line separator. */ - static void formatCauseStackTraceTo( + static void formatCauseStackTrace( final ThrowableProxy src, final StringBuilder sb, final List ignorePackages, final TextRenderer textRenderer, final String suffix, - final String lineSeparator, - final int maxLineCount) { + final String lineSeparator) { final ThrowableProxy causeProxy = src.getCauseProxy(); if (causeProxy != null) { formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator); sb.append(WRAPPED_BY_LABEL); - renderSuffix(suffix, sb, textRenderer); + ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer); } renderOn(src, sb, textRenderer); - renderSuffix(suffix, sb, textRenderer); + ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer); textRenderer.render(lineSeparator, sb, "Text"); - formatElements( + ThrowableProxyRenderer.formatElements( sb, Strings.EMPTY, 0, @@ -301,7 +299,6 @@ static void formatCauseStackTraceTo( textRenderer, suffix, lineSeparator); - StringBuilders.truncateAfterDelimiter(sb, lineSeparator, maxLineCount); } private static void renderOn( From 2e47d49d96bb4b3b4a096646af54d744c8a62459 Mon Sep 17 00:00:00 2001 From: alanyu Date: Tue, 24 Sep 2024 22:36:15 +0900 Subject: [PATCH 56/72] remove unused tests --- .../log4j/core/pattern/ThrowableFullTest.java | 80 --------- .../ExtendedThrowableRenderer.txt | 155 ------------------ .../RootThrowableRenderer.txt | 155 ------------------ .../throwableRenderer/ThrowableRenderer.txt | 155 ------------------ 4 files changed, 545 deletions(-) delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt delete mode 100644 log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java deleted file mode 100644 index a36cb4cdb78..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableFullTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.util.Collections; -import java.util.Objects; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -/** - * Compare the full output of a renderer with expected golden sample. Therefore, changing the method name or - * changing the position(line count) where the exception created will cause the test fail. - */ -public class ThrowableFullTest { - @ParameterizedTest - @MethodSource("testFull_dataSource") - void testFull(final ThrowableRenderer renderer, final String expectedFilePath) throws IOException { - final Throwable throwable = createException("r", 1, 3); - final String actual = render(renderer, throwable); - final String expected = getContentFromResource(expectedFilePath); - assertThat(actual).isEqualTo(expected); - } - - static Stream testFull_dataSource() { - return Stream.of( - Arguments.of( - new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE), "ThrowableRenderer.txt"), - Arguments.of( - new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "RootThrowableRenderer.txt"), - Arguments.of( - new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE), - "ExtendedThrowableRenderer.txt")); - } - - private static Throwable createException(final String name, int depth, int maxDepth) { - Exception r = new Exception(name); - if (depth < maxDepth) { - r.initCause(createException(name + "_c", depth + 1, maxDepth)); - r.addSuppressed(createException(name + "_s", depth + 1, maxDepth)); - } - return r; - } - - private static String getContentFromResource(String fileName) throws IOException { - fileName = "throwableRenderer/" + fileName; - String path = Objects.requireNonNull( - ThrowableTest.class.getClassLoader().getResource(fileName)) - .getPath(); - return new String(Files.readAllBytes(FileSystems.getDefault().getPath(path)), StandardCharsets.UTF_8); - } - - private static String render(final ThrowableRenderer renderer, final Throwable throwable) { - final StringBuilder stringBuilder = new StringBuilder(); - renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); - return stringBuilder.toString(); - } -} diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt deleted file mode 100644 index cadd1c3984f..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/ExtendedThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) [test-classes/:?] - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] - at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) [junit-platform-commons-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) [?:?] - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) [?:?] - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) [?:?] - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) [?:?] - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?] - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?] - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?] - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) [junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) [junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) [surefire-junit-platform-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.3.1.jar:3.3.1] - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.3.1.jar:3.3.1] - Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 130 more - Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 130 more -Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) [test-classes/:?] - ... 130 more -Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) [test-classes/:?] - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) [test-classes/:?] - ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt deleted file mode 100644 index 3123fd5118c..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/RootThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more -Wrapped by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more -Wrapped by: java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) - Suppressed: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more - Wrapped by: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more diff --git a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt b/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt deleted file mode 100644 index 2f77198c2e7..00000000000 --- a/log4j-core-test/src/test/resources/throwableRenderer/ThrowableRenderer.txt +++ /dev/null @@ -1,155 +0,0 @@ -java.lang.Exception: r - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.testFull(ThrowableFullTest.java:40) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) - at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) - at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) - at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:94) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) - at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:142) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:110) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) - at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) - at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) - at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) - at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) - at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) - at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) - at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:110) - at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:44) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:120) - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) - Suppressed: java.lang.Exception: r_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 129 more - Suppressed: java.lang.Exception: r_s_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more - Caused by: java.lang.Exception: r_s_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more -Caused by: java.lang.Exception: r_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 129 more - Suppressed: java.lang.Exception: r_c_s - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:62) - ... 130 more -Caused by: java.lang.Exception: r_c_c - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:59) - at org.apache.logging.log4j.core.pattern.ThrowableFullTest.createException(ThrowableFullTest.java:61) - ... 130 more From 27d4663012d379251637b70454b473adb97ebbb2 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 25 Sep 2024 00:07:48 +0900 Subject: [PATCH 57/72] fix: tests --- .../core/pattern/ThrowablePatternConverterTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 8b6c750f32e..1a59ea77639 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -105,7 +105,7 @@ public void testShortClassName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals(packageName + "ThrowablePatternConverterTest\n", result, "The class names should be same"); + assertEquals(packageName + "ThrowablePatternConverterTest" + Strings.LINE_SEPARATOR, result, "The class names should be same"); } @Test @@ -124,7 +124,7 @@ public void testShortFileName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("ThrowablePatternConverterTest.java\n", result, "The file names should be same"); + assertEquals("ThrowablePatternConverterTest.java" + Strings.LINE_SEPARATOR, result, "The file names should be same"); } @Test @@ -164,7 +164,7 @@ public void testShortLocalizedMessage() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("I am localized.\n", result, "The messages should be same"); + assertEquals("I am localized." + Strings.LINE_SEPARATOR, result, "The messages should be same"); } @Test @@ -183,7 +183,7 @@ public void testShortMessage() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("IllegalArgument\n", result, "The messages should be same"); + assertEquals("IllegalArgument" + Strings.LINE_SEPARATOR, result, "The messages should be same"); } @Test @@ -202,7 +202,7 @@ public void testShortMethodName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("testShortMethodName\n", result, "The method names should be same"); + assertEquals("testShortMethodName" + Strings.LINE_SEPARATOR, result, "The method names should be same"); } @Test From 980da421dba5089af08de1b0d16fed0de65b901b Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 25 Sep 2024 00:18:23 +0900 Subject: [PATCH 58/72] style: fix style --- .../log4j/core/pattern/ThrowablePatternConverterTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 1a59ea77639..4a6e2a6fef5 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -105,7 +105,10 @@ public void testShortClassName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals(packageName + "ThrowablePatternConverterTest" + Strings.LINE_SEPARATOR, result, "The class names should be same"); + assertEquals( + packageName + "ThrowablePatternConverterTest" + Strings.LINE_SEPARATOR, + result, + "The class names should be same"); } @Test @@ -124,7 +127,8 @@ public void testShortFileName() { final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); - assertEquals("ThrowablePatternConverterTest.java" + Strings.LINE_SEPARATOR, result, "The file names should be same"); + assertEquals( + "ThrowablePatternConverterTest.java" + Strings.LINE_SEPARATOR, result, "The file names should be same"); } @Test From 1728fa997ac0e7aebfbcd1910586af8f73beed02 Mon Sep 17 00:00:00 2001 From: alanyu Date: Wed, 25 Sep 2024 10:04:34 +0900 Subject: [PATCH 59/72] tests: fix line separator --- .../logging/log4j/taglib/CatchingTagTest.java | 6 ++++- .../taglib/LoggingMessageTagSupportTest.java | 22 +++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java index adbdbe66289..a7eeb30f033 100644 --- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java +++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/CatchingTagTest.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.util.Strings; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -79,7 +80,10 @@ private void verify(final String expected) { final List events = listApp.getMessages(); try { assertEquals("Incorrect number of messages.", 1, events.size()); - assertEquals("Incorrect message.", "o.a.l.l.t.CatchingTagTest " + expected + "\n", events.get(0)); + assertEquals( + "Incorrect message.", + "o.a.l.l.t.CatchingTagTest " + expected + Strings.LINE_SEPARATOR, + events.get(0)); } finally { listApp.clear(); } diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java index d3db4bd62a7..d64bb1711cc 100644 --- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java +++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/LoggingMessageTagSupportTest.java @@ -29,6 +29,7 @@ import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.util.Strings; import org.junit.ClassRule; import org.junit.Test; import org.springframework.mock.web.MockBodyContent; @@ -136,7 +137,8 @@ public void testDoEndTagStringMessageNoMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify( - "Another message for testDoEndTagStringMessageNoMarkerException ERROR M- E java.lang.Exception: This is a test\n"); + "Another message for testDoEndTagStringMessageNoMarkerException ERROR M- E java.lang.Exception: This is a test" + + Strings.LINE_SEPARATOR); } @Test @@ -149,7 +151,8 @@ public void testDoEndTagStringMessageMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify( - "Final message for testDoEndTagStringMessageMarkerException TRACE M-F02 E java.lang.RuntimeException: This is another test\n"); + "Final message for testDoEndTagStringMessageMarkerException TRACE M-F02 E java.lang.RuntimeException: This is another test" + + Strings.LINE_SEPARATOR); } @Test @@ -175,7 +178,8 @@ public void testDoEndTagStringWithParametersMarkerAndException() throws Exceptio this.tag.setMessage("Final message with [{}] parameter of [{}]"); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify("Final message with [Z] parameter of [SECONDS] DEBUG M-N03 E java.lang.Error: This is the last test\n"); + verify("Final message with [Z] parameter of [SECONDS] DEBUG M-N03 E java.lang.Error: This is the last test" + + Strings.LINE_SEPARATOR); } @Test @@ -210,8 +214,8 @@ public void testDoEndTagMessageNoMarkerException() throws Exception { logger.getMessageFactory().newMessage("Third message for testDoEndTagMessageNoMarkerException")); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify( - "Third message for testDoEndTagMessageNoMarkerException TRACE M- E java.lang.Exception: This is a test\n"); + verify("Third message for testDoEndTagMessageNoMarkerException TRACE M- E java.lang.Exception: This is a test" + + Strings.LINE_SEPARATOR); } @Test @@ -225,7 +229,7 @@ public void testDoEndTagMessageMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify("Final message for testDoEndTagMessageMarkerException ERROR M-F02 E java.lang.RuntimeException: " - + "This is another test\n"); + + "This is another test" + Strings.LINE_SEPARATOR); } @Test @@ -257,8 +261,8 @@ public void testDoEndTagObjectNoMarkerException() throws Exception { this.tag.setMessage(new MyMessage("Third message for testDoEndTagObjectNoMarkerException")); assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); - verify( - "Third message for testDoEndTagObjectNoMarkerException TRACE M- E java.lang.Exception: This is a test\n"); + verify("Third message for testDoEndTagObjectNoMarkerException TRACE M- E java.lang.Exception: This is a test" + + Strings.LINE_SEPARATOR); } @Test @@ -271,7 +275,7 @@ public void testDoEndTagObjectMarkerException() throws Exception { assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag()); verify("Final message for testDoEndTagObjectMarkerException ERROR M-F02 E java.lang.RuntimeException: " - + "This is another test\n"); + + "This is another test" + Strings.LINE_SEPARATOR); } private void verify(final String expected) { From d07e14a9419d28ed3c9324419e5753f4cebc644c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 25 Sep 2024 09:31:16 +0200 Subject: [PATCH 60/72] Rework `ThrowablePatternConverter` et al. --- ...owableExtendedStackTraceRendererTest.java} | 13 +- ...owableInvertedStackTraceRendererTest.java} | 22 +- ...a => ThrowableStackTraceRendererTest.java} | 8 +- .../log4j/core/pattern/ThrowableTest.java | 17 +- .../log4j/core/layout/PatternLayout.java | 2 +- .../ExtendedThrowablePatternConverter.java | 57 +--- .../log4j/core/pattern/PatternParser.java | 2 +- .../RootThrowablePatternConverter.java | 57 +--- ... ThrowableExtendedStackTraceRenderer.java} | 12 +- ... ThrowableInvertedStackTraceRenderer.java} | 8 +- .../pattern/ThrowablePatternConverter.java | 199 +++++------- .../pattern/ThrowablePropertyRenderer.java | 98 ++++++ .../log4j/core/pattern/ThrowableRenderer.java | 275 +--------------- .../pattern/ThrowableStackTraceRenderer.java | 297 ++++++++++++++++++ .../log4j/core/pattern/package-info.java | 2 +- 15 files changed, 558 insertions(+), 511 deletions(-) rename log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/{ExtendedThrowableRendererTest.java => ThrowableExtendedStackTraceRendererTest.java} (93%) rename log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/{RootThrowableRendererTest.java => ThrowableInvertedStackTraceRendererTest.java} (89%) rename log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/{ThrowableRendererTest.java => ThrowableStackTraceRendererTest.java} (97%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/{ExtendedThrowableRenderer.java => ThrowableExtendedStackTraceRenderer.java} (93%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/{RootThrowableRenderer.java => ThrowableInvertedStackTraceRenderer.java} (90%) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePropertyRenderer.java create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java similarity index 93% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java index 4141d314f28..5695b1a1f8a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java @@ -19,21 +19,21 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.assertStackTraceLineMatches; +import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.assertStackTraceLineMatches; import foo.TestFriendlyException; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -class ExtendedThrowableRendererTest { +class ThrowableExtendedStackTraceRendererTest { static final String NEWLINE = System.lineSeparator(); static final Exception EXCEPTION = TestFriendlyException.INSTANCE; static int[] maxLineCounts() { - return ThrowableRendererTest.maxLineCounts(); + return ThrowableStackTraceRendererTest.maxLineCounts(); } @ParameterizedTest @@ -47,7 +47,7 @@ void output_produced_with_maxLineCount_should_match(final int maxLineCount) { "foo.TestFriendlyException: r", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at org.apache.logging.log4j.core.pattern.ExtendedThrowableRendererTest.(ExtendedThrowableRendererTest.java:%DIGITS%) [test-classes/:?]", + " at org.apache.logging.log4j.core.pattern.ThrowableExtendedStackTraceRendererTest.(ThrowableExtendedStackTraceRendererTest.java:%DIGITS%) [test-classes/:?]", " Suppressed: foo.TestFriendlyException: r_s", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", @@ -84,7 +84,7 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(fi asList( "foo.TestFriendlyException: r", " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ExtendedThrowableRendererTest.(ExtendedThrowableRendererTest.java:%DIGITS%) [test-classes/:?]", + " at org.apache.logging.log4j.core.pattern.ThrowableExtendedStackTraceRendererTest.(ThrowableExtendedStackTraceRendererTest.java:%DIGITS%) [test-classes/:?]", " Suppressed: foo.TestFriendlyException: r_s", " ... suppressed 2 lines", " ... 2 more", @@ -144,7 +144,8 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(fi } private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableRenderer renderer = new ExtendedThrowableRenderer(ignoredPackageNames, maxLineCount); + final ThrowableStackTraceRenderer renderer = + new ThrowableExtendedStackTraceRenderer(ignoredPackageNames, maxLineCount); final StringBuilder rendererOutputBuilder = new StringBuilder(); renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); return rendererOutputBuilder.toString(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java similarity index 89% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java index c8b062e7e94..9bbcdbce676 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java @@ -18,19 +18,19 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.EXCEPTION; -import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.NEWLINE; -import static org.apache.logging.log4j.core.pattern.ThrowableRendererTest.assertStackTraceLineMatches; +import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.EXCEPTION; +import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.NEWLINE; +import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.assertStackTraceLineMatches; import java.util.Arrays; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -class RootThrowableRendererTest { +class ThrowableInvertedStackTraceRendererTest { static int[] maxLineCounts() { - return ThrowableRendererTest.maxLineCounts(); + return ThrowableStackTraceRendererTest.maxLineCounts(); } @ParameterizedTest @@ -56,8 +56,8 @@ void output_produced_with_maxLineCount_should_match(final int maxLineCount) { "Wrapped by: foo.TestFriendlyException: r", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.RootThrowableRendererTest.maxLineCounts(RootThrowableRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableInvertedStackTraceRendererTest.maxLineCounts(ThrowableInvertedStackTraceRendererTest.java:%DIGITS%)", " Suppressed: foo.TestFriendlyException: r_s_c", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", @@ -91,8 +91,8 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(fi " ... 4 more", "Wrapped by: foo.TestFriendlyException: r", " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.RootThrowableRendererTest.maxLineCounts(RootThrowableRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableInvertedStackTraceRendererTest.maxLineCounts(ThrowableInvertedStackTraceRendererTest.java:%DIGITS%)", " Suppressed: foo.TestFriendlyException: r_s_c", " ... suppressed 2 lines", " ... 4 more", @@ -143,8 +143,8 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(fi } private static String renderStackTrace(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableRenderer renderer = - new RootThrowableRenderer(ignoredPackageNames, maxLineCount); + final ThrowableStackTraceRenderer renderer = + new ThrowableInvertedStackTraceRenderer(ignoredPackageNames, maxLineCount); final StringBuilder rendererOutputBuilder = new StringBuilder(); renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); return rendererOutputBuilder.toString(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java similarity index 97% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java index 05478b52d71..cfb3cccad35 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java @@ -33,7 +33,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -class ThrowableRendererTest { +class ThrowableStackTraceRendererTest { static final String NEWLINE = System.lineSeparator(); @@ -68,7 +68,7 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(fi asList( "foo.TestFriendlyException: r", " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ThrowableRendererTest.(ThrowableRendererTest.java:%DIGITS%)", + " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", " Suppressed: foo.TestFriendlyException: r_s", " ... suppressed 2 lines", " ... 2 more", @@ -128,8 +128,8 @@ void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(fi } private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableRenderer renderer = - new ThrowableRenderer<>(ignoredPackageNames, maxLineCount); + final ThrowableStackTraceRenderer renderer = + new ThrowableStackTraceRenderer<>(ignoredPackageNames, maxLineCount); final StringBuilder rendererOutputBuilder = new StringBuilder(); renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); return rendererOutputBuilder.toString(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java index 0154025f8da..3b25dce8da6 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableTest.java @@ -97,14 +97,14 @@ void testConverter(String exceptionPattern, String filters, Integer depth, Strin static Stream renderers_dataSource() { return Stream.of( - Arguments.of(new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)), - Arguments.of(new RootThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE)), - Arguments.of(new ExtendedThrowableRenderer(Collections.emptyList(), Integer.MAX_VALUE))); + Arguments.of(new ThrowableStackTraceRenderer<>(Collections.emptyList(), Integer.MAX_VALUE)), + Arguments.of(new ThrowableInvertedStackTraceRenderer(Collections.emptyList(), Integer.MAX_VALUE)), + Arguments.of(new ThrowableExtendedStackTraceRenderer(Collections.emptyList(), Integer.MAX_VALUE))); } @ParameterizedTest @MethodSource("renderers_dataSource") - void testCircularSuppressedExceptions(final ThrowableRenderer renderer) { + void testCircularSuppressedExceptions(final ThrowableStackTraceRenderer renderer) { final Exception e1 = new Exception(); final Exception e2 = new Exception(); e2.addSuppressed(e1); @@ -115,7 +115,7 @@ void testCircularSuppressedExceptions(final ThrowableRenderer renderer) { @ParameterizedTest @MethodSource("renderers_dataSource") - void testCircularSuppressedNestedException(final ThrowableRenderer renderer) { + void testCircularSuppressedNestedException(final ThrowableStackTraceRenderer renderer) { final Exception e1 = new Exception(); final Exception e2 = new Exception(e1); e2.addSuppressed(e1); @@ -126,7 +126,7 @@ void testCircularSuppressedNestedException(final ThrowableRenderer renderer) @ParameterizedTest @MethodSource("renderers_dataSource") - void testCircularCauseExceptions(final ThrowableRenderer renderer) { + void testCircularCauseExceptions(final ThrowableStackTraceRenderer renderer) { final Exception e1 = new Exception(); final Exception e2 = new Exception(e1); e1.initCause(e2); @@ -139,12 +139,13 @@ void testCircularCauseExceptions(final ThrowableRenderer renderer) { @Test public void testThrowableRenderer() { final Throwable throwable = createException("r", 1, 3); - final ThrowableRenderer renderer = new ThrowableRenderer<>(Collections.emptyList(), Integer.MAX_VALUE); + final ThrowableStackTraceRenderer renderer = + new ThrowableStackTraceRenderer<>(Collections.emptyList(), Integer.MAX_VALUE); String actual = render(renderer, throwable); assertThat(actual).isEqualTo(getStandardThrowableStackTrace(throwable)); } - private static String render(final ThrowableRenderer renderer, final Throwable throwable) { + private static String render(final ThrowableStackTraceRenderer renderer, final Throwable throwable) { final StringBuilder stringBuilder = new StringBuilder(); renderer.renderThrowable(stringBuilder, throwable, System.lineSeparator()); return stringBuilder.toString(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java index 76e38aaad60..a915cdadfbc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java @@ -259,7 +259,7 @@ private StringBuilder toText(final Serializer2 serializer, final LogEvent event, */ public static PatternParser createPatternParser(final Configuration config) { if (config == null) { - return new PatternParser(config, KEY, LogEventPatternConverter.class); + return new PatternParser(null, KEY, LogEventPatternConverter.class); } PatternParser parser = config.getComponent(KEY); if (parser == null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index a859b87aee8..4b138d202ac 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -16,62 +16,37 @@ */ package org.apache.logging.log4j.core.pattern; -import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** - * Outputs the Throwable portion of the LoggingEvent as a full stack trace - * unless this converter's option is 'short', where it just outputs the first line of the trace, or if - * the number of lines to print is explicitly specified. - *

    - * The extended stack trace will also include the location of where the class was loaded from and the - * version of the jar if available. + * {@link ThrowablePatternConverter} variant where the rendered {@link StackTraceElement}s are enriched with the enclosing JAR file and its version information, if available. */ +@NullMarked @Plugin(name = "ExtendedThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"xEx", "xThrowable", "xException"}) public final class ExtendedThrowablePatternConverter extends ThrowablePatternConverter { - private ExtendedThrowableRenderer renderer; - /** - * Private constructor. - * - * @param config - * @param options options, may be null. - */ - private ExtendedThrowablePatternConverter(final Configuration config, final String[] options) { - super("ExtendedThrowable", "throwable", options, config); + private ExtendedThrowablePatternConverter(@Nullable final Configuration config, @Nullable final String[] options) { + super("ExtendedThrowable", "throwable", options, config, ExtendedThrowablePatternConverter::createRenderer); } - /** - * Gets an instance of the class. - * - * @param config The current Configuration. - * @param options pattern options, may be null. If first element is "short", - * only the first line of the throwable will be formatted. - * @return instance of class. - */ - public static ExtendedThrowablePatternConverter newInstance(final Configuration config, final String[] options) { - return new ExtendedThrowablePatternConverter(config, options); + private static ThrowableExtendedStackTraceRenderer createRenderer(final ThrowableFormatOptions options) { + return new ThrowableExtendedStackTraceRenderer(options.getIgnorePackages(), options.getLines()); } /** - * {@inheritDoc} + * Creates an instance of the class. + * + * @param config a configuration + * @param options the pattern options + * @return a new instance */ - @Override - public void format(final LogEvent event, final StringBuilder buffer) { - if (event.getThrown() != null && options.anyLines()) { - final int len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { - buffer.append(' '); - } - renderer.renderThrowable(buffer, event.getThrown(), effectiveLineSeparator(event)); - } - } - - @Override - void createRenderer(final ThrowableFormatOptions options) { - this.renderer = new ExtendedThrowableRenderer(options.getIgnorePackages(), options.getLines()); + public static ExtendedThrowablePatternConverter newInstance( + @Nullable final Configuration config, @Nullable final String[] options) { + return new ExtendedThrowablePatternConverter(config, options); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java index 9b2e54ca16d..713f79acc36 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java @@ -212,7 +212,7 @@ public List parse( list.add(new PatternFormatter(pc, field)); } if (alwaysWriteExceptions && !handlesThrowable) { - final LogEventPatternConverter pc = ExtendedThrowablePatternConverter.newInstance(config, null); + final LogEventPatternConverter pc = ExtendedThrowablePatternConverter.newInstance(config, new String[0]); list.add(new PatternFormatter(pc, FormattingInfo.getDefault())); } return list; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index 8fd62ac97cf..c273e6a82b5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -16,62 +16,37 @@ */ package org.apache.logging.log4j.core.pattern; -import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** - * Outputs the Throwable portion of the LoggingEvent as a full stack trace - * unless this converter's option is 'short', where it just outputs the first line of the trace, or if - * the number of lines to print is explicitly specified. - *

    - * The extended stack trace will also include the location of where the class was loaded from and the - * version of the jar if available. + * {@link ThrowablePatternConverter} variant where the stack trace causal chain is rendered in reverse order. */ +@NullMarked @Plugin(name = "RootThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"rEx", "rThrowable", "rException"}) public final class RootThrowablePatternConverter extends ThrowablePatternConverter { - private RootThrowableRenderer renderer; - /** - * Private constructor. - * - * @param config the Configuration or {@code null} - * @param options Options, may be null. - */ - private RootThrowablePatternConverter(final Configuration config, final String[] options) { - super("RootThrowable", "throwable", options, config); + private RootThrowablePatternConverter(@Nullable final Configuration config, @Nullable final String[] options) { + super("RootThrowable", "throwable", options, config, RootThrowablePatternConverter::createRenderer); } - /** - * Gets an instance of the class. - * - * @param config The Configuration or {@code null}. - * @param options pattern options, may be null. If first element is "short", - * only the first line of the throwable will be formatted. - * @return instance of class. - */ - public static RootThrowablePatternConverter newInstance(final Configuration config, final String[] options) { - return new RootThrowablePatternConverter(config, options); + private static ThrowableInvertedStackTraceRenderer createRenderer(final ThrowableFormatOptions options) { + return new ThrowableInvertedStackTraceRenderer(options.getIgnorePackages(), options.getLines()); } /** - * {@inheritDoc} + * Creates an instance of the class. + * + * @param config a configuration + * @param options the pattern options + * @return a new instance */ - @Override - public void format(final LogEvent event, final StringBuilder buffer) { - if (event.getThrown() != null && options.anyLines()) { - final int len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { - buffer.append(' '); - } - renderer.renderThrowable(buffer, event.getThrown(), effectiveLineSeparator(event)); - } - } - - @Override - void createRenderer(final ThrowableFormatOptions options) { - this.renderer = new RootThrowableRenderer(options.getIgnorePackages(), options.getLines()); + public static RootThrowablePatternConverter newInstance( + @Nullable final Configuration config, @Nullable final String[] options) { + return new RootThrowablePatternConverter(config, options); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java similarity index 93% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java index cfbae3d70f2..aa354a4f4f1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java @@ -29,9 +29,13 @@ import org.apache.logging.log4j.util.LoaderUtil; import org.apache.logging.log4j.util.StackLocatorUtil; -final class ExtendedThrowableRenderer extends ThrowableRenderer { +/** + * {@link ThrowableStackTraceRenderer} variant where the rendered {@link StackTraceElement}s are enriched with the enclosing JAR file and its version information, if available. + */ +final class ThrowableExtendedStackTraceRenderer + extends ThrowableStackTraceRenderer { - ExtendedThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { + ThrowableExtendedStackTraceRenderer(final List ignoredPackageNames, final int maxLineCount) { super(ignoredPackageNames, maxLineCount); } @@ -72,7 +76,7 @@ void renderStackTraceElement( buffer.append(lineSeparator); } - static final class ExtendedContext extends ThrowableRenderer.Context { + static final class ExtendedContext extends ThrowableStackTraceRenderer.Context { private final Map classResourceInfoByName; @@ -164,7 +168,7 @@ private static Class loadClass(final ClassLoader loader, final String classNa // 2. Try the `LoaderUtil` magic () -> LoaderUtil.loadClass(className), // 3. Try the current class loader - () -> ExtendedThrowableRenderer.class + () -> ThrowableExtendedStackTraceRenderer.class .getClassLoader() .loadClass(className)) .map(provider -> { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java similarity index 90% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java index 17e36738f3b..f141de74f19 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java @@ -19,11 +19,15 @@ import java.util.List; import java.util.Set; -final class RootThrowableRenderer extends ThrowableRenderer { +/** + * {@link ThrowableStackTraceRenderer} variant where the stack trace causal chain is rendered in reverse order. + */ +final class ThrowableInvertedStackTraceRenderer + extends ThrowableStackTraceRenderer { private static final String WRAPPED_BY_CAPTION = "Wrapped by: "; - RootThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { + ThrowableInvertedStackTraceRenderer(final List ignoredPackageNames, final int maxLineCount) { super(ignoredPackageNames, maxLineCount); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java index 17782e8b652..d7c2060fb7b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java @@ -16,8 +16,8 @@ */ package org.apache.logging.log4j.core.pattern; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.PrintWriter; +import static java.util.Objects.requireNonNull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,14 +27,13 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.util.StringBuilderWriter; -import org.apache.logging.log4j.util.Strings; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** - * Outputs the Throwable portion of the LoggingEvent as a full stack trace - * unless this converter's option is 'short', where it just outputs the first line of the trace, or if - * the number of lines to print is explicitly specified. + * Outputs certain information extracted from the {@link Throwable} associated with a {@link LogEvent}. */ +@NullMarked @Plugin(name = "ThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({"ex", "throwable", "exception"}) public class ThrowablePatternConverter extends LogEventPatternConverter { @@ -49,63 +48,81 @@ public class ThrowablePatternConverter extends LogEventPatternConverter { private final Function effectiveLineSeparatorProvider; - private String rawOption; - - private final boolean subShortOption; + protected final ThrowableFormatOptions options; - private ThrowableRenderer renderer; + private final ThrowableRenderer renderer; - protected final ThrowableFormatOptions options; + /** + * @deprecated Use {@link #ThrowablePatternConverter(String, String, String[], Configuration, Function)} instead. + */ + @Deprecated + protected ThrowablePatternConverter(final String name, final String style, @Nullable final String[] options) { + this(name, style, options, null, null); + } /** - * Constructor. - * @param name Name of converter. - * @param style CSS style for output. - * @param options options, may be null. - * @deprecated Use ThrowablePatternConverter(String name, String stule, String[] options, Configuration config) + * @deprecated Use {@link #ThrowablePatternConverter(String, String, String[], Configuration, Function)} instead. */ @Deprecated - protected ThrowablePatternConverter(final String name, final String style, final String[] options) { - this(name, style, options, null); + protected ThrowablePatternConverter( + final String name, + final String style, + @Nullable final String[] options, + @Nullable final Configuration config) { + this(name, style, options, config, null); } /** - * Constructor. - * @param name name of converter + * The canonical constructor. + * + * @param name name of the converter * @param style CSS style for output - * @param options options, may be null. - * @param config the Configuration or {@code null} + * @param options array of options + * @param config a configuration + * @param stackTraceRendererFactory a renderer factory + * @since 2.25.0 */ - protected ThrowablePatternConverter( - final String name, final String style, final String[] options, final Configuration config) { + ThrowablePatternConverter( + final String name, + final String style, + @Nullable final String[] options, + @Nullable final Configuration config, + @Nullable + final Function> stackTraceRendererFactory) { + + // Process `name`, `style`, and `options` super(name, style); this.options = ThrowableFormatOptions.newInstance(options); - if (options != null && options.length > 0) { - rawOption = options[0]; - } + + // Determine the effective line separator final List suffixFormatters = new ArrayList<>(); this.effectiveLineSeparatorProvider = createEffectiveLineSeparator( this.options.getSeparator(), this.options.getSuffix(), config, suffixFormatters); this.formatters = Collections.unmodifiableList(suffixFormatters); - subShortOption = ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption) - || ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption) - || ThrowableFormatOptions.FILE_NAME.equalsIgnoreCase(rawOption) - || ThrowableFormatOptions.LINE_NUMBER.equalsIgnoreCase(rawOption) - || ThrowableFormatOptions.METHOD_NAME.equalsIgnoreCase(rawOption) - || ThrowableFormatOptions.CLASS_NAME.equalsIgnoreCase(rawOption); - createRenderer(this.options); + + // Create the effective renderer + final ThrowablePropertyRenderer propertyRenderer = ThrowablePropertyRenderer.fromOptions(options); + if (propertyRenderer != null) { + this.renderer = propertyRenderer; + } else { + final Function> effectiveRendererFactory = + stackTraceRendererFactory != null + ? stackTraceRendererFactory + : ThrowablePatternConverter::createRenderer; + this.renderer = effectiveRendererFactory.apply(this.options); + } } /** - * Gets an instance of the class. + * Creates an instance of the class. * - * @param config The Configuration or {@code null}. - * @param options pattern options, may be null. If first element is "short", - * only the first line of the throwable will be formatted. - * @return instance of class. + * @param config a configuration + * @param options the pattern options + * @return a new instance */ - public static ThrowablePatternConverter newInstance(final Configuration config, final String[] options) { - return new ThrowablePatternConverter("Throwable", "throwable", options, config); + public static ThrowablePatternConverter newInstance( + @Nullable final Configuration config, @Nullable final String[] options) { + return new ThrowablePatternConverter("Throwable", "throwable", options, config, null); } /** @@ -113,75 +130,27 @@ public static ThrowablePatternConverter newInstance(final Configuration config, */ @Override public void format(final LogEvent event, final StringBuilder buffer) { + requireNonNull(event, "event"); + requireNonNull(buffer, "buffer"); final Throwable throwable = event.getThrown(); - final String effectiveLineSeparator = effectiveLineSeparator(event); - if (subShortOption) { - formatSubShortOption(throwable, effectiveLineSeparator, buffer); - } else if (throwable != null && options.anyLines()) { - formatOption(throwable, effectiveLineSeparator, buffer); - } - } - - private void formatSubShortOption(final Throwable t, final String lineSeparator, final StringBuilder buffer) { - StackTraceElement[] trace; - StackTraceElement throwingMethod = null; - int len; - - if (t != null) { - trace = t.getStackTrace(); - if (trace != null && trace.length > 0) { - throwingMethod = trace[0]; - } - } - - if (t != null && throwingMethod != null) { - String toAppend = Strings.EMPTY; - - if (ThrowableFormatOptions.CLASS_NAME.equalsIgnoreCase(rawOption)) { - toAppend = throwingMethod.getClassName(); - } else if (ThrowableFormatOptions.METHOD_NAME.equalsIgnoreCase(rawOption)) { - toAppend = throwingMethod.getMethodName(); - } else if (ThrowableFormatOptions.LINE_NUMBER.equalsIgnoreCase(rawOption)) { - toAppend = String.valueOf(throwingMethod.getLineNumber()); - } else if (ThrowableFormatOptions.MESSAGE.equalsIgnoreCase(rawOption)) { - toAppend = t.getMessage(); - } else if (ThrowableFormatOptions.LOCALIZED_MESSAGE.equalsIgnoreCase(rawOption)) { - toAppend = t.getLocalizedMessage(); - } else if (ThrowableFormatOptions.FILE_NAME.equalsIgnoreCase(rawOption)) { - toAppend = throwingMethod.getFileName(); - } - - len = buffer.length(); - if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) { - buffer.append(' '); - } - buffer.append(toAppend); - - buffer.append(lineSeparator); + if (throwable != null) { + final String lineSeparator = effectiveLineSeparatorProvider.apply(event); + ensureWhitespaceSuffix(buffer); + renderer.renderThrowable(buffer, throwable, lineSeparator); } } - @SuppressFBWarnings( - value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", - justification = "Formatting a throwable is the main purpose of this class.") - private void formatOption( - final Throwable throwable, final String effectiveLineSeparator, final StringBuilder buffer) { + private static void ensureWhitespaceSuffix(final StringBuilder buffer) { final int bufferLength = buffer.length(); if (bufferLength > 0 && !Character.isWhitespace(buffer.charAt(bufferLength - 1))) { buffer.append(' '); } - final boolean customRenderingRequired = isCustomRenderingRequired(effectiveLineSeparator); - if (customRenderingRequired) { - renderer.renderThrowable(buffer, throwable, effectiveLineSeparator); - } else { - throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer))); - } } /** - * This converter obviously handles throwables. + * Indicates this converter handles {@link Throwable}s. * - * @return true. + * @return {@code true} */ @Override public boolean handlesThrowable() { @@ -192,10 +161,6 @@ public ThrowableFormatOptions getOptions() { return options; } - private boolean isCustomRenderingRequired(final String effectiveLineSeparator) { - return !options.allLines() || !System.lineSeparator().equals(effectiveLineSeparator) || options.hasPackages(); - } - /** * Creates a lambda that returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator}. *

    @@ -223,14 +188,16 @@ private boolean isCustomRenderingRequired(final String effectiveLineSeparator) { * @param separator the user-provided {@code separator} option * @param suffix the user-provided {@code suffix} option containing a Pattern Layout conversion pattern * @param config the configuration to create the Pattern Layout conversion pattern parser - * @param suffixFormatters the list of pattern formatters to format the suffix + * @param suffixFormatters the list of pattern formatters employed to format the suffix * @return a lambda that returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator} */ private static Function createEffectiveLineSeparator( final String separator, - final String suffix, - final Configuration config, + @Nullable final String suffix, + @Nullable final Configuration config, final List suffixFormatters) { + requireNonNull(separator, "separator"); + requireNonNull(suffixFormatters, "suffixFormatters"); if (suffix != null) { // Suffix is allowed to be a Pattern Layout conversion pattern, hence we need to parse it @@ -265,19 +232,8 @@ private static Function createEffectiveLineSeparator( } } - void createRenderer(final ThrowableFormatOptions options) { - this.renderer = new ThrowableRenderer<>(options.getIgnorePackages(), options.getLines()); - } - - /** - * Returns the effective line separator by concatenating the formatted {@code suffix} with the {@code separator}. - * - * @param logEvent the log event to use while formatting the suffix pattern - * @return the concatenation of the formatted {@code suffix} with the {@code separator} - * @see #createEffectiveLineSeparator(String, String, Configuration, List) - */ - String effectiveLineSeparator(final LogEvent logEvent) { - return effectiveLineSeparatorProvider.apply(logEvent); + private static ThrowableStackTraceRenderer createRenderer(final ThrowableFormatOptions options) { + return new ThrowableStackTraceRenderer<>(options.getIgnorePackages(), options.getLines()); } /** @@ -285,11 +241,12 @@ String effectiveLineSeparator(final LogEvent logEvent) { * * @param logEvent the log event to use while formatting the suffix pattern * @return the formatted suffix - * @deprecated Use {@link #effectiveLineSeparator(LogEvent)} instead + * @deprecated Planned to be removed without a replacement */ @Deprecated protected String getSuffix(final LogEvent logEvent) { - final String effectiveLineSeparator = effectiveLineSeparator(logEvent); + requireNonNull(logEvent, "logEvent"); + final String effectiveLineSeparator = effectiveLineSeparatorProvider.apply(logEvent); if (options.getSeparator().equals(effectiveLineSeparator)) { return ""; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePropertyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePropertyRenderer.java new file mode 100644 index 00000000000..62fce22e67b --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePropertyRenderer.java @@ -0,0 +1,98 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +enum ThrowablePropertyRenderer implements ThrowableRenderer { + MESSAGE(ThrowableFormatOptions.MESSAGE, (buffer, throwable, lineSeparator) -> { + final String message = throwable.getMessage(); + buffer.append(message); + buffer.append(lineSeparator); + }), + LOCALIZED_MESSAGE(ThrowableFormatOptions.LOCALIZED_MESSAGE, (buffer, throwable, lineSeparator) -> { + final String localizedMessage = throwable.getLocalizedMessage(); + buffer.append(localizedMessage); + buffer.append(lineSeparator); + }), + CLASS_NAME(ThrowableFormatOptions.CLASS_NAME, ((buffer, throwable, lineSeparator) -> { + @Nullable final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + if (stackTraceElements != null && stackTraceElements.length > 0) { + final StackTraceElement throwingMethod = stackTraceElements[0]; + final String className = throwingMethod.getClassName(); + buffer.append(className); + buffer.append(lineSeparator); + } + })), + METHOD_NAME(ThrowableFormatOptions.METHOD_NAME, ((buffer, throwable, lineSeparator) -> { + @Nullable final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + if (stackTraceElements != null && stackTraceElements.length > 0) { + final StackTraceElement throwingMethod = stackTraceElements[0]; + final String methodName = throwingMethod.getMethodName(); + buffer.append(methodName); + buffer.append(lineSeparator); + } + })), + LINE_NUMBER(ThrowableFormatOptions.LINE_NUMBER, ((buffer, throwable, lineSeparator) -> { + @Nullable final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + if (stackTraceElements != null && stackTraceElements.length > 0) { + final StackTraceElement throwingMethod = stackTraceElements[0]; + final int lineNumber = throwingMethod.getLineNumber(); + buffer.append(lineNumber); + buffer.append(lineSeparator); + } + })), + FILE_NAME(ThrowableFormatOptions.FILE_NAME, ((buffer, throwable, lineSeparator) -> { + @Nullable final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + if (stackTraceElements != null && stackTraceElements.length > 0) { + final StackTraceElement throwingMethod = stackTraceElements[0]; + final String fileName = throwingMethod.getFileName(); + buffer.append(fileName); + buffer.append(lineSeparator); + } + })); + + private final String name; + + private final ThrowableRenderer delegate; + + ThrowablePropertyRenderer(final String name, final ThrowableRenderer delegate) { + this.name = name; + this.delegate = delegate; + } + + @Override + public void renderThrowable(final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { + delegate.renderThrowable(buffer, throwable, lineSeparator); + } + + @Nullable + static ThrowablePropertyRenderer fromOptions(@Nullable final String[] options) { + if (options != null && options.length > 0) { + final String name = options[0]; + for (final ThrowablePropertyRenderer renderer : values()) { + if (renderer.name.equalsIgnoreCase(name)) { + return renderer; + } + } + } + return null; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java index 7920b830773..0d65d8a4359 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableRenderer.java @@ -16,275 +16,10 @@ */ package org.apache.logging.log4j.core.pattern; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.logging.log4j.core.util.internal.StringBuilders; - -class ThrowableRenderer { - - private static final String CAUSED_BY_CAPTION = "Caused by: "; - - static final String SUPPRESSED_CAPTION = "Suppressed: "; - - final List ignoredPackageNames; - - final int maxLineCount; - - ThrowableRenderer(final List ignoredPackageNames, final int maxLineCount) { - this.ignoredPackageNames = ignoredPackageNames; - this.maxLineCount = maxLineCount; - } - - final void renderThrowable(final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { - C context = createContext(throwable); - renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); - StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); - } - - @SuppressWarnings("unchecked") - C createContext(final Throwable throwable) { - final Map metadataByThrowable = Context.Metadata.ofThrowable(throwable); - return (C) new Context(0, metadataByThrowable); - } - - void renderThrowable( - final StringBuilder buffer, - final Throwable throwable, - final C context, - final Set visitedThrowables, - final String lineSeparator) { - renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator, ""); - } - - private void renderThrowable( - final StringBuilder buffer, - final Throwable throwable, - final C context, - final Set visitedThrowables, - final String prefix, - final String lineSeparator, - final String caption) { - if (visitedThrowables.contains(throwable)) { - return; - } - visitedThrowables.add(throwable); - buffer.append(prefix); - buffer.append(caption); - renderThrowableMessage(buffer, throwable); - buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); - renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); - } - - void renderSuppressed( - final StringBuilder buffer, - final Throwable[] suppressedThrowables, - final C context, - final Set visitedThrowables, - final String prefix, - final String lineSeparator) { - for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable( - buffer, suppressedThrowable, context, visitedThrowables, prefix, lineSeparator, SUPPRESSED_CAPTION); - } - } - - void renderCause( - final StringBuilder buffer, - final Throwable cause, - final C context, - final Set visitedThrowables, - final String prefix, - final String lineSeparator) { - if (cause != null) { - renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator, CAUSED_BY_CAPTION); - } - } - - static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { - final String message = throwable.getMessage(); - buffer.append(throwable.getClass().getName()); - if (message != null) { - buffer.append(": "); - buffer.append(message); - } - } - - final void renderStackTraceElements( - final StringBuilder buffer, - final Throwable throwable, - final C context, - final String prefix, - final String lineSeparator) { - context.ignoredStackTraceElementCount = 0; - final Context.Metadata metadata = context.metadataByThrowable.get(throwable); - final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); - for (int i = 0; i < metadata.stackLength; i++) { - renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, lineSeparator); - } - if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); - } - if (metadata.commonElementCount != 0) { - buffer.append(prefix); - buffer.append("\t... "); - buffer.append(metadata.commonElementCount); - buffer.append(" more"); - buffer.append(lineSeparator); - } - } - - void renderStackTraceElement( - final StringBuilder buffer, - final StackTraceElement stackTraceElement, - final C context, - final String prefix, - final String lineSeparator) { - - // Short-circuit on ignored stack trace elements - final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); - if (stackTraceElementIgnored) { - context.ignoredStackTraceElementCount += 1; - return; - } - - // Render the stack trace element - if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); - context.ignoredStackTraceElementCount = 0; - } - buffer.append(prefix); - buffer.append("\tat "); - buffer.append(stackTraceElement.toString()); - buffer.append(lineSeparator); - } - - static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { - if (ignorePackages != null) { - final String className = element.getClassName(); - for (final String ignoredPackage : ignorePackages) { - if (className.startsWith(ignoredPackage)) { - return true; - } - } - } - return false; - } - - static void renderSuppressedCount( - final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { - buffer.append(prefix); - if (count == 1) { - buffer.append("\t... "); - } else { - buffer.append("\t... suppressed "); - buffer.append(count); - buffer.append(" lines"); - } - buffer.append(lineSeparator); - } - - static class Context { - - /** - * Number of stack trace elements ignored. - *

    - * This value will be reset per {@link Throwable} in the causal chain. - *

    - */ - int ignoredStackTraceElementCount; - - /** - * {@link Metadata} per {@link Throwable} in the causal chain - */ - final Map metadataByThrowable; - - /** - * The canonical constructor. - */ - Context(final int ignoredStackTraceElementCount, final Map metadataByThrowable) { - this.ignoredStackTraceElementCount = ignoredStackTraceElementCount; - this.metadataByThrowable = metadataByThrowable; - } - - /** - * Invariants associated with a {@link Throwable} - */ - static final class Metadata { - - /** - * Number of stack trace elements shared with the parent {@link Throwable}'s stack - */ - final int commonElementCount; - - /** - * Number of stack trace elements exclusive to this {@link Throwable}, i.e., not in common with the parent {@link Throwable}'s stack - */ - final int stackLength; - - private Metadata(final int commonElementCount, final int stackLength) { - this.commonElementCount = commonElementCount; - this.stackLength = stackLength; - } - - static Map ofThrowable(final Throwable throwable) { - final Map metadataByThrowable = new HashMap<>(); - populateMetadata(metadataByThrowable, new HashSet<>(), null, throwable); - return metadataByThrowable; - } - - private static void populateMetadata( - final Map metadataByThrowable, - final Set visitedThrowables, - final Throwable parentThrowable, - final Throwable throwable) { - - // Populate metadata of the current throwable - final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); - final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); - metadataByThrowable.put(throwable, metadata); - - // Populate metadata of suppressed exceptions - for (final Throwable suppressed : throwable.getSuppressed()) { - if (!visitedThrowables.contains(suppressed)) { - visitedThrowables.add(suppressed); - populateMetadata(metadataByThrowable, visitedThrowables, throwable, suppressed); - } - } - - // Populate metadata of the causal chain - final Throwable cause = throwable.getCause(); - if (cause != null && !visitedThrowables.contains(cause)) { - visitedThrowables.add(cause); - populateMetadata(metadataByThrowable, visitedThrowables, throwable, cause); - } - } +/** + * Contract for rendering {@link Throwable}s in {@link ThrowablePatternConverter} et al. + */ +interface ThrowableRenderer { - private static Metadata populateMetadata( - final StackTraceElement[] parentTrace, final StackTraceElement[] currentTrace) { - int commonElementCount; - int stackLength; - if (parentTrace != null) { - int parentIndex = parentTrace.length - 1; - int currentIndex = currentTrace.length - 1; - while (parentIndex >= 0 - && currentIndex >= 0 - && parentTrace[parentIndex].equals(currentTrace[currentIndex])) { - --parentIndex; - --currentIndex; - } - commonElementCount = currentTrace.length - 1 - currentIndex; - stackLength = currentIndex + 1; - } else { - commonElementCount = 0; - stackLength = currentTrace.length; - } - return new Metadata(commonElementCount, stackLength); - } - } - } + void renderThrowable(final StringBuilder buffer, final Throwable throwable, final String lineSeparator); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java new file mode 100644 index 00000000000..bf9840a11d6 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java @@ -0,0 +1,297 @@ +/* + * 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.apache.logging.log4j.core.pattern; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.logging.log4j.core.util.internal.StringBuilders; + +/** + * {@link ThrowableRenderer} implementation for rendering stack traces. + * + * @param the context type + */ +class ThrowableStackTraceRenderer implements ThrowableRenderer { + + private static final String CAUSED_BY_CAPTION = "Caused by: "; + + static final String SUPPRESSED_CAPTION = "Suppressed: "; + + final List ignoredPackageNames; + + final int maxLineCount; + + ThrowableStackTraceRenderer(final List ignoredPackageNames, final int maxLineCount) { + this.ignoredPackageNames = ignoredPackageNames; + this.maxLineCount = maxLineCount; + } + + @Override + public final void renderThrowable( + final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { + C context = createContext(throwable); + renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); + StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); + } + + @SuppressWarnings("unchecked") + C createContext(final Throwable throwable) { + final Map metadataByThrowable = Context.Metadata.ofThrowable(throwable); + return (C) new Context(0, metadataByThrowable); + } + + void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final Set visitedThrowables, + final String lineSeparator) { + renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator, ""); + } + + private void renderThrowable( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final Set visitedThrowables, + final String prefix, + final String lineSeparator, + final String caption) { + if (visitedThrowables.contains(throwable)) { + return; + } + visitedThrowables.add(throwable); + buffer.append(prefix); + buffer.append(caption); + renderThrowableMessage(buffer, throwable); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); + renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); + } + + void renderSuppressed( + final StringBuilder buffer, + final Throwable[] suppressedThrowables, + final C context, + final Set visitedThrowables, + final String prefix, + final String lineSeparator) { + for (final Throwable suppressedThrowable : suppressedThrowables) { + renderThrowable( + buffer, suppressedThrowable, context, visitedThrowables, prefix, lineSeparator, SUPPRESSED_CAPTION); + } + } + + void renderCause( + final StringBuilder buffer, + final Throwable cause, + final C context, + final Set visitedThrowables, + final String prefix, + final String lineSeparator) { + if (cause != null) { + renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator, CAUSED_BY_CAPTION); + } + } + + static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { + final String message = throwable.getMessage(); + buffer.append(throwable.getClass().getName()); + if (message != null) { + buffer.append(": "); + buffer.append(message); + } + } + + final void renderStackTraceElements( + final StringBuilder buffer, + final Throwable throwable, + final C context, + final String prefix, + final String lineSeparator) { + context.ignoredStackTraceElementCount = 0; + final Context.Metadata metadata = context.metadataByThrowable.get(throwable); + final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + for (int i = 0; i < metadata.stackLength; i++) { + renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, lineSeparator); + } + if (context.ignoredStackTraceElementCount > 0) { + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + } + if (metadata.commonElementCount != 0) { + buffer.append(prefix); + buffer.append("\t... "); + buffer.append(metadata.commonElementCount); + buffer.append(" more"); + buffer.append(lineSeparator); + } + } + + void renderStackTraceElement( + final StringBuilder buffer, + final StackTraceElement stackTraceElement, + final C context, + final String prefix, + final String lineSeparator) { + + // Short-circuit on ignored stack trace elements + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + if (stackTraceElementIgnored) { + context.ignoredStackTraceElementCount += 1; + return; + } + + // Render the stack trace element + if (context.ignoredStackTraceElementCount > 0) { + renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + context.ignoredStackTraceElementCount = 0; + } + buffer.append(prefix); + buffer.append("\tat "); + buffer.append(stackTraceElement.toString()); + buffer.append(lineSeparator); + } + + static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { + if (ignorePackages != null) { + final String className = element.getClassName(); + for (final String ignoredPackage : ignorePackages) { + if (className.startsWith(ignoredPackage)) { + return true; + } + } + } + return false; + } + + static void renderSuppressedCount( + final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { + buffer.append(prefix); + if (count == 1) { + buffer.append("\t... "); + } else { + buffer.append("\t... suppressed "); + buffer.append(count); + buffer.append(" lines"); + } + buffer.append(lineSeparator); + } + + static class Context { + + /** + * Number of stack trace elements ignored. + *

    + * This value will be reset per {@link Throwable} in the causal chain. + *

    + */ + int ignoredStackTraceElementCount; + + /** + * {@link Metadata} per {@link Throwable} in the causal chain + */ + final Map metadataByThrowable; + + /** + * The canonical constructor. + */ + Context(final int ignoredStackTraceElementCount, final Map metadataByThrowable) { + this.ignoredStackTraceElementCount = ignoredStackTraceElementCount; + this.metadataByThrowable = metadataByThrowable; + } + + /** + * Invariants associated with a {@link Throwable} + */ + static final class Metadata { + + /** + * Number of stack trace elements shared with the parent {@link Throwable}'s stack + */ + final int commonElementCount; + + /** + * Number of stack trace elements exclusive to this {@link Throwable}, i.e., not in common with the parent {@link Throwable}'s stack + */ + final int stackLength; + + private Metadata(final int commonElementCount, final int stackLength) { + this.commonElementCount = commonElementCount; + this.stackLength = stackLength; + } + + static Map ofThrowable(final Throwable throwable) { + final Map metadataByThrowable = new HashMap<>(); + populateMetadata(metadataByThrowable, new HashSet<>(), null, throwable); + return metadataByThrowable; + } + + private static void populateMetadata( + final Map metadataByThrowable, + final Set visitedThrowables, + final Throwable parentThrowable, + final Throwable throwable) { + + // Populate metadata of the current throwable + final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); + final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); + metadataByThrowable.put(throwable, metadata); + + // Populate metadata of suppressed exceptions + for (final Throwable suppressed : throwable.getSuppressed()) { + if (!visitedThrowables.contains(suppressed)) { + visitedThrowables.add(suppressed); + populateMetadata(metadataByThrowable, visitedThrowables, throwable, suppressed); + } + } + + // Populate metadata of the causal chain + final Throwable cause = throwable.getCause(); + if (cause != null && !visitedThrowables.contains(cause)) { + visitedThrowables.add(cause); + populateMetadata(metadataByThrowable, visitedThrowables, throwable, cause); + } + } + + private static Metadata populateMetadata( + final StackTraceElement[] parentTrace, final StackTraceElement[] currentTrace) { + int commonElementCount; + int stackLength; + if (parentTrace != null) { + int parentIndex = parentTrace.length - 1; + int currentIndex = currentTrace.length - 1; + while (parentIndex >= 0 + && currentIndex >= 0 + && parentTrace[parentIndex].equals(currentTrace[currentIndex])) { + --parentIndex; + --currentIndex; + } + commonElementCount = currentTrace.length - 1 - currentIndex; + stackLength = currentIndex + 1; + } else { + commonElementCount = 0; + stackLength = currentTrace.length; + } + return new Metadata(commonElementCount, stackLength); + } + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java index 5818a773fe9..5c047848b57 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/package-info.java @@ -18,7 +18,7 @@ * Provides classes implementing format specifiers in conversion patterns. */ @Export -@Version("2.24.0") +@Version("2.25.0") package org.apache.logging.log4j.core.pattern; import org.osgi.annotation.bundle.Export; From f3b13af8a7c8924d8adf11ff470f23561787ad93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 26 Sep 2024 12:02:46 +0200 Subject: [PATCH 61/72] Revamp tests --- .../test/java/foo/TestFriendlyException.java | 6 + ...ExtendedThrowablePatternConverterTest.java | 283 +++++---- .../RootThrowablePatternConverterTest.java | 257 ++++---- ...rowableExtendedStackTraceRendererTest.java | 153 ----- ...rowableInvertedStackTraceRendererTest.java | 152 ----- .../ThrowablePatternConverterTest.java | 574 +++++++++++------- .../ThrowableStackTraceRendererTest.java | 186 ------ .../util/internal/StringBuildersTest.java | 103 ---- .../core/impl/ThrowableFormatOptions.java | 6 +- .../ThrowableExtendedStackTraceRenderer.java | 9 +- .../ThrowableInvertedStackTraceRenderer.java | 48 +- .../pattern/ThrowableStackTraceRenderer.java | 77 ++- .../core/util/internal/StringBuilders.java | 61 -- 13 files changed, 751 insertions(+), 1164 deletions(-) delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java delete mode 100644 log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java diff --git a/log4j-core-test/src/test/java/foo/TestFriendlyException.java b/log4j-core-test/src/test/java/foo/TestFriendlyException.java index 2799ca1ced8..f807896d078 100644 --- a/log4j-core-test/src/test/java/foo/TestFriendlyException.java +++ b/log4j-core-test/src/test/java/foo/TestFriendlyException.java @@ -23,6 +23,7 @@ /** * A testing friendly exception featuring *
      + *
    • Distinct localized message
    • *
    • Non-Log4j package origin1
    • *
    • Sufficient causal chain depth
    • *
    • Decorated with suppressed exceptions
    • @@ -79,4 +80,9 @@ private void removeExcludedStackTraceElements() { .toArray(StackTraceElement[]::new); setStackTrace(newStackTrace); } + + @Override + public String getLocalizedMessage() { + return getMessage() + " [localized]"; + } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java index af38e52e16a..2d0a3ba26f3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java @@ -16,162 +16,153 @@ */ package org.apache.logging.log4j.core.pattern; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static java.util.Arrays.asList; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.List; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.util.Strings; -import org.junit.jupiter.api.Test; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractPropertyTest; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractStackTraceTest; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.DepthTestCase; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -public class ExtendedThrowablePatternConverterTest { +/** + * {@link ExtendedThrowablePatternConverter} tests. + */ +class ExtendedThrowablePatternConverterTest { - @Test - public void testSuffixFromNormalPattern() { - final String suffix = "suffix(%mdc{key})"; - ThreadContext.put("key", "test suffix "); - final String[] options = {suffix}; - final ExtendedThrowablePatternConverter converter = - ExtendedThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains("test suffix"), "No suffix"); - } + @Nested + class PropertyTest extends AbstractPropertyTest { - @Test - public void testSuffix() { - final String suffix = "suffix(test suffix)"; - final String[] options = {suffix}; - final ExtendedThrowablePatternConverter converter = - ExtendedThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains("test suffix"), "No suffix"); + PropertyTest() { + super("%xEx"); + } } - @Test - public void testSuffixWillIgnoreThrowablePattern() { - final String suffix = "suffix(%xEx{suffix(inner suffix)})"; - final String[] options = {suffix}; - final ExtendedThrowablePatternConverter converter = - ExtendedThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertFalse(result.contains("inner suffix"), "Has unexpected suffix"); - } + private static final List EXPECTED_FULL_STACK_TRACE_LINES = asList( + "foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.(TestFriendlyException.java:0) ~[test-classes/:?]", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0) [test-classes/:?]", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more"); - @Test - public void testDeserializedLogEventWithThrowableProxyButNoThrowable() { - final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, null); - final Throwable originalThrowable = new Exception("something bad happened"); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("")) // - .setThrown(originalThrowable) // - .setTimeMillis(0) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains(originalThrowable.getMessage()), result); - assertTrue(result.contains(originalThrowable.getStackTrace()[0].getMethodName()), result); - } + @Nested + class StackTraceTest extends AbstractStackTraceTest { - @Test - public void testFiltering() { - final String packages = "filters(org.junit, org.apache.maven, sun.reflect, java.lang.reflect)"; - final String[] options = {packages}; - final ExtendedThrowablePatternConverter converter = - ExtendedThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains(" suppressed "), "No suppressed lines"); - } + StackTraceTest() { + super("%xEx"); + } - @Test - public void testFull() { - final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, null); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final StringWriter sw = new StringWriter(); - final PrintWriter pw = new PrintWriter(sw); - parent.printStackTrace(pw); - String result = sb.toString(); - result = result.replaceAll(" ~?\\[.*\\]", Strings.EMPTY); - final String expected = sw.toString(); // .replaceAll("\r", Strings.EMPTY); - assertEquals(expected, result); - } + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#fullStackTracePatterns") + void full_output_should_match(final String pattern) { + final String effectivePattern = patternPrefix + pattern; + assertStackTraceLines(null, effectivePattern, EXPECTED_FULL_STACK_TRACE_LINES); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_limited_output_should_match(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines(depthTestCase, pattern, EXPECTED_FULL_STACK_TRACE_LINES); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(foo)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r [localized]", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0) [test-classes/:?]", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " ... suppressed 2 lines", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " ... suppressed 2 lines", + " ... 3 more")); + } - @Test - public void testFiltersAndSeparator() { - final ExtendedThrowablePatternConverter exConverter = ExtendedThrowablePatternConverter.newInstance( - null, new String[] {"full", "filters(org.junit,org.eclipse)", "separator(|)"}); - final ThrowableFormatOptions options = exConverter.getOptions(); - final List ignorePackages = options.getIgnorePackages(); - assertNotNull(ignorePackages); - final String ignorePackagesString = ignorePackages.toString(); - assertTrue(ignorePackages.contains("org.junit"), ignorePackagesString); - assertTrue(ignorePackages.contains("org.eclipse"), ignorePackagesString); - assertEquals("|", options.getSeparator()); + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(org.apache)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.(TestFriendlyException.java:0) ~[test-classes/:?]", + " ...", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", + " ... 3 more")); + } } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java index e069da72a01..7f656c8d497 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java @@ -16,132 +16,153 @@ */ package org.apache.logging.log4j.core.pattern; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static java.util.Arrays.asList; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.message.SimpleMessage; -import org.junit.jupiter.api.Test; +import java.util.List; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractPropertyTest; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractStackTraceTest; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.DepthTestCase; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -public class RootThrowablePatternConverterTest { +/** + * {@link RootThrowablePatternConverter} tests. + */ +class RootThrowablePatternConverterTest { - @Test - public void testSuffix() { - final String suffix = "suffix(test suffix)"; - final String[] options = {suffix}; - final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains("test suffix"), "No suffix"); - } + @Nested + class PropertyTest extends AbstractPropertyTest { - @Test - public void testSuffixFromNormalPattern() { - final String suffix = "suffix(%mdc{key})"; - ThreadContext.put("key", "test suffix "); - final String[] options = {suffix}; - final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains("test suffix"), "No suffix"); + PropertyTest() { + super("%rEx"); + } } - @Test - public void testSuffixWillIgnoreThrowablePattern() { - final String suffix = "suffix(%xEx{suffix(inner suffix)})"; - final String[] options = {suffix}; - final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertFalse(result.contains("inner suffix"), "Has unexpected suffix"); - } + private static final List EXPECTED_FULL_STACK_TRACE_LINES = asList( + "foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.(TestFriendlyException.java:0)", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", + " Suppressed: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + " Wrapped by: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more"); - @Test - public void testFull1() { - final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, null); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - // System.out.print(result); - assertTrue( - result.contains("Wrapped by: java.lang.IllegalArgumentException: IllegalArgument"), - "Missing Exception"); - assertTrue(result.startsWith("java.lang.NullPointerException: null pointer"), "Incorrect start of msg"); - } + @Nested + class StackTraceTest extends AbstractStackTraceTest { + + StackTraceTest() { + super("%rEx"); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#fullStackTracePatterns") + void full_output_should_match(final String pattern) { + final String effectivePattern = patternPrefix + pattern; + assertStackTraceLines(null, effectivePattern, EXPECTED_FULL_STACK_TRACE_LINES); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_limited_output_should_match(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines(depthTestCase, pattern, EXPECTED_FULL_STACK_TRACE_LINES); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(foo)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r_c_c [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r_c [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r [localized]", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", + " Suppressed: foo.TestFriendlyException: r_s_c [localized]", + " ... suppressed 2 lines", + " ... 3 more", + " Wrapped by: foo.TestFriendlyException: r_s [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " ... suppressed 2 lines", + " ... 3 more")); + } - /** - * Sanity check for testFull1() above, makes sure that the way testFull1 is written matches actually throwing - * exceptions. - */ - @Test - public void testFull2() { - final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, null); - Throwable parent; - try { - try { - throw new NullPointerException("null pointer"); - } catch (final NullPointerException e) { - throw new IllegalArgumentException("IllegalArgument", e); - } - } catch (final IllegalArgumentException e) { - parent = e; + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(org.apache)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Wrapped by: foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.(TestFriendlyException.java:0)", + " ...", + " Suppressed: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + " Wrapped by: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more")); } - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - // System.out.print(result); - assertTrue( - result.contains("Wrapped by: java.lang.IllegalArgumentException: IllegalArgument"), - "Missing Exception"); - assertTrue(result.startsWith("java.lang.NullPointerException: null pointer"), "Incorrect start of msg"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java deleted file mode 100644 index 5695b1a1f8a..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRendererTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.assertStackTraceLineMatches; - -import foo.TestFriendlyException; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -class ThrowableExtendedStackTraceRendererTest { - - static final String NEWLINE = System.lineSeparator(); - - static final Exception EXCEPTION = TestFriendlyException.INSTANCE; - - static int[] maxLineCounts() { - return ThrowableStackTraceRendererTest.maxLineCounts(); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_maxLineCount_should_match(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingLog4j(emptyList(), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - asList( - "foo.TestFriendlyException: r", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at org.apache.logging.log4j.core.pattern.ThrowableExtendedStackTraceRendererTest.(ThrowableExtendedStackTraceRendererTest.java:%DIGITS%) [test-classes/:?]", - " Suppressed: foo.TestFriendlyException: r_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - " Caused by: foo.TestFriendlyException: r_s_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more")); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingLog4j(singletonList("foo"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - asList( - "foo.TestFriendlyException: r", - " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ThrowableExtendedStackTraceRendererTest.(ThrowableExtendedStackTraceRendererTest.java:%DIGITS%) [test-classes/:?]", - " Suppressed: foo.TestFriendlyException: r_s", - " ... suppressed 2 lines", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " ... suppressed 2 lines", - " ... 3 more", - " Caused by: foo.TestFriendlyException: r_s_c", - " ... suppressed 2 lines", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c", - " ... suppressed 2 lines", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " ... suppressed 2 lines", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c_c", - " ... suppressed 2 lines", - " ... 3 more")); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingLog4j(singletonList("org.apache"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - asList( - "foo.TestFriendlyException: r", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... ", - " Suppressed: foo.TestFriendlyException: r_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - " Caused by: foo.TestFriendlyException: r_s_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%) ~[test-classes/:?]", - " ... 3 more")); - } - - private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableStackTraceRenderer renderer = - new ThrowableExtendedStackTraceRenderer(ignoredPackageNames, maxLineCount); - final StringBuilder rendererOutputBuilder = new StringBuilder(); - renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); - return rendererOutputBuilder.toString(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java deleted file mode 100644 index 9bbcdbce676..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRendererTest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.EXCEPTION; -import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.NEWLINE; -import static org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.assertStackTraceLineMatches; - -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -class ThrowableInvertedStackTraceRendererTest { - - static int[] maxLineCounts() { - return ThrowableStackTraceRendererTest.maxLineCounts(); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_maxLineCount_should_match(final int maxLineCount) { - final String stackTrace = renderStackTrace(emptyList(), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - Arrays.asList( - "foo.TestFriendlyException: r_c_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.ThrowableInvertedStackTraceRendererTest.maxLineCounts(ThrowableInvertedStackTraceRendererTest.java:%DIGITS%)", - " Suppressed: foo.TestFriendlyException: r_s_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - " Wrapped by: foo.TestFriendlyException: r_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more")); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { - final String stackTrace = renderStackTrace(singletonList("foo"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - Arrays.asList( - "foo.TestFriendlyException: r_c_c", - " ... suppressed 2 lines", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r_c", - " ... suppressed 2 lines", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " ... suppressed 2 lines", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r", - " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", - " at org.apache.logging.log4j.core.pattern.ThrowableInvertedStackTraceRendererTest.maxLineCounts(ThrowableInvertedStackTraceRendererTest.java:%DIGITS%)", - " Suppressed: foo.TestFriendlyException: r_s_c", - " ... suppressed 2 lines", - " ... 4 more", - " Wrapped by: foo.TestFriendlyException: r_s", - " ... suppressed 2 lines", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " ... suppressed 2 lines", - " ... 4 more")); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { - final String stackTrace = renderStackTrace(singletonList("org.apache"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - Arrays.asList( - "foo.TestFriendlyException: r_c_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - "Wrapped by: foo.TestFriendlyException: r", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", - " ... suppressed 2 lines", - " Suppressed: foo.TestFriendlyException: r_s_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more", - " Wrapped by: foo.TestFriendlyException: r_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 4 more")); - } - - private static String renderStackTrace(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableStackTraceRenderer renderer = - new ThrowableInvertedStackTraceRenderer(ignoredPackageNames, maxLineCount); - final StringBuilder rendererOutputBuilder = new StringBuilder(); - renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); - return rendererOutputBuilder.toString(); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 4a6e2a6fef5..8a435fdc96f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -16,245 +16,409 @@ */ package org.apache.logging.log4j.core.pattern; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import foo.TestFriendlyException; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.util.Integers; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.util.Strings; -import org.junit.jupiter.api.Test; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +/** + * {@link ThrowablePatternConverter} tests. + */ public class ThrowablePatternConverterTest { - private static final class LocalizedException extends Exception { + private static final String NEWLINE = System.lineSeparator(); - private static final long serialVersionUID = 1L; + private static final Throwable EXCEPTION = TestFriendlyException.INSTANCE; - @Override - public String getLocalizedMessage() { - return "I am localized."; + private static final StackTraceElement THROWING_METHOD = EXCEPTION.getStackTrace()[0]; + + private static final PatternParser PATTERN_PARSER = PatternLayout.createPatternParser(null); + + private static final Level LEVEL = Level.FATAL; + + static final class SeparatorTestCase { + + final String patternAddendum; + + private final String conversionEnding; + + private SeparatorTestCase(final String patternAddendum, final String conversionEnding) { + this.patternAddendum = patternAddendum; + this.conversionEnding = conversionEnding; } - } - private boolean everyLineEndsWith(final String text, final String suffix) { - final String[] lines = text.split(Strings.LINE_SEPARATOR); - for (final String line : lines) { - if (!line.trim().endsWith(suffix)) { - return false; - } + @Override + public String toString() { + return String.format("{patternAddendum=`%s`, conversionEnding=`%s`}", patternAddendum, conversionEnding); } - return true; } - /** - * TODO: Needs better a better exception? NumberFormatException is NOT helpful. - */ - @Test - public void testBadShortOption() { - final String[] options = {"short.UNKNOWN"}; - assertThrows(NumberFormatException.class, () -> ThrowablePatternConverter.newInstance(null, options)); + static Stream separatorTestCases() { + final String level = LEVEL.toString(); + return Stream.of( + // Only separators + new SeparatorTestCase("{separator()}", ""), + new SeparatorTestCase("{separator(#)}", "#"), + // Only suffixes + new SeparatorTestCase("{suffix()}", NEWLINE), + new SeparatorTestCase("{suffix(~)}", " ~" + NEWLINE), + new SeparatorTestCase("{suffix(%level)}", " " + level + NEWLINE), + new SeparatorTestCase("{suffix(%rEx)}", NEWLINE), + // Both separators and suffixes + new SeparatorTestCase("{separator()}{suffix()}", ""), + new SeparatorTestCase("{separator()}{suffix(~)}", " ~"), + new SeparatorTestCase("{separator()}{suffix(%level)}", " " + level), + new SeparatorTestCase("{separator()}{suffix(%rEx)}", ""), + new SeparatorTestCase("{separator(#)}{suffix()}", "#"), + new SeparatorTestCase("{separator(#)}{suffix(~)}", " ~#"), + new SeparatorTestCase("{separator(#)}{suffix(%level)}", " " + level + "#"), + new SeparatorTestCase("{separator(#)}{suffix(%rEx)}", "#")); } - @Test - public void testFull() { - final String[] options = {"full"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - Throwable parent; - try { - try { - throw new NullPointerException("null pointer"); - } catch (final NullPointerException e) { - throw new IllegalArgumentException("IllegalArgument", e); - } - } catch (final IllegalArgumentException e) { - parent = e; + @Nested + class PropertyTest extends AbstractPropertyTest { + + PropertyTest() { + super("%ex"); } - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - // System.out.print(result); - assertTrue(result.startsWith("java.lang.IllegalArgumentException: IllegalArgument"), "Incorrect start of msg"); - assertTrue(result.contains("java.lang.NullPointerException: null pointer"), "Missing nested exception"); } - @Test - public void testShortClassName() { - final String packageName = "org.apache.logging.log4j.core.pattern."; - final String[] options = {"short.className"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals( - packageName + "ThrowablePatternConverterTest" + Strings.LINE_SEPARATOR, - result, - "The class names should be same"); + abstract static class AbstractPropertyTest { + + private final String patternPrefix; + + AbstractPropertyTest(final String patternPrefix) { + this.patternPrefix = patternPrefix; + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void message_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.message}", EXCEPTION.getMessage()); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void localizedMessage_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.localizedMessage}", EXCEPTION.getLocalizedMessage()); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void className_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.className}", THROWING_METHOD.getClassName()); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void methodName_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.methodName}", THROWING_METHOD.getMethodName()); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void lineNumber_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.lineNumber}", THROWING_METHOD.getLineNumber() + ""); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void fileName_should_be_rendered(final SeparatorTestCase separatorTestCase) { + assertConversion(separatorTestCase, "{short.fileName}", THROWING_METHOD.getFileName()); + } + + private void assertConversion( + final SeparatorTestCase separatorTestCase, final String pattern, final Object expectedOutput) { + final String effectivePattern = patternPrefix + pattern + separatorTestCase.patternAddendum; + final String output = convert(effectivePattern); + final String effectiveExpectedOutput = expectedOutput + separatorTestCase.conversionEnding; + assertThat(output) + .as( + "pattern=`%s`, separatorTestCase=%s, expectedOutput=`%s`", + pattern, separatorTestCase, expectedOutput) + .isEqualTo(effectiveExpectedOutput); + } } - @Test - public void testShortFileName() { - final String[] options = {"short.fileName"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals( - "ThrowablePatternConverterTest.java" + Strings.LINE_SEPARATOR, result, "The file names should be same"); + static final class DepthTestCase { + + final SeparatorTestCase separatorTestCase; + + final int maxLineCount; + + private DepthTestCase(final SeparatorTestCase separatorTestCase, final int maxLineCount) { + this.separatorTestCase = separatorTestCase; + this.maxLineCount = maxLineCount; + } + + @Override + public String toString() { + return String.format("{separatorTestCase=%s, maxLineCount=%d}", separatorTestCase, maxLineCount); + } } - @Test - public void testShortLineNumber() { - final String[] options = {"short.lineNumber"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final StackTraceElement top = parent.getStackTrace()[0]; - final int expectedLineNumber = top.getLineNumber(); - - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals(Integers.parseInt(result), expectedLineNumber, "The line numbers should be same"); + static Stream depthTestCases() { + return separatorTestCases().flatMap(separatorTestCase -> maxLineCounts() + .map(maxLineCount -> new DepthTestCase(separatorTestCase, maxLineCount))); } - @Test - public void testShortLocalizedMessage() { - final String[] options = {"short.localizedMessage"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable parent = new LocalizedException(); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals("I am localized." + Strings.LINE_SEPARATOR, result, "The messages should be same"); + static Stream maxLineCounts() { + return Stream.of(0, 1, 2, 3, 4, 5, 10, 15, 20, Integer.MAX_VALUE); } - @Test - public void testShortMessage() { - final String[] options = {"short.message"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals("IllegalArgument" + Strings.LINE_SEPARATOR, result, "The messages should be same"); + static Stream fullStackTracePatterns() { + return Stream.of("", "{}", "{full}", "{" + Integer.MAX_VALUE + "}", "{separator(" + NEWLINE + ")}"); } - @Test - public void testShortMethodName() { - final String[] options = {"short.methodName"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertEquals("testShortMethodName" + Strings.LINE_SEPARATOR, result, "The method names should be same"); + @Nested + class StackTraceTest extends AbstractStackTraceTest { + + StackTraceTest() { + super("%ex"); + } + + // This test does not provide `separator` and `suffix` options, since the reference output will be obtained from + // `Throwable#printStackTrace()`, which doesn't take these into account. + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#fullStackTracePatterns") + void full_output_should_match_Throwable_printStackTrace(final String pattern) { + final String expectedStackTrace = renderStackTraceUsingJava(); + final String effectivePattern = patternPrefix + pattern; + final String actualStackTrace = convert(effectivePattern); + assertThat(actualStackTrace).as("pattern=`%s`", effectivePattern).isEqualTo(expectedStackTrace); + } + + // This test does not provide `separator` and `suffix` options, since the reference output will be obtained from + // `Throwable#printStackTrace()`, which doesn't take these into account. + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#maxLineCounts") + void depth_limited_output_should_match_Throwable_printStackTrace(final int maxLineCount) { + final String expectedStackTrace = renderStackTraceUsingJava(maxLineCount); + final String effectivePattern = patternPrefix + '{' + maxLineCount + '}'; + final String actualStackTrace = convert(effectivePattern); + assertThat(actualStackTrace).as("pattern=`%s`", effectivePattern).isEqualTo(expectedStackTrace); + } + + private String renderStackTraceUsingJava(final int maxLineCount) { + if (maxLineCount == 0) { + return ""; + } + final String stackTrace = renderStackTraceUsingJava(); + if (maxLineCount == Integer.MAX_VALUE) { + return stackTrace; + } + return limitLines(stackTrace, maxLineCount); + } + + private String limitLines(final String text, final int maxLineCount) { + final StringBuilder buffer = new StringBuilder(); + int lineCount = 0; + int startIndex = 0; + int newlineIndex; + while (lineCount < maxLineCount && (newlineIndex = text.indexOf(NEWLINE, startIndex)) != -1) { + final String line = text.substring(startIndex, newlineIndex + NEWLINE.length()); + buffer.append(line); + lineCount++; + startIndex = newlineIndex + 1; + } + return buffer.toString(); + } + + private String renderStackTraceUsingJava() { + final Charset charset = StandardCharsets.UTF_8; + try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final PrintStream printStream = new PrintStream(outputStream, false, charset.name())) { + EXCEPTION.printStackTrace(printStream); + printStream.flush(); + return new String(outputStream.toByteArray(), charset); + } catch (final Exception error) { + throw new RuntimeException(error); + } + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_limited_output_should_match(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.(TestFriendlyException.java:0)", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more")); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(foo)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r [localized]", + " ... suppressed 2 lines", + " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " ... suppressed 2 lines", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " ... suppressed 2 lines", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " ... suppressed 2 lines", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " ... suppressed 2 lines", + " ... 3 more")); + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#depthTestCases") + void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTestCase) { + final String pattern = String.format( + "%s{%d}{filters(org.apache)}%s", + patternPrefix, depthTestCase.maxLineCount, depthTestCase.separatorTestCase.patternAddendum); + assertStackTraceLines( + depthTestCase, + pattern, + asList( + "foo.TestFriendlyException: r [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.(TestFriendlyException.java:0)", + " ...", + " Suppressed: foo.TestFriendlyException: r_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_s_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + " Caused by: foo.TestFriendlyException: r_s_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 2 more", + " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more", + "Caused by: foo.TestFriendlyException: r_c_c [localized]", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", + " ... 3 more")); + } } - @Test - public void testFullWithSuffix() { - final String[] options = {"full", "suffix(test suffix)"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - Throwable parent; - try { - try { - throw new NullPointerException("null pointer"); - } catch (final NullPointerException e) { - throw new IllegalArgumentException("IllegalArgument", e); + abstract static class AbstractStackTraceTest { + + final String patternPrefix; + + AbstractStackTraceTest(final String patternPrefix) { + this.patternPrefix = patternPrefix; + } + + @ParameterizedTest + @MethodSource("org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest#separatorTestCases") + void none_output_should_be_empty(final SeparatorTestCase separatorTestCase) { + final String effectivePattern = patternPrefix + "{none}" + separatorTestCase.patternAddendum; + final String stackTrace = convert(effectivePattern); + assertThat(stackTrace).as("pattern=`%s`", effectivePattern).isEmpty(); + } + + void assertStackTraceLines( + @Nullable final DepthTestCase depthTestCase, + final String pattern, + final List expectedStackTraceLines) { + final String actualStackTrace = convert(pattern); + final int maxLineCount; + final String conversionEnding; + if (depthTestCase == null) { + maxLineCount = Integer.MAX_VALUE; + conversionEnding = NEWLINE; + } else { + maxLineCount = depthTestCase.maxLineCount; + conversionEnding = depthTestCase.separatorTestCase.conversionEnding; } - } catch (final IllegalArgumentException e) { - parent = e; + final String expectedStackTrace = expectedStackTraceLines.stream() + .limit(maxLineCount) + .map(expectedStackTraceLine -> expectedStackTraceLine + conversionEnding) + .collect(Collectors.joining()); + final String truncatedActualStackTrace = truncateStackTraceLineNumbers(actualStackTrace); + final String truncatedExpectedStackTrace = truncateStackTraceLineNumbers(expectedStackTrace); + assertThat(truncatedActualStackTrace) + .as("depthTestCase=%s, pattern=`%s`", depthTestCase, pattern) + .isEqualTo(truncatedExpectedStackTrace); + } + + private static String truncateStackTraceLineNumbers(final String stackTrace) { + return stackTrace.replaceAll("\\.java:[0-9]+\\)", ".java:0"); } - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue( - everyLineEndsWith(result, "test suffix"), - "Each line of full stack trace should end with the specified suffix"); } - @Test - public void testShortOptionWithSuffix() { - final String packageName = "org.apache.logging.log4j.core.pattern."; - final String[] options = {"short.className", "suffix(test suffix)"}; - final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); - final Throwable cause = new NullPointerException("null pointer"); - final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent) - .build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(everyLineEndsWith(result, "test suffix"), "Each line should end with suffix"); + private static String convert(final String pattern) { + final List patternFormatters = PATTERN_PARSER.parse(pattern, false, true, true); + assertThat(patternFormatters).hasSize(1); + final PatternFormatter patternFormatter = patternFormatters.get(0); + final LogEvent logEvent = + Log4jLogEvent.newBuilder().setThrown(EXCEPTION).setLevel(LEVEL).build(); + final StringBuilder buffer = new StringBuilder(); + patternFormatter.format(logEvent, buffer); + return buffer.toString(); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java deleted file mode 100644 index cfb3cccad35..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRendererTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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.apache.logging.log4j.core.pattern; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; - -import foo.TestFriendlyException; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -class ThrowableStackTraceRendererTest { - - static final String NEWLINE = System.lineSeparator(); - - static final Exception EXCEPTION = TestFriendlyException.INSTANCE; - - @Test - void output_should_match_Throwable_printStackTrace() { - final String log4jOutput = renderStackTraceUsingLog4j(emptyList(), Integer.MAX_VALUE); - final String javaOutput = renderStackTraceUsingJava(); - assertThat(log4jOutput).isEqualTo(javaOutput); - } - - static int[] maxLineCounts() { - return new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, Integer.MAX_VALUE}; - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_maxLineCount_should_match_Throwable_printStackTrace(final int maxLineCount) { - final String log4jOutput = renderStackTraceUsingLog4j(emptyList(), maxLineCount); - final String javaOutput = renderStackTraceUsingJava(maxLineCount); - assertThat(log4jOutput).isEqualTo(javaOutput); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_1(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingLog4j(singletonList("foo"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - asList( - "foo.TestFriendlyException: r", - " ... suppressed 2 lines", - " at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRendererTest.(ThrowableStackTraceRendererTest.java:%DIGITS%)", - " Suppressed: foo.TestFriendlyException: r_s", - " ... suppressed 2 lines", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " ... suppressed 2 lines", - " ... 3 more", - " Caused by: foo.TestFriendlyException: r_s_c", - " ... suppressed 2 lines", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c", - " ... suppressed 2 lines", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " ... suppressed 2 lines", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c_c", - " ... suppressed 2 lines", - " ... 3 more")); - } - - @ParameterizedTest - @MethodSource("maxLineCounts") - void output_produced_with_ignoredPackageNames_and_maxLineCount_should_match_2(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingLog4j(singletonList("org.apache"), maxLineCount); - assertStackTraceLineMatches( - stackTrace, - maxLineCount, - asList( - "foo.TestFriendlyException: r", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.(TestFriendlyException.java:%DIGITS%)", - " ... ", - " Suppressed: foo.TestFriendlyException: r_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_s_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - " Caused by: foo.TestFriendlyException: r_s_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more", - "Caused by: foo.TestFriendlyException: r_c_c", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " at foo.TestFriendlyException.create(TestFriendlyException.java:%DIGITS%)", - " ... 3 more")); - } - - private static String renderStackTraceUsingLog4j(final List ignoredPackageNames, final int maxLineCount) { - final ThrowableStackTraceRenderer renderer = - new ThrowableStackTraceRenderer<>(ignoredPackageNames, maxLineCount); - final StringBuilder rendererOutputBuilder = new StringBuilder(); - renderer.renderThrowable(rendererOutputBuilder, EXCEPTION, NEWLINE); - return rendererOutputBuilder.toString(); - } - - private static String renderStackTraceUsingJava(final int maxLineCount) { - final String stackTrace = renderStackTraceUsingJava(); - if (maxLineCount == Integer.MAX_VALUE) { - return stackTrace; - } - return splitLines(stackTrace).stream().limit(maxLineCount).collect(Collectors.joining()); - } - - @SuppressWarnings("SameParameterValue") - private static String renderStackTraceUsingJava() { - final Charset charset = StandardCharsets.UTF_8; - try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - final PrintStream printStream = new PrintStream(outputStream, false, charset.name())) { - EXCEPTION.printStackTrace(printStream); - printStream.flush(); - return new String(outputStream.toByteArray(), charset); - } catch (final Exception error) { - throw new RuntimeException(error); - } - } - - static void assertStackTraceLineMatches( - final String actualStackTrace, final int maxLineCount, final List expectedStackTraceLineRegexes) { - final List actualStackTraceLines = splitLines(actualStackTrace); - final int expectedLineCount = Math.min(maxLineCount, expectedStackTraceLineRegexes.size()); - assertThat(actualStackTraceLines).hasSize(expectedLineCount); - for (int lineIndex = 0; lineIndex < expectedLineCount; lineIndex++) { - final String actualStackTraceLine = actualStackTraceLines.get(lineIndex); - final String expectedStackTraceLineRegex = expectedStackTraceLineRegexes.get(lineIndex); - final String interpolatedExpectedStackTraceLineRegex = - expectedStackTraceLineRegex.replaceAll("%DIGITS%", "\\\\E\\\\d+\\\\Q"); - assertThat(actualStackTraceLine) - .as("line at index %d of stack trace:%n%s", lineIndex, actualStackTrace) - .matches("^\\Q" + interpolatedExpectedStackTraceLineRegex + NEWLINE + "\\E$"); - } - } - - private static List splitLines(final String text) { - final List lines = new ArrayList<>(); - int startIndex = 0; - int lfIndex; - while ((lfIndex = text.indexOf('\n', startIndex)) != -1) { - final String line = text.substring(startIndex, lfIndex + 1); - lines.add(line); - startIndex = lfIndex + 1; - } - return lines; - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java deleted file mode 100644 index 4b6099e82e5..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/internal/StringBuildersTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.apache.logging.log4j.core.util.internal; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.Arrays; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class StringBuildersTest { - - static Stream truncateAfterDelimiter_should_succeed_inputs() { - return Stream.of( - // maxOccurrenceCount < lines count - Arguments.of("abc#def#ghi#jkl#", "#", 2), - // maxOccurrenceCount == lines count - Arguments.of("abc#def#ghi#jkl#", "#", 4), - // maxOccurrenceCount > lines count - Arguments.of("abc#def#ghi#jkl#", "#", 10), - // maxOccurrenceCount == Integer.MAX_VALUE - Arguments.of("abc#def#ghi#jkl#", "#", Integer.MAX_VALUE), - // maxOccurrenceCount == 0 - Arguments.of("abc#def#ghi#jkl#", "#", 0), - // empty buffer - Arguments.of("", "#", 2), - // empty delimiter - Arguments.of("abc#def#ghi#jkl#", "", 2), - // delimiter # - Arguments.of("#", "#", 1), - Arguments.of("##", "#", 1), - Arguments.of("a#", "#", 1), - Arguments.of("#a", "#", 1), - // delimiter ## - Arguments.of("##", "##", 1), - Arguments.of("###", "##", 1), - Arguments.of("####", "##", 1), - Arguments.of("a#", "##", 1), - Arguments.of("a##", "##", 1), - Arguments.of("a###", "##", 1), - Arguments.of("a####", "##", 1), - Arguments.of("#a", "##", 1), - Arguments.of("##a", "##", 1), - Arguments.of("###a", "##", 1), - Arguments.of("####a", "##", 1)); - } - - @ParameterizedTest - @MethodSource("truncateAfterDelimiter_should_succeed_inputs") - void truncateAfterDelimiter_should_succeed( - final String input, final String delimiter, final int maxOccurrenceCount) { - final StringBuilder buffer = new StringBuilder(input); - StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount); - final String expected; - if (delimiter.isEmpty()) { - expected = input; - } else if (buffer.length() == 0) { - expected = ""; - } else { - expected = Arrays.stream(input.split(delimiter)) - .limit(maxOccurrenceCount) - .collect(Collectors.joining(delimiter, "", delimiter)); - } - assertThat(buffer.toString()).isEqualTo(expected); - } - - static Stream truncateAfterDelimiter_should_fail_inputs() { - return Stream.of( - // negative maxOccurrenceCount - Arguments.of("abc#def#ghi#jkl#", "#", -1, IllegalArgumentException.class), - // null buffer - Arguments.of(null, "#", 10, NullPointerException.class), - // null delimiter - Arguments.of("abc#def#ghi#jkl#", null, 10, NullPointerException.class)); - } - - @ParameterizedTest - @MethodSource("truncateAfterDelimiter_should_fail_inputs") - void truncateAfterDelimiter_should_fail( - final String input, final String delimiter, final int maxOccurrenceCount, final Class expected) { - final StringBuilder buffer = input == null ? null : new StringBuilder(input); - assertThatThrownBy(() -> StringBuilders.truncateAfterDelimiter(buffer, delimiter, maxOccurrenceCount)) - .isInstanceOf(expected); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java index fc5417911f1..5df74e5d9cd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java @@ -189,7 +189,7 @@ public boolean anyLines() { * @return The number of lines to print. */ public int minLines(final int maxLines) { - return this.lines > maxLines ? maxLines : this.lines; + return Math.min(this.lines, maxLines); } /** @@ -267,13 +267,13 @@ public static ThrowableFormatOptions newInstance(String[] options) { separator = option.substring("separator(".length(), option.length() - 1); } else if (option.startsWith("filters(") && option.endsWith(")")) { final String filterStr = option.substring("filters(".length(), option.length() - 1); - if (filterStr.length() > 0) { + if (!filterStr.isEmpty()) { final String[] array = filterStr.split(Patterns.COMMA_SEPARATOR); if (array.length > 0) { packages = new ArrayList<>(array.length); for (String token : array) { token = token.trim(); - if (token.length() > 0) { + if (!token.isEmpty()) { packages.add(token); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java index aa354a4f4f1..0b17d0e224f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java @@ -53,17 +53,20 @@ void renderStackTraceElement( final String lineSeparator) { // Short-circuit on ignored stack trace elements - final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement); if (stackTraceElementIgnored) { context.ignoredStackTraceElementCount += 1; return; } - // Render the stack trace element + // Render the suppressed stack trace element count if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } + + // Render the stack trace element + acquireLineCapacity(context); buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java index f141de74f19..4c830190cb4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Set; +import org.jspecify.annotations.Nullable; /** * {@link ThrowableStackTraceRenderer} variant where the stack trace causal chain is rendered in reverse order. @@ -38,7 +39,7 @@ void renderThrowable( final Context context, final Set visitedThrowables, final String lineSeparator) { - renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator); + renderThrowable(buffer, throwable, context, visitedThrowables, "", lineSeparator, false); } private void renderThrowable( @@ -47,31 +48,44 @@ private void renderThrowable( final Context context, final Set visitedThrowables, final String prefix, - final String lineSeparator) { + final String lineSeparator, + boolean lineCapacityAcquired) { if (visitedThrowables.contains(throwable)) { return; } visitedThrowables.add(throwable); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); + if (!renderCause( + buffer, + throwable.getCause(), + context, + visitedThrowables, + prefix, + lineSeparator, + lineCapacityAcquired)) { + acquireLineCapacity(context); + } renderThrowableMessage(buffer, throwable); buffer.append(lineSeparator); renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); } - @Override - void renderCause( + private boolean renderCause( final StringBuilder buffer, - final Throwable cause, + @Nullable final Throwable cause, final Context context, final Set visitedThrowables, final String prefix, - final String lineSeparator) { + final String lineSeparator, + final boolean lineCapacityAcquired) { if (cause != null) { - renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator); + renderThrowable(buffer, cause, context, visitedThrowables, prefix, lineSeparator, lineCapacityAcquired); + acquireLineCapacity(context); buffer.append(prefix); buffer.append(WRAPPED_BY_CAPTION); + return true; } + return lineCapacityAcquired; } @Override @@ -82,11 +96,23 @@ void renderSuppressed( final Set visitedThrowables, final String prefix, final String lineSeparator) { - if (suppressedThrowables != null && suppressedThrowables.length != 0) { + if (suppressedThrowables.length > 0) { + acquireLineCapacity(context); buffer.append(prefix); buffer.append(SUPPRESSED_CAPTION); - for (final Throwable suppressedThrowable : suppressedThrowables) { - renderThrowable(buffer, suppressedThrowable, context, visitedThrowables, prefix, lineSeparator); + for (int suppressedThrowableIndex = 0; + suppressedThrowableIndex < suppressedThrowables.length; + suppressedThrowableIndex++) { + final Throwable suppressedThrowable = suppressedThrowables[suppressedThrowableIndex]; + final boolean lineCapacityAcquired = suppressedThrowableIndex == 0; + renderThrowable( + buffer, + suppressedThrowable, + context, + visitedThrowables, + prefix, + lineSeparator, + lineCapacityAcquired); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java index bf9840a11d6..e39997ff449 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java @@ -21,15 +21,19 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.logging.log4j.core.util.internal.StringBuilders; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * {@link ThrowableRenderer} implementation for rendering stack traces. * * @param the context type */ +@NullMarked class ThrowableStackTraceRenderer implements ThrowableRenderer { + private static final RuntimeException MAX_LINE_COUNT_EXCEEDED = new RuntimeException("max-line-count-exceeded"); + private static final String CAUSED_BY_CAPTION = "Caused by: "; static final String SUPPRESSED_CAPTION = "Suppressed: "; @@ -46,9 +50,16 @@ class ThrowableStackTraceRenderer @Override public final void renderThrowable( final StringBuilder buffer, final Throwable throwable, final String lineSeparator) { - C context = createContext(throwable); - renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); - StringBuilders.truncateAfterDelimiter(buffer, lineSeparator, maxLineCount); + if (maxLineCount > 0) { + try { + C context = createContext(throwable); + renderThrowable(buffer, throwable, context, new HashSet<>(), lineSeparator); + } catch (final Exception error) { + if (error != MAX_LINE_COUNT_EXCEEDED) { + throw error; + } + } + } } @SuppressWarnings("unchecked") @@ -77,6 +88,7 @@ private void renderThrowable( if (visitedThrowables.contains(throwable)) { return; } + acquireLineCapacity(context); visitedThrowables.add(throwable); buffer.append(prefix); buffer.append(caption); @@ -87,6 +99,14 @@ private void renderThrowable( renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); } + void acquireLineCapacity(final C context) { + if (context.lineCount < maxLineCount) { + context.lineCount++; + } else { + throw MAX_LINE_COUNT_EXCEEDED; + } + } + void renderSuppressed( final StringBuilder buffer, final Throwable[] suppressedThrowables, @@ -100,9 +120,9 @@ void renderSuppressed( } } - void renderCause( + private void renderCause( final StringBuilder buffer, - final Throwable cause, + @Nullable final Throwable cause, final C context, final Set visitedThrowables, final String prefix, @@ -113,7 +133,7 @@ void renderCause( } static void renderThrowableMessage(final StringBuilder buffer, final Throwable throwable) { - final String message = throwable.getMessage(); + final String message = throwable.getLocalizedMessage(); buffer.append(throwable.getClass().getName()); if (message != null) { buffer.append(": "); @@ -134,9 +154,10 @@ final void renderStackTraceElements( renderStackTraceElement(buffer, stackTraceElements[i], context, prefix, lineSeparator); } if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context, prefix, lineSeparator); } if (metadata.commonElementCount != 0) { + acquireLineCapacity(context); buffer.append(prefix); buffer.append("\t... "); buffer.append(metadata.commonElementCount); @@ -153,28 +174,31 @@ void renderStackTraceElement( final String lineSeparator) { // Short-circuit on ignored stack trace elements - final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement, ignoredPackageNames); + final boolean stackTraceElementIgnored = isStackTraceElementIgnored(stackTraceElement); if (stackTraceElementIgnored) { context.ignoredStackTraceElementCount += 1; return; } - // Render the stack trace element + // Render the suppressed stack trace element count if (context.ignoredStackTraceElementCount > 0) { - renderSuppressedCount(buffer, context.ignoredStackTraceElementCount, prefix, lineSeparator); + renderSuppressedCount(buffer, context, prefix, lineSeparator); context.ignoredStackTraceElementCount = 0; } + + // Render the stack trace element + acquireLineCapacity(context); buffer.append(prefix); buffer.append("\tat "); buffer.append(stackTraceElement.toString()); buffer.append(lineSeparator); } - static boolean isStackTraceElementIgnored(final StackTraceElement element, final List ignorePackages) { - if (ignorePackages != null) { + boolean isStackTraceElementIgnored(final StackTraceElement element) { + if (ignoredPackageNames != null) { final String className = element.getClassName(); - for (final String ignoredPackage : ignorePackages) { - if (className.startsWith(ignoredPackage)) { + for (final String ignoredPackageName : ignoredPackageNames) { + if (className.startsWith(ignoredPackageName)) { return true; } } @@ -182,14 +206,15 @@ static boolean isStackTraceElementIgnored(final StackTraceElement element, final return false; } - static void renderSuppressedCount( - final StringBuilder buffer, final int count, final String prefix, final String lineSeparator) { + void renderSuppressedCount( + final StringBuilder buffer, final C context, final String prefix, final String lineSeparator) { + acquireLineCapacity(context); buffer.append(prefix); - if (count == 1) { - buffer.append("\t... "); + if (context.ignoredStackTraceElementCount == 1) { + buffer.append("\t..."); } else { buffer.append("\t... suppressed "); - buffer.append(count); + buffer.append(context.ignoredStackTraceElementCount); buffer.append(" lines"); } buffer.append(lineSeparator); @@ -197,6 +222,11 @@ static void renderSuppressedCount( static class Context { + /** + * Number of lines consumed from the {@link Throwable} causal chain so far. + */ + int lineCount = 0; + /** * Number of stack trace elements ignored. *

      @@ -247,10 +277,11 @@ static Map ofThrowable(final Throwable throwable) { private static void populateMetadata( final Map metadataByThrowable, final Set visitedThrowables, - final Throwable parentThrowable, + @Nullable final Throwable parentThrowable, final Throwable throwable) { // Populate metadata of the current throwable + @Nullable final StackTraceElement[] rootTrace = parentThrowable == null ? null : parentThrowable.getStackTrace(); final Metadata metadata = populateMetadata(rootTrace, throwable.getStackTrace()); metadataByThrowable.put(throwable, metadata); @@ -264,7 +295,7 @@ private static void populateMetadata( } // Populate metadata of the causal chain - final Throwable cause = throwable.getCause(); + @Nullable final Throwable cause = throwable.getCause(); if (cause != null && !visitedThrowables.contains(cause)) { visitedThrowables.add(cause); populateMetadata(metadataByThrowable, visitedThrowables, throwable, cause); @@ -272,7 +303,7 @@ private static void populateMetadata( } private static Metadata populateMetadata( - final StackTraceElement[] parentTrace, final StackTraceElement[] currentTrace) { + @Nullable final StackTraceElement[] parentTrace, final StackTraceElement[] currentTrace) { int commonElementCount; int stackLength; if (parentTrace != null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java deleted file mode 100644 index 547f5dbab03..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/StringBuilders.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.apache.logging.log4j.core.util.internal; - -import java.util.Objects; - -/** - * StringBuilder helpers - */ -public class StringBuilders { - - /** - * Truncates the content of the given {@code StringBuilder} after the specified times of occurrences of the given delimiter. - * - *

      If {@code maxOccurrenceCount} is {@link Integer#MAX_VALUE}, or if {@code delimiter} is empty, - * the method returns without making any changes to the {@code StringBuilder}. - * - * @param buffer the {@code StringBuilder} to be truncated - * @param delimiter The delimiter to be used. - * Setting this value to an empty string effectively disables truncation. - * @param maxOccurrenceCount Denotes the maximum number of {@code delimiter} occurrences allowed. - * Setting this value to {@link Integer#MAX_VALUE} effectively disables truncation. - */ - public static void truncateAfterDelimiter( - final StringBuilder buffer, final String delimiter, final int maxOccurrenceCount) { - Objects.requireNonNull(buffer, "buffer"); - Objects.requireNonNull(delimiter, "delimiter"); - if (maxOccurrenceCount < 0) { - throw new IllegalArgumentException("`maxOccurrenceCount` should not be negative"); - } - if (buffer.length() < delimiter.length() || delimiter.isEmpty() || maxOccurrenceCount == Integer.MAX_VALUE) { - return; - } - final int delimiterLen = delimiter.length(); - int offset = 0; - int currentOccurrenceCount = 0; - while (currentOccurrenceCount < maxOccurrenceCount) { - int delimiterIndex = buffer.indexOf(delimiter, offset); - if (delimiterIndex == -1) { - break; - } - currentOccurrenceCount++; - offset = delimiterIndex + delimiterLen; - } - buffer.setLength(offset); - } -} From 7108d3634a2159e3a9beb0b48968c80684e72e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 26 Sep 2024 12:13:43 +0200 Subject: [PATCH 62/72] Improve docs --- .../ROOT/pages/manual/pattern-layout.adoc | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc index adccb098e42..4734a3e39ca 100644 --- a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc @@ -624,7 +624,7 @@ ex|exception|throwable {separator(separator)} ---- -By default this will output the full trace as one would normally find with a call to `Throwable#printStackTrace()`. +By default this will output the full stack trace as one would normally find with a call to `Throwable#printStackTrace()`. You can follow the throwable conversion word with an option in the form `%throwable\{option}`. @@ -632,11 +632,11 @@ You can follow the throwable conversion word with an option in the form `%throwa `%throwable{short.className}` outputs the name of the class where the exception occurred. -`%throwable{short.methodName}` outputs the method name where the exception occurred. +`%throwable{short.methodName}` outputs the name of the method where the exception occurred. -`%throwable{short.fileName}` outputs the name of the class where the exception occurred. +`%throwable{short.fileName}` outputs the name of the file containing the class where the exception occurred. -`%throwable{short.lineNumber}` outputs the line number where the exception occurred. +`%throwable{short.lineNumber}` outputs the line number of the file containing the class where the exception occurred. `%throwable{short.message}` outputs the message. @@ -646,7 +646,7 @@ You can follow the throwable conversion word with an option in the form `%throwa Specifying `%throwable\{none}` or `%throwable\{0}` suppresses output of the exception. -Use `{filters(packages)}` where _packages_ is a list of package names to suppress matching stack frames from stack traces. +Use `{filters(packages)}`, where `packages` is a list of package names, to suppress matching stack frames from stack traces. You can change the used line separator in multiple ways: @@ -655,6 +655,7 @@ It defaults to `System.lineSeparator()`. The contents of `separator` will be rendered verbatim without being subject to any processing. * `{suffix(pattern)}` is identical to `{separator(separator)}` with the exception that the provided `pattern` will be processed as a xref:manual/pattern-layout.adoc[] conversion pattern before being rendered. +Exception-rendering directives in the `pattern` (`%ex`, `%rEx`, etc.) will be discarded. `{separator(...)}` and `{suffix(pattern)}` get concatenated to produce _the effective line separator_ as follows: @@ -676,7 +677,7 @@ Exception converter is not garbage-free. [#converter-exception-extended] ==== Exception (Extended) -The same as <>, but also includes class packaging information +The same as <>, but also includes class packaging information .link:../javadoc/log4j-core/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.html[`ThrowablePatternConverter`] specifier grammar [source,text] @@ -1195,30 +1196,22 @@ The same as <>, but the stack tra [source,text] ---- rEx|rException|rThrowable - { - ["none" | "short" | "full" | depth] - [,filters(package,package,...)] - [,separator(separator)] - } - {ansi( - Key=Value,Value,... - Key=Value,Value,... - ...) + { "none" + | "full" + | depth + | "short" + | "short.className" + | "short.fileName" + | "short.lineNumber" + | "short.methodName" + | "short.message" + | "short.localizedMessage" } + {filters(package,package,...)} {suffix(pattern)} + {separator(separator)} ---- -The throwable conversion specifier can be followed by an option in the form `%rEx\{short}`, which will only output the first line of the `Throwable`, or `%rEx\{n}`, where the first `n` lines of the stack trace will be printed. - -Specifying `%rEx\{none}` or `%rEx\{0}` will suppress printing of the exception. - -Use `filters(packages)`, where `packages` is a list of package names to suppress matching stack frames from stack traces. - -Use a `separator` string to separate the lines of a stack trace, e.g., `separator(|)`. -The default value is the `line.separator` system property, which is platform dependent. - -Use `rEx{suffix(pattern)}` to add the output of `pattern` to the output only when there is a `Throwable` to print. - [#converter-seq] ==== Sequence number From 8c57109c2b4087cb8236a6e32d4a016aeb2a0a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 26 Sep 2024 13:12:24 +0200 Subject: [PATCH 63/72] Remove redundant changelog entries --- src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml | 2 +- .../.2.x.x/fix_throwable_converter_issues.xml | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 src/changelog/.2.x.x/fix_throwable_converter_issues.xml diff --git a/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml b/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml index b7c39d48c8c..8110ff25e3f 100644 --- a/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml +++ b/src/changelog/.2.x.x/2691_deprecate_ThrowableProxy.xml @@ -4,5 +4,5 @@ xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="deprecated"> - `ThrowableProxy` and its usages are deprecated + Deprecate `ThrowableProxy` and all its usages diff --git a/src/changelog/.2.x.x/fix_throwable_converter_issues.xml b/src/changelog/.2.x.x/fix_throwable_converter_issues.xml deleted file mode 100644 index fb81a7c0b57..00000000000 --- a/src/changelog/.2.x.x/fix_throwable_converter_issues.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Add `filters` and `depth` support to `%ex` and `%xEx` converters, respectively, of Pattern Layout - - From 2cf6d36632f4d019f55099c9f59f0559b140ff3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 27 Sep 2024 12:16:10 +0200 Subject: [PATCH 64/72] Add circular reference support --- .../test/java/foo/TestFriendlyException.java | 18 ++++++-- ...ExtendedThrowablePatternConverterTest.java | 12 +++-- .../RootThrowablePatternConverterTest.java | 18 +++++--- .../ThrowablePatternConverterTest.java | 14 ++++-- .../ThrowableInvertedStackTraceRenderer.java | 46 ++++++++++++------- .../pattern/ThrowableStackTraceRenderer.java | 23 ++++++---- 6 files changed, 88 insertions(+), 43 deletions(-) diff --git a/log4j-core-test/src/test/java/foo/TestFriendlyException.java b/log4j-core-test/src/test/java/foo/TestFriendlyException.java index f807896d078..20d6b969354 100644 --- a/log4j-core-test/src/test/java/foo/TestFriendlyException.java +++ b/log4j-core-test/src/test/java/foo/TestFriendlyException.java @@ -26,6 +26,7 @@ *

    • Distinct localized message
    • *
    • Non-Log4j package origin1
    • *
    • Sufficient causal chain depth
    • + *
    • Cyclic causal chain
    • *
    • Decorated with suppressed exceptions
    • *
    • A stack trace free of clutter (i.e., elements from JUnit, JDK, etc.)
    • *
    @@ -39,18 +40,27 @@ public final class TestFriendlyException extends RuntimeException { "java.lang", "jdk.internal", "org.junit", "sun.reflect" }; - public static final TestFriendlyException INSTANCE = create("r", 0, 2); + public static final TestFriendlyException INSTANCE = create("r", 0, 2, new boolean[] {false}); static { // Ensure the distinct packaging assertThat(TestFriendlyException.class.getPackage().getName()).doesNotStartWith("org.apache"); } - private static TestFriendlyException create(final String name, final int depth, final int maxDepth) { + private static TestFriendlyException create( + final String name, final int depth, final int maxDepth, final boolean[] circular) { final TestFriendlyException error = new TestFriendlyException(name); if (depth < maxDepth) { - error.initCause(create(name + "_c", depth + 1, maxDepth)); - error.addSuppressed(create(name + "_s", depth + 1, maxDepth)); + final TestFriendlyException cause = create(name + "_c", depth + 1, maxDepth, circular); + error.initCause(cause); + final TestFriendlyException suppressed = create(name + "_s", depth + 1, maxDepth, circular); + error.addSuppressed(suppressed); + final boolean circularAllowed = depth + 1 == maxDepth && !circular[0]; + if (circularAllowed) { + cause.initCause(error); + suppressed.initCause(error); + circular[0] = true; + } } return error; } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java index 2d0a3ba26f3..8262bd39a16 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java @@ -64,10 +64,12 @@ class PropertyTest extends AbstractPropertyTest { " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", - " ... 3 more"); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]"); @Nested class StackTraceTest extends AbstractStackTraceTest { @@ -120,9 +122,11 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe " Suppressed: foo.TestFriendlyException: r_c_s [localized]", " ... suppressed 2 lines", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " ... suppressed 2 lines", - " ... 3 more")); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]")); } @ParameterizedTest @@ -159,10 +163,12 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", - " ... 3 more")); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]")); } } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java index 7f656c8d497..af50d005fff 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java @@ -40,7 +40,8 @@ class PropertyTest extends AbstractPropertyTest { } private static final List EXPECTED_FULL_STACK_TRACE_LINES = asList( - "foo.TestFriendlyException: r_c_c [localized]", + "[CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + "Wrapped by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", @@ -48,7 +49,8 @@ class PropertyTest extends AbstractPropertyTest { " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " Suppressed: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + " Wrapped by: foo.TestFriendlyException: r_c_s [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", @@ -102,13 +104,15 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe depthTestCase, pattern, asList( - "foo.TestFriendlyException: r_c_c [localized]", + "[CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + "Wrapped by: foo.TestFriendlyException: r_c_c [localized]", " ... suppressed 2 lines", " ... 3 more", "Wrapped by: foo.TestFriendlyException: r_c [localized]", " ... suppressed 2 lines", " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " Suppressed: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + " Wrapped by: foo.TestFriendlyException: r_c_s [localized]", " ... suppressed 2 lines", " ... 3 more", "Wrapped by: foo.TestFriendlyException: r [localized]", @@ -135,7 +139,8 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe depthTestCase, pattern, asList( - "foo.TestFriendlyException: r_c_c [localized]", + "[CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + "Wrapped by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", @@ -143,7 +148,8 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 2 more", - " Suppressed: foo.TestFriendlyException: r_c_s [localized]", + " Suppressed: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", + " Wrapped by: foo.TestFriendlyException: r_c_s [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 8a435fdc96f..61eb8dbc5f1 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -285,10 +285,12 @@ void depth_limited_output_should_match(final DepthTestCase depthTestCase) { " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", - " ... 3 more")); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]")); } @ParameterizedTest @@ -319,9 +321,11 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe " Suppressed: foo.TestFriendlyException: r_c_s [localized]", " ... suppressed 2 lines", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " ... suppressed 2 lines", - " ... 3 more")); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]")); } @ParameterizedTest @@ -358,10 +362,12 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", + " Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]", "Caused by: foo.TestFriendlyException: r_c_c [localized]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", - " ... 3 more")); + " ... 3 more", + "Caused by: [CIRCULAR REFERENCE: foo.TestFriendlyException: r_c [localized]]")); } } @@ -407,7 +413,7 @@ void assertStackTraceLines( } private static String truncateStackTraceLineNumbers(final String stackTrace) { - return stackTrace.replaceAll("\\.java:[0-9]+\\)", ".java:0"); + return stackTrace.replaceAll("\\.java:[0-9]+\\)", ".java:0)"); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java index 4c830190cb4..786016f5496 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableInvertedStackTraceRenderer.java @@ -50,26 +50,38 @@ private void renderThrowable( final String prefix, final String lineSeparator, boolean lineCapacityAcquired) { - if (visitedThrowables.contains(throwable)) { - return; - } - visitedThrowables.add(throwable); - if (!renderCause( - buffer, - throwable.getCause(), - context, - visitedThrowables, - prefix, - lineSeparator, - lineCapacityAcquired)) { - acquireLineCapacity(context); + final boolean circular = !visitedThrowables.add(throwable); + if (circular) { + if (!lineCapacityAcquired) { + acquireLineCapacity(context); + } + buffer.append("[CIRCULAR REFERENCE: "); + renderThrowableMessage(buffer, throwable); + buffer.append(']'); + buffer.append(lineSeparator); + } else { + lineCapacityAcquired = renderCause( + buffer, + throwable.getCause(), + context, + visitedThrowables, + prefix, + lineSeparator, + lineCapacityAcquired); + if (!lineCapacityAcquired) { + acquireLineCapacity(context); + } + renderThrowableMessage(buffer, throwable); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); + renderSuppressed( + buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); } - renderThrowableMessage(buffer, throwable); - buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); - renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); } + /** + * @return {@code true}, if line capacity is acquired; {@code false}, otherwise + */ private boolean renderCause( final StringBuilder buffer, @Nullable final Throwable cause, diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java index e39997ff449..0470ac7337c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java @@ -85,18 +85,23 @@ private void renderThrowable( final String prefix, final String lineSeparator, final String caption) { - if (visitedThrowables.contains(throwable)) { - return; - } acquireLineCapacity(context); - visitedThrowables.add(throwable); + final boolean circular = !visitedThrowables.add(throwable); buffer.append(prefix); buffer.append(caption); - renderThrowableMessage(buffer, throwable); - buffer.append(lineSeparator); - renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); - renderSuppressed(buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); - renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); + if (circular) { + buffer.append("[CIRCULAR REFERENCE: "); + renderThrowableMessage(buffer, throwable); + buffer.append(']'); + buffer.append(lineSeparator); + } else { + renderThrowableMessage(buffer, throwable); + buffer.append(lineSeparator); + renderStackTraceElements(buffer, throwable, context, prefix, lineSeparator); + renderSuppressed( + buffer, throwable.getSuppressed(), context, visitedThrowables, prefix + '\t', lineSeparator); + renderCause(buffer, throwable.getCause(), context, visitedThrowables, prefix, lineSeparator); + } } void acquireLineCapacity(final C context) { From e52fe1f3f78cd432c2415e72cce0a08c4bdc2ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 27 Sep 2024 12:56:17 +0200 Subject: [PATCH 65/72] Fix newline handling in tests --- .../log4j/core/pattern/ThrowablePatternConverterTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 61eb8dbc5f1..47f21f875b3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -231,10 +231,11 @@ private String limitLines(final String text, final int maxLineCount) { int startIndex = 0; int newlineIndex; while (lineCount < maxLineCount && (newlineIndex = text.indexOf(NEWLINE, startIndex)) != -1) { - final String line = text.substring(startIndex, newlineIndex + NEWLINE.length()); + final int endIndex = newlineIndex + NEWLINE.length(); + final String line = text.substring(startIndex, endIndex); buffer.append(line); lineCount++; - startIndex = newlineIndex + 1; + startIndex = endIndex; } return buffer.toString(); } From 7719098732c31517c6f5a05d5e552067efee87a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 27 Sep 2024 12:58:49 +0200 Subject: [PATCH 66/72] Improve changelog --- .../.2.x.x/2691_change_PatternLayout_exception_rendering.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml b/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml index 74d9671bcdb..6d5d90c0eea 100644 --- a/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml +++ b/src/changelog/.2.x.x/2691_change_PatternLayout_exception_rendering.xml @@ -4,5 +4,5 @@ xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="changed"> - Consolidate exception rendering in Pattern Layout + Consolidate exception rendering logic and improve circular reference support in Pattern Layout From f3e89d39f24936bcf0a410a423c878cf0d6796a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Sun, 29 Sep 2024 21:32:29 +0200 Subject: [PATCH 67/72] Remove redundant `toString()` calls --- .../log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java | 2 +- .../logging/log4j/core/pattern/ThrowableStackTraceRenderer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java index 0b17d0e224f..01d804a3da6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableExtendedStackTraceRenderer.java @@ -69,7 +69,7 @@ void renderStackTraceElement( acquireLineCapacity(context); buffer.append(prefix); buffer.append("\tat "); - buffer.append(stackTraceElement.toString()); + buffer.append(stackTraceElement); final ClassResourceInfo classResourceInfo = context.classResourceInfoByName.get(stackTraceElement.getClassName()); if (classResourceInfo != null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java index 0470ac7337c..b16e9b98362 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowableStackTraceRenderer.java @@ -195,7 +195,7 @@ void renderStackTraceElement( acquireLineCapacity(context); buffer.append(prefix); buffer.append("\tat "); - buffer.append(stackTraceElement.toString()); + buffer.append(stackTraceElement); buffer.append(lineSeparator); } From b7882066bbca1c29a5fe814e3854b62d114cbcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 30 Sep 2024 10:28:59 +0200 Subject: [PATCH 68/72] Test module name serialization (LOG4J2-2170) --- .../test/java/foo/TestFriendlyException.java | 115 +++++++++++++----- ...ExtendedThrowablePatternConverterTest.java | 4 + .../RootThrowablePatternConverterTest.java | 4 + .../ThrowablePatternConverterTest.java | 3 + 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/log4j-core-test/src/test/java/foo/TestFriendlyException.java b/log4j-core-test/src/test/java/foo/TestFriendlyException.java index 20d6b969354..4ce0c7d5a06 100644 --- a/log4j-core-test/src/test/java/foo/TestFriendlyException.java +++ b/log4j-core-test/src/test/java/foo/TestFriendlyException.java @@ -18,7 +18,10 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.net.Socket; import java.util.Arrays; +import java.util.stream.Stream; +import org.apache.logging.log4j.util.Constants; /** * A testing friendly exception featuring @@ -27,33 +30,64 @@ *
  • Non-Log4j package origin1
  • *
  • Sufficient causal chain depth
  • *
  • Cyclic causal chain
  • - *
  • Decorated with suppressed exceptions
  • - *
  • A stack trace free of clutter (i.e., elements from JUnit, JDK, etc.)
  • + *
  • Suppressed exceptions
  • + *
  • Clutter-free stack trace (i.e., elements from JUnit, JDK, etc.)
  • + *
  • Stack trace elements from named modules2
  • * *

    - * 1 This becomes handy for tests observing stack trace manipulation effects of Log4j. + * 1 Helps with observing stack trace manipulation effects of Log4j. + *

    + *

    + * 2 Helps with testing module name serialization. *

    */ public final class TestFriendlyException extends RuntimeException { - private static final String[] EXCLUDED_CLASS_NAME_PREFIXES = { - "java.lang", "jdk.internal", "org.junit", "sun.reflect" - }; - - public static final TestFriendlyException INSTANCE = create("r", 0, 2, new boolean[] {false}); - static { // Ensure the distinct packaging assertThat(TestFriendlyException.class.getPackage().getName()).doesNotStartWith("org.apache"); } + public static final StackTraceElement NAMED_MODULE_STACK_TRACE_ELEMENT = namedModuleStackTraceElement(); + + @SuppressWarnings("resource") + private static StackTraceElement namedModuleStackTraceElement() { + try { + new Socket("0.0.0.0", -1); + } catch (final Exception error) { + final StackTraceElement[] stackTraceElements = error.getStackTrace(); + final String socketClassName = Socket.class.getCanonicalName(); + for (final StackTraceElement stackTraceElement : stackTraceElements) { + if (stackTraceElement.getClassName().equals(socketClassName)) { + if (Constants.JAVA_MAJOR_VERSION > 8) { + final String stackTraceElementString = stackTraceElement.toString(); + assertThat(stackTraceElementString).startsWith("java.base/"); + } + return stackTraceElement; + } + } + } + throw new IllegalStateException("should not have reached here"); + } + + private static final String[] EXCLUDED_CLASS_NAME_PREFIXES = { + "java.lang", "jdk.internal", "org.junit", "sun.reflect" + }; + + public static final TestFriendlyException INSTANCE = create("r", 0, 2, new boolean[] {false}, new boolean[] {true}); + private static TestFriendlyException create( - final String name, final int depth, final int maxDepth, final boolean[] circular) { - final TestFriendlyException error = new TestFriendlyException(name); + final String name, + final int depth, + final int maxDepth, + final boolean[] circular, + final boolean[] namedModuleAllowed) { + final TestFriendlyException error = new TestFriendlyException(name, namedModuleAllowed); if (depth < maxDepth) { - final TestFriendlyException cause = create(name + "_c", depth + 1, maxDepth, circular); + final TestFriendlyException cause = create(name + "_c", depth + 1, maxDepth, circular, namedModuleAllowed); error.initCause(cause); - final TestFriendlyException suppressed = create(name + "_s", depth + 1, maxDepth, circular); + final TestFriendlyException suppressed = + create(name + "_s", depth + 1, maxDepth, circular, namedModuleAllowed); error.addSuppressed(suppressed); final boolean circularAllowed = depth + 1 == maxDepth && !circular[0]; if (circularAllowed) { @@ -65,32 +99,55 @@ private static TestFriendlyException create( return error; } - private TestFriendlyException(final String message) { + private TestFriendlyException(final String message, final boolean[] namedModuleAllowed) { super(message); - removeExcludedStackTraceElements(); + removeExcludedStackTraceElements(namedModuleAllowed); } - private void removeExcludedStackTraceElements() { + private void removeExcludedStackTraceElements(final boolean[] namedModuleAllowed) { final StackTraceElement[] oldStackTrace = getStackTrace(); final boolean[] seenExcludedStackTraceElement = {false}; final StackTraceElement[] newStackTrace = Arrays.stream(oldStackTrace) - .filter(stackTraceElement -> { - if (seenExcludedStackTraceElement[0]) { - return false; - } - final String className = stackTraceElement.getClassName(); - for (final String excludedClassNamePrefix : EXCLUDED_CLASS_NAME_PREFIXES) { - if (className.startsWith(excludedClassNamePrefix)) { - seenExcludedStackTraceElement[0] = true; - return false; - } - } - return true; - }) + .flatMap(stackTraceElement -> + mapStackTraceElement(stackTraceElement, namedModuleAllowed, seenExcludedStackTraceElement)) .toArray(StackTraceElement[]::new); setStackTrace(newStackTrace); } + private static Stream mapStackTraceElement( + final StackTraceElement stackTraceElement, + final boolean[] namedModuleAllowed, + final boolean[] seenExcludedStackTraceElement) { + final Stream filteredStackTraceElement = + filterStackTraceElement(stackTraceElement, seenExcludedStackTraceElement); + final Stream javaBaseIncludedStackTraceElement = + namedModuleIncludedStackTraceElement(namedModuleAllowed); + return Stream.concat(javaBaseIncludedStackTraceElement, filteredStackTraceElement); + } + + private static Stream filterStackTraceElement( + final StackTraceElement stackTraceElement, final boolean[] seenExcludedStackTraceElement) { + if (seenExcludedStackTraceElement[0]) { + return Stream.empty(); + } + final String className = stackTraceElement.getClassName(); + for (final String excludedClassNamePrefix : EXCLUDED_CLASS_NAME_PREFIXES) { + if (className.startsWith(excludedClassNamePrefix)) { + seenExcludedStackTraceElement[0] = true; + return Stream.empty(); + } + } + return Stream.of(stackTraceElement); + } + + private static Stream namedModuleIncludedStackTraceElement(final boolean[] namedModuleAllowed) { + if (!namedModuleAllowed[0]) { + return Stream.of(); + } + namedModuleAllowed[0] = false; + return Stream.of(NAMED_MODULE_STACK_TRACE_ELEMENT); + } + @Override public String getLocalizedMessage() { return getMessage() + " [localized]"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java index 8262bd39a16..b1418c62e44 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java @@ -18,6 +18,7 @@ import static java.util.Arrays.asList; +import foo.TestFriendlyException; import java.util.List; import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractPropertyTest; import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractStackTraceTest; @@ -41,6 +42,7 @@ class PropertyTest extends AbstractPropertyTest { private static final List EXPECTED_FULL_STACK_TRACE_LINES = asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT + " ~[?:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.(TestFriendlyException.java:0) ~[test-classes/:?]", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0) [test-classes/:?]", @@ -105,6 +107,7 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe pattern, asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT + " ~[?:?]", " ... suppressed 2 lines", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0) [test-classes/:?]", " Suppressed: foo.TestFriendlyException: r_s [localized]", @@ -140,6 +143,7 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe pattern, asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT + " ~[?:?]", " at foo.TestFriendlyException.create(TestFriendlyException.java:0) ~[test-classes/:?]", " at foo.TestFriendlyException.(TestFriendlyException.java:0) ~[test-classes/:?]", " ...", diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java index af50d005fff..b02618aff4b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java @@ -18,6 +18,7 @@ import static java.util.Arrays.asList; +import foo.TestFriendlyException; import java.util.List; import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractPropertyTest; import org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.AbstractStackTraceTest; @@ -55,6 +56,7 @@ class PropertyTest extends AbstractPropertyTest { " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", "Wrapped by: foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.(TestFriendlyException.java:0)", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", @@ -116,6 +118,7 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe " ... suppressed 2 lines", " ... 3 more", "Wrapped by: foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " ... suppressed 2 lines", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", " Suppressed: foo.TestFriendlyException: r_s_c [localized]", @@ -154,6 +157,7 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " ... 3 more", "Wrapped by: foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.(TestFriendlyException.java:0)", " ...", diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 47f21f875b3..0118d2b9d4c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -263,6 +263,7 @@ void depth_limited_output_should_match(final DepthTestCase depthTestCase) { pattern, asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.(TestFriendlyException.java:0)", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", @@ -305,6 +306,7 @@ void depth_and_package_limited_output_should_match_1(final DepthTestCase depthTe pattern, asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " ... suppressed 2 lines", " at org.apache.logging.log4j.core.pattern.ThrowablePatternConverterTest.(ThrowablePatternConverterTest.java:0)", " Suppressed: foo.TestFriendlyException: r_s [localized]", @@ -340,6 +342,7 @@ void depth_and_package_limited_output_should_match_2(final DepthTestCase depthTe pattern, asList( "foo.TestFriendlyException: r [localized]", + " at " + TestFriendlyException.NAMED_MODULE_STACK_TRACE_ELEMENT, " at foo.TestFriendlyException.create(TestFriendlyException.java:0)", " at foo.TestFriendlyException.(TestFriendlyException.java:0)", " ...", From d853ec05fc0c18243b725bf25d524edbaaeef0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 30 Sep 2024 10:30:17 +0200 Subject: [PATCH 69/72] Update changelog (LOG4J2-2170) --- .../.2.x.x/2691_fix_PatternLayout_exception_rendering.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml b/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml index 937bbb61c21..a3b27c26c35 100644 --- a/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml +++ b/src/changelog/.2.x.x/2691_fix_PatternLayout_exception_rendering.xml @@ -3,6 +3,7 @@ xmlns="https://logging.apache.org/xml/ns" xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="fixed"> + From a419ea8974d0c5025595edf50dbc86af965cc4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 30 Sep 2024 11:42:28 +0200 Subject: [PATCH 70/72] Normalize extended stack trace suffixes --- .../core/pattern/ThrowablePatternConverterTest.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index 0118d2b9d4c..c886def43ce 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -409,15 +409,20 @@ void assertStackTraceLines( .limit(maxLineCount) .map(expectedStackTraceLine -> expectedStackTraceLine + conversionEnding) .collect(Collectors.joining()); - final String truncatedActualStackTrace = truncateStackTraceLineNumbers(actualStackTrace); - final String truncatedExpectedStackTrace = truncateStackTraceLineNumbers(expectedStackTrace); + final String truncatedActualStackTrace = normalizeStackTrace(actualStackTrace, conversionEnding); + final String truncatedExpectedStackTrace = normalizeStackTrace(expectedStackTrace, conversionEnding); assertThat(truncatedActualStackTrace) .as("depthTestCase=%s, pattern=`%s`", depthTestCase, pattern) .isEqualTo(truncatedExpectedStackTrace); } - private static String truncateStackTraceLineNumbers(final String stackTrace) { - return stackTrace.replaceAll("\\.java:[0-9]+\\)", ".java:0)"); + private static String normalizeStackTrace(final String stackTrace, final String conversionEnding) { + return stackTrace + // Normalize line numbers + .replaceAll("\\.java:[0-9]+\\)", ".java:0)") + // Normalize extended stack trace resource information for Java Standard library classes. + // We replace the `~[?:1.8.0_422]` suffix of such classes with `~[?:0]`. + .replaceAll(" ~\\[\\?:[^]]+](\\Q" + conversionEnding + "\\E|$)", " ~[?:0]$1"); } } From beede50bcf252310c4b7f30800ba233a90aa0575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 1 Oct 2024 13:10:30 +0200 Subject: [PATCH 71/72] Add `ThrowVsReturnBenchmark` --- .../logging/log4j/ThrowVsReturnBenchmark.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java diff --git a/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java b/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java new file mode 100644 index 00000000000..b2d6cf22502 --- /dev/null +++ b/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java @@ -0,0 +1,79 @@ +/* + * 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.apache.logging.log4j; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +public class ThrowVsReturnBenchmark { + + private static final int SALT = ThreadLocalRandom.current().nextInt(); + + private static final RuntimeException EXCEPTION = new RuntimeException(); + + private static final int MAX_DEPTH = 5; + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public int withReturn(final Blackhole blackhole) { + return withReturn(blackhole, 0); + } + + private static int withReturn(final Blackhole blackhole, final int depth) { + doWork(blackhole); + return depth < MAX_DEPTH ? withReturn(blackhole, depth + 1) : blackhole.i1; + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public int withThrow(final Blackhole blackhole) { + try { + withThrow(blackhole, 0); + } catch (final Exception error) { + if (error == EXCEPTION) { + return blackhole.i1; + } + } + throw new IllegalStateException(); + } + + private static void withThrow(final Blackhole blackhole, final int depth) { + doWork(blackhole); + if (depth < MAX_DEPTH) { + withThrow(blackhole, depth + 1); + } else { + throw EXCEPTION; + } + } + + private static void doWork(final Blackhole blackhole) { + for (int i = 0; i < 1_000; i++) { + blackhole.consume((i << 10) + SALT); + } + } +} From 663a9e7dd1d296c2b81071afb0286340192e0e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Tue, 1 Oct 2024 21:31:28 +0200 Subject: [PATCH 72/72] Fix Spotless failures --- .../org/apache/logging/log4j/ThrowVsReturnBenchmark.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java b/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java index b2d6cf22502..1c1d59b1ba7 100644 --- a/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java +++ b/log4j-perf-test/src/main/java/org/apache/logging/log4j/ThrowVsReturnBenchmark.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -24,9 +26,6 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class ThrowVsReturnBenchmark {