From 36919e2c72cfb88af5aca1ea4fd629b4bf5bac6d Mon Sep 17 00:00:00 2001 From: zsomborklara Date: Thu, 28 Sep 2017 17:28:03 +0200 Subject: [PATCH] LOG4J2-1216: Nested pattern layout options broken --- .../log4j/core/pattern/PatternParser.java | 39 ++++++++----------- .../log4j/core/pattern/PatternParserTest.java | 20 +++++++++- 2 files changed, 36 insertions(+), 23 deletions(-) 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 065ab9ce41a..d788f57f202 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 @@ -271,32 +271,27 @@ private static int extractConverter(final char lastChar, final String pattern, f */ private static int extractOptions(final String pattern, final int start, final List options) { int i = start; - while (i < pattern.length() && pattern.charAt(i) == '{') { - final int begin = i++; - int end; - int depth = 0; - do { - end = pattern.indexOf('}', i); - if (end == -1) { - break; - } - final int next = pattern.indexOf("{", i); - if (next != -1 && next < end) { - i = end + 1; - ++depth; - } else if (depth > 0) { - --depth; + while (i < pattern.length() && pattern.charAt(i) == '{') { + i++; // skip opening "{" + final int begin = i; // position of first real char + int depth = 1; // already inside one level + while (depth > 0 && i < pattern.length()) { + char c = pattern.charAt(i); + if (c == '{') { + depth++; + } else if (c == '}') { + depth--; + // TODO(?) maybe escaping of { and } with \ or % } - } while (depth > 0); + i++; + } // while - if (end == -1) { - break; + if (depth > 0) { // option not closed, continue with pattern after closing bracket + return pattern.indexOf('}', start) + 1; } - final String r = pattern.substring(begin + 1, end); - options.add(r); - i = end + 1; - } + options.add(pattern.substring(begin, i-1)); + } // while return i; } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java index 1e4cd921154..1b68c0da621 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java @@ -54,6 +54,7 @@ public class PatternParserTest { private final String mdcMsgPattern3 = "%m : %X{key2}%n"; private final String mdcMsgPattern4 = "%m : %X{key3}%n"; private final String mdcMsgPattern5 = "%m : %X{key1},%X{key2},%X{key3}%n"; + private final String deeplyNestedPattern = "%notEmpty{ %maxLen{%X{var}}{3} }"; private static String badPattern = "[%d{yyyyMMdd HH:mm:ss,SSS] %-5p [%c{10}] - %m%n"; private static String customPattern = "[%d{yyyyMMdd HH:mm:ss,SSS}] %-5p [%-25.25c{1}:%-4L] - %m%n"; @@ -114,7 +115,7 @@ public void testCustomPattern() { formatter.format(event, buf); } final String str = buf.toString(); - final String expected = "INFO [PatternParserTest :100 ] - Hello, world" + Strings.LINE_SEPARATOR; + final String expected = "INFO [PatternParserTest :101 ] - Hello, world" + Strings.LINE_SEPARATOR; assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected)); } @@ -332,4 +333,21 @@ public void testNanoPatternLongChangesNanoClockFactoryMode() { pp.parse("%N"); assertTrue(config.getNanoClock() instanceof SystemNanoClock); } + + @Test + public void testDeeplyNestedPattern() { + final List formatters = parser.parse(deeplyNestedPattern); + assertNotNull(formatters); + assertEquals(1, formatters.size()); + + final Map mdc = new HashMap<>(); + mdc.put("var", "1234"); + final Log4jLogEvent event = Log4jLogEvent.newBuilder() // + .setContextMap(mdc).build(); + final StringBuilder buf = new StringBuilder(); + formatters.get(0).format(event, buf); + final String expected = " 123 "; + assertEquals(expected, buf.toString()); + + } }