This is an automated email from the ASF dual-hosted git repository. vy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/main by this push: new f04667fda8 LOG4J2-3660 Fix `%notEmpty` for empty MDC/NDC inputs f04667fda8 is described below commit f04667fda86804c882dc3cfab4604f5526a0400b Author: Volkan Yazıcı <vol...@yazi.ci> AuthorDate: Sun Apr 23 21:28:04 2023 +0200 LOG4J2-3660 Fix `%notEmpty` for empty MDC/NDC inputs --- .../VariablesNotEmptyReplacementConverterTest.java | 16 +++++++++++ .../core/pattern/LogEventPatternConverter.java | 8 ++++++ .../log4j/core/pattern/MdcPatternConverter.java | 9 ++++--- .../log4j/core/pattern/NdcPatternConverter.java | 6 +++++ .../VariablesNotEmptyReplacementConverter.java | 31 ++++++++++++++++++++-- 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java index 34a8a137f2..580e994167 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java @@ -58,6 +58,21 @@ public class VariablesNotEmptyReplacementConverterTest { testReplacement("%logger", "[" + VariablesNotEmptyReplacementConverterTest.class.getName() + "]"); } + @Test + void empty_NDC_should_be_replaced() { + testReplacement("%NDC", ""); + } + + @Test + void empty_MDC_should_be_replaced() { + testReplacement("%mdc", ""); + } + + @Test + void MDC_with_non_existent_keys_should_be_replaced() { + testReplacement("%mdc{noSuchKey1,noSuchKey2}", ""); + } + private void testReplacement(final String tag, final String expectedValue) { final LogEvent event = Log4jLogEvent.newBuilder() // .setLoggerName(VariablesNotEmptyReplacementConverterTest.class.getName()) // @@ -73,4 +88,5 @@ public class VariablesNotEmptyReplacementConverterTest { converter.format(event, sb); assertEquals(expectedValue, sb.toString()); } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java index 2ff42974fe..2958e4bef2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java @@ -77,4 +77,12 @@ public abstract class LogEventPatternConverter extends AbstractPatternConverter public boolean isVariable() { return true; } + + /** + * @return the formatted output when the input variable (MDC, NDC, etc.) is empty + */ + public String emptyVariableOutput() { + return ""; + } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java index 9649886607..7c1ff18031 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.core.pattern; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.plugins.Namespace; -import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.util.PerformanceSensitive; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringBuilders; @@ -147,4 +144,10 @@ public final class MdcPatternConverter extends LogEventPatternConverter { } sb.append('}'); } + + @Override + public String emptyVariableOutput() { + return "{}"; + } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NdcPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NdcPatternConverter.java index 31deeb1252..9f351036c4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NdcPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NdcPatternConverter.java @@ -57,4 +57,10 @@ public final class NdcPatternConverter extends LogEventPatternConverter { public void format(final LogEvent event, final StringBuilder toAppendTo) { toAppendTo.append(event.getContextStack()); } + + @Override + public String emptyVariableOutput() { + return "[]"; + } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java index c513ff5cd0..0391ec67be 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java @@ -83,13 +83,40 @@ public final class VariablesNotEmptyReplacementConverter extends LogEventPattern final PatternFormatter formatter = formatters.get(i); final int formatterStart = toAppendTo.length(); formatter.format(event, toAppendTo); - if (formatter.getConverter().isVariable()) { + LogEventPatternConverter converter = formatter.getConverter(); + if (converter.isVariable()) { hasVars = true; - allVarsEmpty = allVarsEmpty && (toAppendTo.length() == formatterStart); + allVarsEmpty = allVarsEmpty && sequenceRegionMatches(toAppendTo, formatterStart, converter.emptyVariableOutput()); } } if (!hasVars || allVarsEmpty) { toAppendTo.setLength(start); // remove formatter results } } + + /** + * @param sequence1 the 1st sequence + * @param sequence1Offset the start index of the 1st sequence region + * @param sequence2 the 2nd sequence + * @return {@code true}, if the pointed region of the 1st sequence matches to the 2nd sequence; {@code false}, otherwise + */ + private static boolean sequenceRegionMatches( + final CharSequence sequence1, + final int sequence1Offset, + final CharSequence sequence2) { + final boolean lengthMatches = (sequence1.length() - sequence1Offset) == sequence2.length(); + if (!lengthMatches) { + return false; + } + for (int i2 = 0; i2 < sequence2.length(); i2++) { + final char c2 = sequence2.charAt(i2); + final int i1 = i2 + sequence1Offset; + final char c1 = sequence1.charAt(i1); + if (c2 != c1) { + return false; + } + } + return true; + } + }