|
16 | 16 | */ |
17 | 17 | package org.apache.logging.log4j.layout.template.json.resolver; |
18 | 18 |
|
| 19 | +import static java.util.Collections.singletonList; |
19 | 20 | import static org.apache.logging.log4j.layout.template.json.TestHelpers.CONFIGURATION; |
20 | 21 | import static org.apache.logging.log4j.layout.template.json.TestHelpers.JAVA_BASE_PREFIX; |
21 | 22 | import static org.apache.logging.log4j.layout.template.json.TestHelpers.asMap; |
|
40 | 41 | import org.apache.logging.log4j.core.impl.Log4jLogEvent; |
41 | 42 | import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; |
42 | 43 | import org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults; |
| 44 | +import org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter; |
43 | 45 | import org.apache.logging.log4j.util.Constants; |
44 | 46 | import org.assertj.core.api.AbstractStringAssert; |
45 | 47 | import org.junit.jupiter.api.Nested; |
@@ -593,6 +595,67 @@ private String pointMatcherRegex(final Throwable exception) { |
593 | 595 | private String matchingRegex(final String string) { |
594 | 596 | return "[" + string.charAt(0) + "]" + Pattern.quote(string.substring(1)); |
595 | 597 | } |
| 598 | + |
| 599 | + @Test |
| 600 | + void should_not_fail_on_truncated_output_not_ending_with_newline() { |
| 601 | + |
| 602 | + // Try to find an exception whose truncated stack trace does not end with a newline |
| 603 | + final int maxStringLength = 100; |
| 604 | + final float maxByteCountPerChar = |
| 605 | + JsonTemplateLayoutDefaults.getCharset().newEncoder().maxBytesPerChar(); |
| 606 | + final int maxStringByteCount = |
| 607 | + Math.toIntExact(Math.round(Math.ceil(maxByteCountPerChar * maxStringLength))); |
| 608 | + final TruncatingBufferedPrintWriter writer = TruncatingBufferedPrintWriter.ofCapacity(maxStringByteCount); |
| 609 | + Exception exception; |
| 610 | + String message = "m"; |
| 611 | + do { |
| 612 | + exception = new Exception(message); |
| 613 | + exception.printStackTrace(writer); |
| 614 | + if (writer.truncated() && writer.buffer()[writer.length() - 1] != '\n') { |
| 615 | + break; |
| 616 | + } |
| 617 | + writer.close(); |
| 618 | + message += "m"; |
| 619 | + } while (true); |
| 620 | + |
| 621 | + // Create the event template |
| 622 | + final String eventTemplate = writeJson(asMap( |
| 623 | + "ex", |
| 624 | + asMap( |
| 625 | + "$resolver", |
| 626 | + "exception", |
| 627 | + "field", |
| 628 | + "stackTrace", |
| 629 | + "stackTrace", |
| 630 | + asMap( |
| 631 | + "stringified", |
| 632 | + asMap( |
| 633 | + "truncation", |
| 634 | + asMap( |
| 635 | + "suffix", |
| 636 | + TRUNCATION_SUFFIX, |
| 637 | + "pointMatcherStrings", |
| 638 | + singletonList("this string shouldn't match with anything"))))))); |
| 639 | + |
| 640 | + // Create the layout |
| 641 | + final JsonTemplateLayout layout = JsonTemplateLayout.newBuilder() |
| 642 | + .setConfiguration(CONFIGURATION) |
| 643 | + .setEventTemplate(eventTemplate) |
| 644 | + .setMaxStringLength(maxStringLength) |
| 645 | + .setStackTraceEnabled(true) |
| 646 | + .build(); |
| 647 | + |
| 648 | + // Create the log event |
| 649 | + final LogEvent logEvent = |
| 650 | + Log4jLogEvent.newBuilder().setThrown(exception).build(); |
| 651 | + |
| 652 | + // Check the serialized event |
| 653 | + usingSerializedLogEventAccessor(layout, logEvent, accessor -> { |
| 654 | + final int expectedStackTraceLength = maxStringLength + TRUNCATION_SUFFIX.length(); |
| 655 | + final String stackTrace = accessor.getString("ex"); |
| 656 | + assertThat(stackTrace).hasSizeLessThan(expectedStackTraceLength); |
| 657 | + }); |
| 658 | + } |
596 | 659 | } |
597 | 660 |
|
598 | 661 | @Test |
|
0 commit comments