Skip to content

Commit 7d7c559

Browse files
committed
fix: LOG4J2-3627 and gh issue 1729
1 parent 204d825 commit 7d7c559

File tree

6 files changed

+156
-53
lines changed

6 files changed

+156
-53
lines changed

log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public void test_formatExtendedStackTraceTo() {
3333
new ArrayList<>(),
3434
new PlainTextRenderer(),
3535
"",
36-
System.lineSeparator());
36+
System.lineSeparator(),
37+
null);
3738
}
3839
}

log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public ThrowableProxy getCauseProxy() {
255255
* @param suffix Append this to the end of each stack frame.
256256
*/
257257
public String getCauseStackTraceAsString(final String suffix) {
258-
return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR);
258+
return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR, null);
259259
}
260260

261261
/**
@@ -266,7 +266,7 @@ public String getCauseStackTraceAsString(final String suffix) {
266266
* @return The formatted Throwable that caused this Throwable.
267267
*/
268268
public String getCauseStackTraceAsString(final List<String> packages, final String suffix) {
269-
return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR);
269+
return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR, null);
270270
}
271271

272272
/**
@@ -279,7 +279,7 @@ public String getCauseStackTraceAsString(final List<String> packages, final Stri
279279
*/
280280
public String getCauseStackTraceAsString(
281281
final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix) {
282-
return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR);
282+
return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR, null);
283283
}
284284

285285
/**
@@ -295,12 +295,35 @@ public String getCauseStackTraceAsString(
295295
final List<String> ignorePackages,
296296
final TextRenderer textRenderer,
297297
final String suffix,
298-
final String lineSeparator) {
298+
final String lineSeparator,
299+
final Integer linesToKeep) {
299300
final StringBuilder sb = new StringBuilder();
300-
ThrowableProxyRenderer.formatCauseStackTrace(this, sb, ignorePackages, textRenderer, suffix, lineSeparator);
301+
ThrowableProxyRenderer.formatCauseStackTraceTo(
302+
this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep);
301303
return sb.toString();
302304
}
303305

306+
/**
307+
* Formats the stack trace with cause exception.
308+
*
309+
* @param sb Destination.
310+
* @param ignorePackages List of packages to be ignored in the trace.
311+
* @param textRenderer The message renderer.
312+
* @param suffix Append this to the end of each stack frame.
313+
* @param lineSeparator The end-of-line separator.
314+
* @param linesToKeep The total line count of final result
315+
*/
316+
public void formatCauseStackTraceTo(
317+
final StringBuilder sb,
318+
final List<String> ignorePackages,
319+
final TextRenderer textRenderer,
320+
final String suffix,
321+
final String lineSeparator,
322+
final Integer linesToKeep) {
323+
ThrowableProxyRenderer.formatCauseStackTraceTo(
324+
this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep);
325+
}
326+
304327
/**
305328
* Returns the number of elements that are being omitted because they are common with the parent Throwable's stack
306329
* trace.
@@ -389,7 +412,7 @@ public String getExtendedStackTraceAsString(
389412
final String suffix,
390413
final String lineSeparator) {
391414
final StringBuilder sb = new StringBuilder(1024);
392-
formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator);
415+
formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator, null);
393416
return sb.toString();
394417
}
395418

@@ -401,15 +424,17 @@ public String getExtendedStackTraceAsString(
401424
* @param textRenderer The message renderer.
402425
* @param suffix Append this to the end of each stack frame.
403426
* @param lineSeparator The end-of-line separator.
427+
* @param linesToKeep The total line count of final result
404428
*/
405429
public void formatExtendedStackTraceTo(
406430
final StringBuilder sb,
407431
final List<String> ignorePackages,
408432
final TextRenderer textRenderer,
409433
final String suffix,
410-
final String lineSeparator) {
434+
final String lineSeparator,
435+
final Integer linesToKeep) {
411436
ThrowableProxyRenderer.formatExtendedStackTraceTo(
412-
this, sb, ignorePackages, textRenderer, suffix, lineSeparator);
437+
this, sb, ignorePackages, textRenderer, suffix, lineSeparator, linesToKeep);
413438
}
414439

415440
public String getLocalizedMessage() {

log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,9 @@ static void formatExtendedStackTraceTo(
240240
final List<String> ignorePackages,
241241
final TextRenderer textRenderer,
242242
final String suffix,
243-
final String lineSeparator) {
244-
textRenderer.render(src.getName(), sb, "Name");
245-
textRenderer.render(": ", sb, "NameMessageSeparator");
246-
textRenderer.render(src.getMessage(), sb, "Message");
243+
final String lineSeparator,
244+
final Integer linesToKeep) {
245+
renderOn(src, sb, textRenderer);
247246
renderSuffix(suffix, sb, textRenderer);
248247
textRenderer.render(lineSeparator, sb, "Text");
249248
final StackTraceElement[] causedTrace =
@@ -260,6 +259,7 @@ static void formatExtendedStackTraceTo(
260259
lineSeparator);
261260
formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator);
262261
formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator);
262+
truncateLines(sb, lineSeparator, linesToKeep, textRenderer);
263263
}
264264

265265
/**
@@ -272,23 +272,24 @@ static void formatExtendedStackTraceTo(
272272
* @param suffix Append this to the end of each stack frame.
273273
* @param lineSeparator The end-of-line separator.
274274
*/
275-
static void formatCauseStackTrace(
275+
static void formatCauseStackTraceTo(
276276
final ThrowableProxy src,
277277
final StringBuilder sb,
278278
final List<String> ignorePackages,
279279
final TextRenderer textRenderer,
280280
final String suffix,
281-
final String lineSeparator) {
281+
final String lineSeparator,
282+
final Integer linesToKeep) {
282283
final ThrowableProxy causeProxy = src.getCauseProxy();
283284
if (causeProxy != null) {
284285
formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator);
285286
sb.append(WRAPPED_BY_LABEL);
286-
ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer);
287+
renderSuffix(suffix, sb, textRenderer);
287288
}
288289
renderOn(src, sb, textRenderer);
289-
ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer);
290+
renderSuffix(suffix, sb, textRenderer);
290291
textRenderer.render(lineSeparator, sb, "Text");
291-
ThrowableProxyRenderer.formatElements(
292+
formatElements(
292293
sb,
293294
Strings.EMPTY,
294295
0,
@@ -298,6 +299,7 @@ static void formatCauseStackTrace(
298299
textRenderer,
299300
suffix,
300301
lineSeparator);
302+
truncateLines(sb, lineSeparator, linesToKeep, textRenderer);
301303
}
302304

303305
private static void renderOn(
@@ -309,4 +311,24 @@ private static void renderOn(
309311
textRenderer.render(msg, output, "Message");
310312
}
311313
}
314+
315+
private static void truncateLines(
316+
StringBuilder sb, String lineSeparator, Integer linesToKeep, TextRenderer textRenderer) {
317+
if (linesToKeep == null) {
318+
return;
319+
}
320+
321+
String content = sb.toString();
322+
String[] lines = content.split(lineSeparator);
323+
324+
if (lines.length <= linesToKeep) {
325+
return;
326+
}
327+
328+
sb.setLength(0);
329+
for (int i = 0; i < linesToKeep; i++) {
330+
sb.append(lines[i]);
331+
textRenderer.render(lineSeparator, sb, "Text");
332+
}
333+
}
312334
}

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ public void format(final LogEvent event, final StringBuilder toAppendTo) {
7676
options.getIgnorePackages(),
7777
options.getTextRenderer(),
7878
getSuffix(event),
79-
options.getSeparator());
79+
options.getSeparator(),
80+
options.allLines() ? null : options.getLines());
8081
}
8182
}
8283
}

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.apache.logging.log4j.core.config.Configuration;
2121
import org.apache.logging.log4j.core.config.plugins.Plugin;
2222
import org.apache.logging.log4j.core.impl.ThrowableProxy;
23-
import org.apache.logging.log4j.util.Strings;
2423

2524
/**
2625
* 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) {
6867
super.format(event, toAppendTo);
6968
return;
7069
}
71-
final String trace = proxy.getCauseStackTraceAsString(
72-
options.getIgnorePackages(), options.getTextRenderer(), getSuffix(event), options.getSeparator());
7370
final int len = toAppendTo.length();
7471
if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) {
7572
toAppendTo.append(' ');
7673
}
77-
if (!options.allLines() || !Strings.LINE_SEPARATOR.equals(options.getSeparator())) {
78-
final StringBuilder sb = new StringBuilder();
79-
final String[] array = trace.split(Strings.LINE_SEPARATOR);
80-
final int limit = options.minLines(array.length) - 1;
81-
for (int i = 0; i <= limit; ++i) {
82-
sb.append(array[i]);
83-
if (i < limit) {
84-
sb.append(options.getSeparator());
85-
}
86-
}
87-
toAppendTo.append(sb.toString());
88-
89-
} else {
90-
toAppendTo.append(trace);
91-
}
74+
proxy.formatCauseStackTraceTo(
75+
toAppendTo,
76+
options.getIgnorePackages(),
77+
options.getTextRenderer(),
78+
getSuffix(event),
79+
options.getSeparator(),
80+
options.allLines() ? null : options.getLines());
9281
}
9382
}
9483
}

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2020
import java.io.PrintWriter;
21-
import java.io.StringWriter;
2221
import java.util.ArrayList;
2322
import java.util.Collections;
2423
import java.util.List;
@@ -188,23 +187,24 @@ private void formatOption(final Throwable throwable, final String suffix, final
188187
if (len > 0 && !Character.isWhitespace(buffer.charAt(len - 1))) {
189188
buffer.append(' ');
190189
}
191-
if (!options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix)) {
192-
final StringWriter w = new StringWriter();
193-
throwable.printStackTrace(new PrintWriter(w));
194-
195-
final String[] array = w.toString().split(Strings.LINE_SEPARATOR);
196-
final int limit = options.minLines(array.length) - 1;
197-
final boolean suffixNotBlank = Strings.isNotBlank(suffix);
198-
for (int i = 0; i <= limit; ++i) {
199-
buffer.append(array[i]);
200-
if (suffixNotBlank) {
201-
buffer.append(' ');
202-
buffer.append(suffix);
203-
}
204-
if (i < limit) {
205-
buffer.append(options.getSeparator());
190+
if (requireAdditionalFormatting(suffix)) {
191+
StackTraceElement[] stackTrace = throwable.getStackTrace();
192+
int ignoredCount = 0;
193+
for (StackTraceElement stackTraceElement : stackTrace) {
194+
if (!ignoreElement(stackTraceElement, options.getIgnorePackages())) {
195+
if (ignoredCount > 0) {
196+
appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator());
197+
ignoredCount = 0;
198+
}
199+
appendEntry(stackTraceElement, buffer, suffix, options.getSeparator());
200+
} else {
201+
++ignoredCount;
206202
}
207203
}
204+
if (ignoredCount > 0) {
205+
appendSuppressedCount(buffer, ignoredCount, suffix, options.getSeparator());
206+
}
207+
truncateLines(buffer, options.getSeparator(), options.allLines() ? null : options.getLines());
208208
} else {
209209
throwable.printStackTrace(new PrintWriter(new StringBuilderWriter(buffer)));
210210
}
@@ -235,4 +235,69 @@ protected String getSuffix(final LogEvent event) {
235235
public ThrowableFormatOptions getOptions() {
236236
return options;
237237
}
238+
239+
private boolean requireAdditionalFormatting(String suffix) {
240+
return !options.allLines() || nonStandardLineSeparator || Strings.isNotBlank(suffix) || options.hasPackages();
241+
}
242+
243+
private boolean ignoreElement(final StackTraceElement element, final List<String> ignorePackages) {
244+
if (ignorePackages != null) {
245+
final String className = element.getClassName();
246+
for (final String pkg : ignorePackages) {
247+
if (className.startsWith(pkg)) {
248+
return true;
249+
}
250+
}
251+
}
252+
return false;
253+
}
254+
255+
private void appendSuppressedCount(
256+
final StringBuilder sb, final int count, final String suffix, final String lineSeparator) {
257+
if (count == 1) {
258+
sb.append("\t... ");
259+
} else {
260+
sb.append("\t... suppressed ");
261+
sb.append(count);
262+
sb.append(" lines");
263+
}
264+
appendSuffix(sb, suffix);
265+
sb.append(lineSeparator);
266+
}
267+
268+
private void appendEntry(
269+
final StackTraceElement stackTraceElement,
270+
final StringBuilder sb,
271+
final String suffix,
272+
final String lineSeparator) {
273+
sb.append(stackTraceElement.toString());
274+
appendSuffix(sb, suffix);
275+
sb.append(lineSeparator);
276+
}
277+
278+
private void appendSuffix(StringBuilder buffer, String suffix) {
279+
if (Strings.isNotBlank(suffix)) {
280+
buffer.append(' ');
281+
buffer.append(suffix);
282+
}
283+
}
284+
285+
private void truncateLines(StringBuilder sb, String lineSeparator, Integer linesToKeep) {
286+
if (linesToKeep == null) {
287+
return;
288+
}
289+
290+
String content = sb.toString();
291+
String[] lines = content.split(lineSeparator);
292+
293+
if (lines.length <= linesToKeep) {
294+
return;
295+
}
296+
297+
sb.setLength(0);
298+
for (int i = 0; i < linesToKeep; i++) {
299+
sb.append(lines[i]);
300+
sb.append(lineSeparator);
301+
}
302+
}
238303
}

0 commit comments

Comments
 (0)