This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch 2.25.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/2.25.x by this push:
new 6c8cf594fe Restore support for documented `Rfc5424Layout` attributes
(#4074)
6c8cf594fe is described below
commit 6c8cf594fe853e4cf8d5180d247f8b7bc910696d
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Wed Mar 25 00:56:53 2026 +0100
Restore support for documented `Rfc5424Layout` attributes (#4074)
In `2.21.0`, `Rfc5424Layout` was migrated from a factory method to the
builder pattern. During this change, the recognized names of several
configuration attributes unintentionally diverged from the documented ones.
As a result, some documented attributes were no longer recognized, while
new, undocumented names were introduced.
This change restores support for the documented attribute names while
continuing to accept the names introduced in `2.21.0` for backward
compatibility.
Fixes #4022
Co-authored-by: Volkan Yazıcı <[email protected]>
Co-authored-by: Copilot <[email protected]>
---
.../log4j/core/layout/Rfc5424LayoutTest.java | 133 ++++++++++++++-
.../logging/log4j/core/layout/Rfc5424Layout.java | 187 +++++++++++++++++++--
src/changelog/.2.x.x/4022_rfc5424-param-names.xml | 13 ++
3 files changed, 320 insertions(+), 13 deletions(-)
diff --git
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
index ec83dba175..d4371b90dc 100644
---
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
+++
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
@@ -32,8 +32,10 @@ import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.stream.Stream;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.MarkerManager;
@@ -103,18 +105,29 @@ class Rfc5424LayoutTest {
"[RequestContext@3692 ipAddress=\"192.168.0.120\"
loginId=\"JohnDoe\"]";
private static final String collectionEndOfLine = "Transfer Complete";
+ private static final String NEW_LINE_ESCAPE = "\\n";
+ private static final String INCLUDED_KEYS = "key1, key2, locale";
+ private static final String EXCLUDED_KEYS = "key3, key4";
+
static ConfigurationFactory cf = new BasicConfigurationFactory();
+ private static PluginManager pluginManager;
+
@BeforeAll
static void setupClass() {
StatusLogger.getLogger().setLevel(Level.OFF);
ConfigurationFactory.setConfigurationFactory(cf);
final LoggerContext ctx = LoggerContext.getContext();
ctx.reconfigure();
+
+ pluginManager = new PluginManager(Node.CATEGORY);
+ pluginManager.collectPlugins();
}
@AfterAll
static void cleanupClass() {
+ pluginManager = null;
+
ConfigurationFactory.removeConfigurationFactory(cf);
}
@@ -763,9 +776,7 @@ class Rfc5424LayoutTest {
final Rfc5424Layout layout = new
Rfc5424Layout.Rfc5424LayoutBuilder().build();
checkDefaultValues(layout);
- final PluginManager manager = new PluginManager(Node.CATEGORY);
- manager.collectPlugins();
- final Object obj = new
PluginBuilder(manager.getPluginType("Rfc5424Layout"))
+ final Object obj = new
PluginBuilder(pluginManager.getPluginType("Rfc5424Layout"))
.withConfigurationNode(new Node())
.withConfiguration(new DefaultConfiguration())
.build();
@@ -807,6 +818,122 @@ class Rfc5424LayoutTest {
assertThat(layout.getLocalHostName()).isEqualTo(fqdn);
}
+ private static Map<String, String> attributeMap(String... keyValuePairs) {
+ Map<String, String> result = new HashMap<>();
+ for (int i = 0; i < keyValuePairs.length; i += 2) {
+ result.put(keyValuePairs[i], keyValuePairs[i + 1]);
+ }
+ return result;
+ }
+
+ private static Rfc5424Layout buildRfc5424Layout(Map<String, String>
attributes) {
+ Node node = new Node();
+ node.getAttributes().putAll(attributes);
+
+ Object object = new
PluginBuilder(pluginManager.getPluginType("Rfc5424Layout"))
+ .withConfigurationNode(node)
+ .withConfiguration(new DefaultConfiguration())
+ .build();
+
+ assertThat(object).isInstanceOf(Rfc5424Layout.class);
+ return (Rfc5424Layout) object;
+ }
+
+ private static Stream<Arguments>
testAcceptsDocumentedAttributesAndCompatibilityAliases() {
+ return Stream.of(
+ Arguments.of(
+ "documented attributes",
+ attributeMap(
+ "newLine",
+ "true",
+ "newLineEscape",
+ NEW_LINE_ESCAPE,
+ "useTlsMessageFormat",
+ "true",
+ "mdcRequired",
+ INCLUDED_KEYS)),
+ Arguments.of(
+ "compatibility aliases",
+ attributeMap(
+ "includeNL",
+ "true",
+ "escapeNL",
+ NEW_LINE_ESCAPE,
+ "useTLSMessageFormat",
+ "true",
+ "required",
+ INCLUDED_KEYS)));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testAcceptsDocumentedAttributesAndCompatibilityAliases(
+ String ignoredDisplayName, Map<String, String> attributes) {
+
+ Rfc5424Layout layout = buildRfc5424Layout(attributes);
+
+ assertThat(layout.isIncludeNewLine()).isTrue();
+ // The field contains Matcher.quote() escaped value, so we expect the
backslash to be escaped.
+ assertThat(layout.getEscapeNewLine()).isEqualTo("\\\\n");
+ assertThat(layout.isUseTlsMessageFormat()).isTrue();
+ assertThat(layout.getMdcRequired()).containsExactly("key1", "key2",
"locale");
+ }
+
+ private static Stream<Arguments>
testAcceptsIncludeAttributesAndCompatibilityAliases() {
+ return Stream.of(
+ Arguments.of("documented attributes",
attributeMap("mdcIncludes", INCLUDED_KEYS)),
+ Arguments.of("compatibility aliases", attributeMap("includes",
INCLUDED_KEYS)));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testAcceptsIncludeAttributesAndCompatibilityAliases(
+ String ignoredDisplayName, Map<String, String> attributes) {
+
+ Rfc5424Layout layout = buildRfc5424Layout(attributes);
+
+ assertThat(layout.getMdcIncludes()).containsExactly("key1", "key2",
"locale");
+ assertThat(layout.getMdcExcludes()).isNullOrEmpty();
+ }
+
+ private static Stream<Arguments>
testAcceptsExcludeAttributesAndCompatibilityAliases() {
+ return Stream.of(
+ Arguments.of("documented attributes",
attributeMap("mdcExcludes", EXCLUDED_KEYS)),
+ Arguments.of("compatibility aliases", attributeMap("excludes",
EXCLUDED_KEYS)));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testAcceptsExcludeAttributesAndCompatibilityAliases(
+ String ignoredDisplayName, Map<String, String> attributes) {
+
+ Rfc5424Layout layout = buildRfc5424Layout(attributes);
+
+ assertThat(layout.getMdcExcludes()).containsExactly("key3", "key4");
+ assertThat(layout.getMdcIncludes()).isNullOrEmpty();
+ }
+
+ private static Stream<Arguments> testRejectsIncludesAndExcludesTogether() {
+ return Stream.of(
+ Arguments.of(
+ "documented attributes",
+ attributeMap("mdcIncludes", INCLUDED_KEYS,
"mdcExcludes", EXCLUDED_KEYS)),
+ Arguments.of(
+ "compatibility aliases", attributeMap("includes",
INCLUDED_KEYS, "excludes", EXCLUDED_KEYS)));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testRejectsIncludesAndExcludesTogether(String ignoredDisplayName,
Map<String, String> attributes) {
+
+ Rfc5424Layout layout = buildRfc5424Layout(attributes);
+
+ // If both includes and excludes are specified, the layout will ignore
the includes and log an error about the
+ // invalid configuration.
+ assertThat(layout.getMdcExcludes()).containsExactly("key3", "key4");
+ assertThat(layout.getMdcIncludes()).isNullOrEmpty();
+ }
+
private static LogEvent createLogEventWithMdcParamName(final String
paramName) {
final MutableInstant instant = new MutableInstant();
instant.initFromEpochMilli(1L, 0);
diff --git
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
index bb793b2519..6a1ba5da0c 100644
---
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
+++
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
@@ -24,6 +24,7 @@ import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
@@ -469,6 +470,26 @@ public final class Rfc5424Layout extends
AbstractStringLayout {
return mdcIncludes;
}
+ // Test-only
+ List<String> getMdcRequired() {
+ return mdcRequired;
+ }
+
+ // Test-only
+ boolean isIncludeNewLine() {
+ return includeNewLine;
+ }
+
+ // Test-only
+ String getEscapeNewLine() {
+ return escapeNewLine;
+ }
+
+ // Test-only
+ boolean isUseTlsMessageFormat() {
+ return useTlsMessageFormat;
+ }
+
private String computeTimeStampString(final long now) {
long last;
synchronized (this) {
@@ -697,7 +718,7 @@ public final class Rfc5424Layout extends
AbstractStringLayout {
* @param loggerFields Container for the KeyValuePairs containing the
patterns
* @param config The Configuration. Some Converters require access to the
Interpolator.
* @return An Rfc5424Layout.
- * @deprecated Use {@link Rfc5424LayoutBuilder instead}
+ * @deprecated Since 2.21.0 use {@link Rfc5424LayoutBuilder instead}
*/
@Deprecated
public static Rfc5424Layout createLayout(
@@ -747,65 +768,208 @@ public final class Rfc5424Layout extends
AbstractStringLayout {
.build();
}
+ /**
+ * @since 2.21.0
+ */
@PluginBuilderFactory
public static Rfc5424LayoutBuilder newBuilder() {
return new Rfc5424LayoutBuilder();
}
+ /**
+ * @since 2.21.0
+ */
public static class Rfc5424LayoutBuilder extends
AbstractStringLayout.Builder<Rfc5424LayoutBuilder>
implements
org.apache.logging.log4j.core.util.Builder<Rfc5424Layout> {
+ /**
+ * The name of the {@link Facility} as described in RFC 5424
+ *
+ * <p>The matching is case-insensitive. Defaults to {@code LOCAL0}.</p>
+ */
@PluginBuilderAttribute
private Facility facility = Facility.LOCAL0;
+ /**
+ * The default {@code SD-ID} as described in RFC 5424.
+ */
@PluginBuilderAttribute
private String id;
+ /**
+ * The enterprise number to include in {@code SD-ID} identifiers.
+ *
+ * <p>Can contain multiple integers separated by a dot, for example
{@code 32473.1}</p>
+ *
+ * <p>Defaults to {@value #DEFAULT_ENTERPRISE_NUMBER}.</p>
+ */
@PluginBuilderAttribute
private String ein = String.valueOf(DEFAULT_ENTERPRISE_NUMBER);
+ /**
+ * The enterprise number to include in {@code SD-ID} identifiers.
+ *
+ * <p>Limited to a single integer.</p>
+ *
+ * <p>Defaults to {@value #DEFAULT_ENTERPRISE_NUMBER}.</p>
+ */
@PluginBuilderAttribute
private Integer enterpriseNumber;
+ /**
+ * Indicates whether data from the context map will be included as RFC
5424 {@code SD-ELEMENT}.
+ *
+ * <p>Defaults to {@code true}.</p>
+ */
@PluginBuilderAttribute
private boolean includeMDC = true;
+ /**
+ * If {@code true}, a newline will be appended to the end of the
syslog record.
+ *
+ * <p>Default is {@code false}.</p>
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private boolean newLine;
+
+ /**
+ * Same as {@code newLine}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private boolean includeNL;
+ /**
+ * If set, this string will be used to replace new lines within the
message text.
+ *
+ * <p>By default, new lines are not escaped.</p>
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private String newLineEscape;
+
+ /**
+ * Same as {@code newLineEscape}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private String escapeNL;
+ /**
+ * The id to use for the MDC Structured Data Element.
+ *
+ * <p>Defaults to {@value #DEFAULT_MDCID}.</p>
+ */
@PluginBuilderAttribute
private String mdcId = DEFAULT_MDCID;
+ /**
+ * A prefix to add to MDC key names when formatting them as structured
data parameters.
+ */
@PluginBuilderAttribute
private String mdcPrefix;
+ /**
+ * A prefix to add to event key names when formatting {@link
StructuredDataMessage} fields.
+ */
@PluginBuilderAttribute
private String eventPrefix;
+ /**
+ * The value to use as the {@code APP-NAME} in the RFC 5424 syslog
record.
+ */
@PluginBuilderAttribute
private String appName;
+ /**
+ * The default value to be used in the {@code MSGID} field of RFC 5424
syslog records.
+ *
+ * <p>If the log event contains a {@link StructuredDataMessage}, the
id from that message will be used
+ * instead.</p>
+ */
@PluginBuilderAttribute
private String messageId;
+ /**
+ * A comma separated list of MDC keys that should be excluded from the
LogEvent.
+ *
+ * <p>Mutually exclusive with {@link #mdcIncludes}.</p>
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private String mdcExcludes;
+
+ /**
+ * Same as {@code mdcExcludes}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private String excludes;
+ /**
+ * A comma separated list of MDC keys that should be included in the
LogEvent.
+ *
+ * <p>Mutually exclusive with {@link #mdcExcludes}.</p>
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private String mdcIncludes;
+
+ /**
+ * Same as {@code mdcIncludes}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private String includes;
+ /**
+ * A comma separated list of MDC keys that must be present in the MDC.
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private String mdcRequired;
+
+ /**
+ * Same as {@code mdcRequired}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private String required;
+ /**
+ * The pattern used to format exceptions appended to the syslog
message.
+ */
@PluginBuilderAttribute
private String exceptionPattern;
+ /**
+ * If true the message will be formatted according to RFC 5425.
+ *
+ * <p>Default is {@code false}.</p>
+ */
+ @SuppressWarnings("log4j.public.setter")
+ @PluginBuilderAttribute
+ private boolean useTlsMessageFormat;
+
+ /**
+ * Same as {@code useTlsMessageFormat}.
+ *
+ * <p>Erroneously introduced in version 2.21.0, but kept for
compatibility.</p>
+ */
@PluginBuilderAttribute
private boolean useTLSMessageFormat;
+ /**
+ * Optional additional {@code SD-ELEMENT}s.
+ *
+ * <p>Each {@link LoggerFields} entry contains a set of key/value
patterns to produce structured data parameters.</p>
+ */
@PluginElement(value = "loggerFields")
private LoggerFields[] loggerFields;
@@ -918,9 +1082,12 @@ public final class Rfc5424Layout extends
AbstractStringLayout {
@Override
public Rfc5424Layout build() {
- if (includes != null && excludes != null) {
- LOGGER.error("mdcIncludes and mdcExcludes are mutually
exclusive. Includes wil be ignored");
- includes = null;
+ String effectiveIncludes = Objects.toString(mdcIncludes, includes);
+ String effectiveExcludes = Objects.toString(mdcExcludes, excludes);
+
+ if (effectiveIncludes != null && effectiveExcludes != null) {
+ LOGGER.error("mdcIncludes and mdcExcludes are mutually
exclusive. Includes will be ignored");
+ effectiveIncludes = null;
}
if (enterpriseNumber != null) {
@@ -938,19 +1105,19 @@ public final class Rfc5424Layout extends
AbstractStringLayout {
id,
ein,
includeMDC,
- includeNL,
- escapeNL,
+ newLine || includeNL,
+ Objects.toString(newLineEscape, escapeNL),
mdcId,
mdcPrefix,
eventPrefix,
appName,
messageId,
- excludes,
- includes,
- required,
+ effectiveExcludes,
+ effectiveIncludes,
+ Objects.toString(mdcRequired, required),
charset != null ? charset : StandardCharsets.UTF_8,
exceptionPattern,
- useTLSMessageFormat,
+ useTlsMessageFormat || useTLSMessageFormat,
loggerFields);
}
}
diff --git a/src/changelog/.2.x.x/4022_rfc5424-param-names.xml
b/src/changelog/.2.x.x/4022_rfc5424-param-names.xml
new file mode 100644
index 0000000000..3949415b25
--- /dev/null
+++ b/src/changelog/.2.x.x/4022_rfc5424-param-names.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+ type="fixed">
+ <issue id="4022"
link="https://github.com/apache/logging-log4j2/issues/4022"/>
+ <issue id="4074"
link="https://github.com/apache/logging-log4j2/pull/4074"/>
+ <description format="asciidoc">
+ Restore support for documented `Rfc5424Layout` parameter names.
+ </description>
+</entry>