This is an automated email from the ASF dual-hosted git repository. vy pushed a commit to branch 2.x in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/2.x by this push: new 8563ffcdee LOG4J2-3660 Fix `%notEmpty` for empty MDC/NDC inputs 8563ffcdee is described below commit 8563ffcdeee3faddedd6ea6c6ac79400a2d73a40 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 | 12 ++++++--- .../log4j/core/pattern/NdcPatternConverter.java | 6 +++++ .../VariablesNotEmptyReplacementConverter.java | 31 ++++++++++++++++++++-- ...ix_notEmpty_converter_for_empty_collections.xml | 25 +++++++++++++++++ 6 files changed, 93 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 84cee329e1..71db001c2c 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 @@ -68,4 +68,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 451bac7f78..90805ca8be 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,12 +16,12 @@ */ package org.apache.logging.log4j.core.pattern; -import org.apache.logging.log4j.util.PerformanceSensitive; -import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.util.TriConsumer; +import org.apache.logging.log4j.util.PerformanceSensitive; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringBuilders; +import org.apache.logging.log4j.util.TriConsumer; /** * Able to handle the contents of the LogEvent's MDC and either @@ -143,4 +143,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 754ea9a7ad..e4d89e3009 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 @@ -55,4 +55,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 1f0d827479..886fa67b4a 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 @@ -81,13 +81,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; + } + } diff --git a/src/changelog/.2.x.x/LOG4J2-3660_fix_notEmpty_converter_for_empty_collections.xml b/src/changelog/.2.x.x/LOG4J2-3660_fix_notEmpty_converter_for_empty_collections.xml new file mode 100644 index 0000000000..5d5b388978 --- /dev/null +++ b/src/changelog/.2.x.x/LOG4J2-3660_fix_notEmpty_converter_for_empty_collections.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://logging.apache.org/log4j/changelog" + xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.1.xsd" + type="fixed"> + <issue id="LOG4J2-3660" link="https://issues.apache.org/jira/browse/LOG4J2-3660"/> + <author id="vy"/> + <description format="asciidoc">Fix `%notEmpty` directive of `PatternLayout` for empty MDC/NDC inputs</description> +</entry>