You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/10/01 18:59:41 UTC

[logging-log4j2] 01/02: [LOG4J2-1376] Define eid as String instead of int to allow for Oid according to RFC5424 (#836)

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit ad4e0c1925115807a3a4139b124eb416575e3daa
Author: mneundorfer <co...@mneundorfer.de>
AuthorDate: Mon May 16 10:01:03 2022 +0200

    [LOG4J2-1376] Define eid as String instead of int to allow for Oid
    according to RFC5424 (#836)
    
    * LOG4J2-1376 - define eid as String instead of int to allow for Oid
    according to RFC5424
    
    * LOG4J2-1376 - Define eid as String to allow for OID fragments
    
    Co-authored-by: ppkarwasz <pi...@karwasz.org>
---
 .../log4j/message/StructuredDataMessageTest.java   |   8 +
 .../logging/log4j/message/StructuredDataId.java    |  75 +++++++--
 .../log4j/core/layout/Rfc5424LayoutTest.java       |  85 ++++++++--
 .../log4j/core/appender/SyslogAppender.java        |  38 ++++-
 .../logging/log4j/core/layout/LoggerFields.java    |  11 +-
 .../logging/log4j/core/layout/Rfc5424Layout.java   | 178 ++++++++++++++++++---
 .../log4j/flume/appender/FlumeAppender.java        |  18 ++-
 7 files changed, 351 insertions(+), 62 deletions(-)

diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
index 39e0d02b38..b592fcea8b 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
@@ -108,4 +108,12 @@ public class StructuredDataMessageTest {
         final String expected2 = "Alert [MsgId@1 memo=\"Added later\" message=\"Test message {}\" project=\"Log4j\"] Test message {}";
         assertEquals(expected2, result2);
     }
+
+    @Test
+    public void testEnterpriseNoAsOidFragment() {
+        final String testMsg = "Test message {}";
+        final StructuredDataMessage structuredDataMessage = new StructuredDataMessage("XX_DATA@1234.55.6.7", testMsg, "Nothing");
+        assertNotNull(structuredDataMessage);
+    }
+
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java
index 2b21e6499b..47d392431c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataId.java
@@ -47,14 +47,14 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
     /**
      * Reserved enterprise number.
      */
-    public static final int RESERVED = -1;
+    public static final String RESERVED = "-1";
 
-    private static final long serialVersionUID = 9031746276396249990L;
+    private static final long serialVersionUID = -8252896346202183738L;
     private static final int MAX_LENGTH = 32;
     private static final String AT_SIGN = "@";
 
     private final String name;
-    private final int enterpriseNumber;
+    private final String enterpriseNumber;
     private final String[] required;
     private final String[] optional;
 
@@ -111,7 +111,7 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
 
         if (index > 0) {
             this.name = name.substring(0, index);
-            this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
+            this.enterpriseNumber = name.substring(index + 1).trim();
         } else {
             this.name = name;
             this.enterpriseNumber = RESERVED;
@@ -128,11 +128,26 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
      * @param required The list of keys that are required for this id.
      * @param optional The list of keys that are optional for this id.
      */
-    public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
+    public StructuredDataId(final String name, final String enterpriseNumber, final String[] required,
                             final String[] optional) {
         this(name, enterpriseNumber, required, optional, MAX_LENGTH);
     }
 
+    /**
+     * A Constructor that helps conformance to RFC 5424.
+     *
+     * @param name The name portion of the id.
+     * @param enterpriseNumber The enterprise number.
+     * @param required The list of keys that are required for this id.
+     * @param optional The list of keys that are optional for this id.
+     * @deprecated Use {@link #StructuredDataId(String, String, String[], String[])} instead.
+     */
+    @Deprecated
+    public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
+                            final String[] optional) {
+        this(name, String.valueOf(enterpriseNumber), required, optional, MAX_LENGTH);
+    }
+
     /**
      * A Constructor that helps conformance to RFC 5424.
      *
@@ -143,15 +158,15 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
      * @param maxLength The maximum length of the StructuredData Id key.
      * @since 2.9
      */
-    public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
-            final String[] optional, final int maxLength) {
+    public StructuredDataId(final String name, final String enterpriseNumber, final String[] required,
+                            final String[] optional, final int maxLength) {
         if (name == null) {
             throw new IllegalArgumentException("No structured id name was supplied");
         }
         if (name.contains(AT_SIGN)) {
             throw new IllegalArgumentException("Structured id name cannot contain an " + Strings.quote(AT_SIGN));
         }
-        if (enterpriseNumber <= 0) {
+        if (RESERVED.equals(enterpriseNumber)) {
             throw new IllegalArgumentException("No enterprise number was supplied");
         }
         this.name = name;
@@ -164,6 +179,23 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
         this.optional = optional;
     }
 
+    /**
+     * A Constructor that helps conformance to RFC 5424.
+     *
+     * @param name The name portion of the id.
+     * @param enterpriseNumber The enterprise number.
+     * @param required The list of keys that are required for this id.
+     * @param optional The list of keys that are optional for this id.
+     * @param maxLength The maximum length of the StructuredData Id key.
+     * @since 2.9
+     * @deprecated Use {@link #StructuredDataId(String, String, String[], String[], int)} instead.
+     */
+    @Deprecated
+    public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
+            final String[] optional, final int maxLength) {
+        this(name, String.valueOf(enterpriseNumber), required, optional, maxLength);
+    }
+
     /**
      * Creates an id using another id to supply default values.
      *
@@ -184,11 +216,11 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
      * @param anEnterpriseNumber The enterprise number.
      * @return a StructuredDataId.
      */
-    public StructuredDataId makeId(final String defaultId, final int anEnterpriseNumber) {
-        final String id;
-        final String[] req;
-        final String[] opt;
-        if (anEnterpriseNumber <= 0) {
+    public StructuredDataId makeId(final String defaultId, final String anEnterpriseNumber) {
+        String id;
+        String[] req;
+        String[] opt;
+        if (RESERVED.equals(anEnterpriseNumber)) {
             return this;
         }
         if (this.name != null) {
@@ -204,6 +236,19 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
         return new StructuredDataId(id, anEnterpriseNumber, req, opt);
     }
 
+    /**
+     * Creates an id based on the current id.
+     *
+     * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
+     * @param anEnterpriseNumber The enterprise number.
+     * @return a StructuredDataId.
+     * @deprecated Use {@link StructuredDataId#makeId(String, String)} instead
+     */
+    @Deprecated
+    public StructuredDataId makeId(final String defaultId, final int anEnterpriseNumber) {
+        return makeId(defaultId, String.valueOf(anEnterpriseNumber));
+    }
+
     /**
      * Returns a list of required keys.
      *
@@ -236,7 +281,7 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
      *
      * @return the enterprise number.
      */
-    public int getEnterpriseNumber() {
+    public String getEnterpriseNumber() {
         return enterpriseNumber;
     }
 
@@ -246,7 +291,7 @@ public class StructuredDataId implements Serializable, StringBuilderFormattable
      * @return true if the id uses the reserved enterprise number, false otherwise.
      */
     public boolean isReserved() {
-        return enterpriseNumber <= 0;
+        return RESERVED.equals(enterpriseNumber);
     }
 
     @Override
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 c5bad85c8d..aee0460aed 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
@@ -16,6 +16,11 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.ThreadContext;
@@ -26,6 +31,7 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.net.Facility;
 import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.util.Integers;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.core.util.ProcessIdUtil;
 import org.apache.logging.log4j.message.StructuredDataCollectionMessage;
@@ -37,13 +43,15 @@ import org.apache.logging.log4j.util.Strings;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 @UsingAnyThreadContext
 public class Rfc5424LayoutTest {
@@ -136,7 +144,7 @@ public class Rfc5424LayoutTest {
                 final int firstSpacePosition = frame.indexOf(' ');
                 final String messageLength = frame.substring(0, firstSpacePosition);
                 try {
-                    length = Integer.parseInt(messageLength);
+                    length = Integers.parseInt(messageLength);
                     // the ListAppender removes the ending newline, so we expect one less size
                     assertEquals(frameLength, messageLength.length() + length);
                 }
@@ -189,7 +197,7 @@ public class Rfc5424LayoutTest {
             final StructuredDataMessage msg2 = new StructuredDataMessage("Extra@18060", null, "Audit");
             msg2.put("Item1", "Hello");
             msg2.put("Item2", "World");
-            List<StructuredDataMessage> messages = new ArrayList<>();
+            final List<StructuredDataMessage> messages = new ArrayList<>();
             messages.add(msg);
             messages.add(msg2);
             final StructuredDataCollectionMessage collectionMessage = new StructuredDataCollectionMessage(messages);
@@ -214,7 +222,7 @@ public class Rfc5424LayoutTest {
                 final int firstSpacePosition = frame.indexOf(' ');
                 final String messageLength = frame.substring(0, firstSpacePosition);
                 try {
-                    length = Integer.parseInt(messageLength);
+                    length = Integers.parseInt(messageLength);
                     // the ListAppender removes the ending newline, so we expect one less size
                     assertEquals(frameLength, messageLength.length() + length);
                 }
@@ -498,8 +506,8 @@ public class Rfc5424LayoutTest {
         // set up appender
         final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
             null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, true, null, null);
-        final ListAppender appender = new ListAppender("List", null, layout, true, false);
 
+        final ListAppender appender = new ListAppender("List", null, layout, true, false);
         appender.start();
 
         // set appender on root and set level to debug
@@ -517,4 +525,61 @@ public class Rfc5424LayoutTest {
             appender.stop();
         }
     }
+
+    @Test
+    void testLayoutBuilder() {
+        for (final Appender appender : root.getAppenders().values()) {
+            root.removeAppender(appender);
+        }
+
+        final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+                .setFacility(Facility.LOCAL0)
+                .setId("Event")
+                .setEin("1234.56.7")
+                .setIncludeMDC(true)
+                .setMdcId("RequestContext")
+                .setIncludeNL(true)
+                .setAppName("ATM")
+                .setExcludes("key1, key2, locale")
+                .setUseTLSMessageFormat(true)
+                .build();
+
+        final ListAppender appender = new ListAppender("List", null, layout, true, false);
+        appender.start();
+
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+        root.info("Hello {}", "World");
+        try {
+            final List<String> list = appender.getMessages();
+            assertTrue(list.size() > 0, "Not enough list entries");
+            final String message =  list.get(0);
+            assertTrue(message.contains("Hello World"),
+                    "Incorrect message. Expected - Hello World, Actual - " + message);
+        } finally {
+            root.removeAppender(appender);
+            appender.stop();
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "123456789", "0", "2147483647", "123.45.6.78.9", "0.0.0.0.0.0.0.0.0.0.0.0.0.0" })
+    void testLayoutBuilderValidEids(String eid) {
+        final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+                .setEin(eid)
+                .build();
+
+        assertNotNull(layout);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "abc", "someEid", "-1" })
+    void testLayoutBuilderInvalidEids(String eid) {
+        final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+                .setEin(eid)
+                .build();
+
+        assertNull(layout);
+    }
+
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
index 1d555475d0..14e36a4f5d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
@@ -56,7 +56,7 @@ public class SyslogAppender extends SocketAppender {
         private String id;
 
         @PluginBuilderAttribute(value = "enterpriseNumber")
-        private int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
+        private String enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
 
         @PluginBuilderAttribute(value = "includeMdc")
         private boolean includeMdc = true;
@@ -113,10 +113,26 @@ public class SyslogAppender extends SocketAppender {
             Layout<? extends Serializable> layout = getLayout();
             if (layout == null) {
                 layout = RFC5424.equalsIgnoreCase(format)
-                        ? Rfc5424Layout.createLayout(facility, id, enterpriseNumber, includeMdc, mdcId, mdcPrefix,
-                                eventPrefix, newLine, escapeNL, appName, msgId, excludes, includes, required,
-                                exceptionPattern, useTlsMessageFormat, loggerFields, configuration)
-                        :
+                        ? new Rfc5424Layout.Rfc5424LayoutBuilder()
+                        .setFacility(facility)
+                        .setId(id)
+                        .setEin(enterpriseNumber)
+                        .setIncludeMDC(includeMdc)
+                        .setMdcId(mdcId)
+                        .setMdcPrefix(mdcPrefix)
+                        .setEventPrefix(eventPrefix)
+                        .setIncludeNL(newLine)
+                        .setEscapeNL(escapeNL)
+                        .setAppName(appName)
+                        .setMessageId(msgId)
+                        .setExcludes(excludes)
+                        .setIncludes(includes)
+                        .setRequired(required)
+                        .setExceptionPattern(exceptionPattern)
+                        .setUseTLSMessageFormat(useTlsMessageFormat)
+                        .setLoggerFields(loggerFields)
+                        .setConfig(configuration)
+                        .build() :
                         // @formatter:off
                         SyslogLayout.newBuilder()
                             .setFacility(facility)
@@ -146,7 +162,7 @@ public class SyslogAppender extends SocketAppender {
             return id;
         }
 
-        public int getEnterpriseNumber() {
+        public String getEnterpriseNumber() {
             return enterpriseNumber;
         }
 
@@ -220,11 +236,19 @@ public class SyslogAppender extends SocketAppender {
             return asBuilder();
         }
 
-        public B setEnterpriseNumber(final int enterpriseNumber) {
+        public B setEnterpriseNumber(final String enterpriseNumber) {
             this.enterpriseNumber = enterpriseNumber;
             return asBuilder();
         }
 
+        /**
+         * @deprecated Use {@link #setEnterpriseNumber(String)} instead
+         */
+        public B setEnterpriseNumber(final int enterpriseNumber) {
+            this.enterpriseNumber = String.valueOf(enterpriseNumber);
+            return asBuilder();
+        }
+
         public B setIncludeMdc(final boolean includeMdc) {
             this.includeMdc = includeMdc;
             return asBuilder();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
index fb44665885..b47ad6c7b6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
@@ -16,6 +16,10 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.StructuredDataId;
 import org.apache.logging.log4j.plugins.Configurable;
@@ -24,10 +28,6 @@ import org.apache.logging.log4j.plugins.PluginAttribute;
 import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.plugins.PluginFactory;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * A LoggerFields container.
  */
@@ -89,8 +89,7 @@ public final class LoggerFields {
         if (enterpriseId == null || sdId == null) {
             return null;
         }
-        final int eId = Integer.parseInt(enterpriseId);
-        return new StructuredDataId(sdId, eId, null, null);
+        return new StructuredDataId(sdId, enterpriseId, null, null);
     }
 
     public boolean getDiscardIfAllFieldsAreEmpty() {
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 3cea03a754..76830e4f86 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
@@ -72,9 +72,9 @@ import java.util.regex.Pattern;
 public final class Rfc5424Layout extends AbstractStringLayout {
 
     /**
-     * Not a very good default - it is the Apache Software Foundation's enterprise number.
+     * The default example enterprise number from RFC5424.
      */
-    public static final int DEFAULT_ENTERPRISE_NUMBER = 18060;
+    public static final String DEFAULT_ENTERPRISE_NUMBER = "32473";
     /**
      * The default event id.
      */
@@ -88,6 +88,11 @@ public final class Rfc5424Layout extends AbstractStringLayout {
      */
     public static final Pattern PARAM_VALUE_ESCAPE_PATTERN = Pattern.compile("[\\\"\\]\\\\]");
 
+    /**
+     * For now, avoid too restrictive OID checks to allow for easier transition
+     */
+    public static final Pattern ENTERPRISE_ID_PATTERN = Pattern.compile("\\d+(\\.\\d+)*");
+
     /**
      * Default MDC ID: {@value} .
      */
@@ -102,7 +107,7 @@ public final class Rfc5424Layout extends AbstractStringLayout {
 
     private final Facility facility;
     private final String defaultId;
-    private final int enterpriseNumber;
+    private final String enterpriseNumber;
     private final boolean includeMdc;
     private final String mdcId;
     private final StructuredDataId mdcSdId;
@@ -127,11 +132,11 @@ public final class Rfc5424Layout extends AbstractStringLayout {
     private final Map<String, FieldFormatter> fieldFormatters;
     private final String procId;
 
-    private Rfc5424Layout(final Configuration config, final Facility facility, final String id, final int ein,
-            final boolean includeMDC, final boolean includeNL, final String escapeNL, final String mdcId,
-            final String mdcPrefix, final String eventPrefix, final String appName, final String messageId,
-            final String excludes, final String includes, final String required, final Charset charset,
-            final String exceptionPattern, final boolean useTLSMessageFormat, final LoggerFields[] loggerFields) {
+    private Rfc5424Layout(final Configuration config, final Facility facility, final String id, final String ein,
+              final boolean includeMDC, final boolean includeNL, final String escapeNL, final String mdcId,
+              final String mdcPrefix, final String eventPrefix, final String appName, final String messageId,
+              final String excludes, final String includes, final String required, final Charset charset,
+              final String exceptionPattern, final boolean useTLSMessageFormat, final LoggerFields[] loggerFields) {
         super(charset);
         final PatternParser exceptionParser = createPatternParser(config, ThrowablePatternConverter.class);
         exceptionFormatters = exceptionPattern == null ? null : exceptionParser.parse(exceptionPattern);
@@ -530,11 +535,11 @@ public final class Rfc5424Layout extends AbstractStringLayout {
         } else {
             sb.append(id.getName());
         }
-        int ein = id != null ? id.getEnterpriseNumber() : enterpriseNumber;
-        if (ein < 0) {
+        String ein = id != null ? id.getEnterpriseNumber() : enterpriseNumber;
+        if (StructuredDataId.RESERVED.equals(ein)) {
             ein = enterpriseNumber;
         }
-        if (ein >= 0) {
+        if (!StructuredDataId.RESERVED.equals(ein)) {
             sb.append('@').append(ein);
         }
         return sb.toString();
@@ -605,18 +610,20 @@ 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}
      */
     @PluginFactory
     public static Rfc5424Layout createLayout(
             // @formatter:off
-            @PluginAttribute(defaultString = "LOCAL0") final Facility facility,
-            @PluginAttribute final String id,
-            @PluginAttribute(defaultInt = DEFAULT_ENTERPRISE_NUMBER) final int enterpriseNumber,
-            @PluginAttribute(defaultBoolean = true) final boolean includeMDC,
-            @PluginAttribute(defaultString = DEFAULT_MDCID) final String mdcId,
-            @PluginAttribute final String mdcPrefix,
-            @PluginAttribute final String eventPrefix,
-            @PluginAttribute final boolean newLine,
+            @PluginAttribute(value = "facility", defaultString = "LOCAL0") final Facility facility,
+            @PluginAttribute("id") final String id,
+            @PluginAttribute(value = "enterpriseNumber", defaultInt = -1)
+            final int enterpriseNumber,
+            @PluginAttribute(value = "includeMDC", defaultBoolean = true) final boolean includeMDC,
+            @PluginAttribute(value = "mdcId", defaultString = DEFAULT_MDCID) final String mdcId,
+            @PluginAttribute("mdcPrefix") final String mdcPrefix,
+            @PluginAttribute("eventPrefix") final String eventPrefix,
+            @PluginAttribute(value = "newLine") final boolean newLine,
             @PluginAttribute("newLineEscape") final String escapeNL,
             @PluginAttribute final String appName,
             @PluginAttribute("messageId") final String msgId,
@@ -634,11 +641,142 @@ public final class Rfc5424Layout extends AbstractStringLayout {
             includes = null;
         }
 
-        return new Rfc5424Layout(config, facility, id, enterpriseNumber, includeMDC, newLine, escapeNL, mdcId,
+        return new Rfc5424Layout(config, facility, id, String.valueOf(enterpriseNumber), includeMDC, newLine, escapeNL, mdcId,
                 mdcPrefix, eventPrefix, appName, msgId, excludes, includes, required, StandardCharsets.UTF_8,
                 exceptionPattern, useTlsMessageFormat, loggerFields);
     }
 
+    public static class Rfc5424LayoutBuilder {
+        private Configuration config;
+        private Facility facility;
+        private String id;
+        private String ein;
+        private boolean includeMDC;
+        private boolean includeNL;
+        private String escapeNL;
+        private String mdcId;
+        private String mdcPrefix;
+        private String eventPrefix;
+        private String appName;
+        private String messageId;
+        private String excludes;
+        private String includes;
+        private String required;
+        private Charset charset;
+        private String exceptionPattern;
+        private boolean useTLSMessageFormat;
+        private LoggerFields[] loggerFields;
+
+        public Rfc5424LayoutBuilder setConfig(Configuration config) {
+            this.config = config;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setFacility(Facility facility) {
+            this.facility = facility;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setId(String id) {
+            this.id = id;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setEin(String ein) {
+            this.ein = ein;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setIncludeMDC(boolean includeMDC) {
+            this.includeMDC = includeMDC;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setIncludeNL(boolean includeNL) {
+            this.includeNL = includeNL;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setEscapeNL(String escapeNL) {
+            this.escapeNL = escapeNL;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setMdcId(String mdcId) {
+            this.mdcId = mdcId;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setMdcPrefix(String mdcPrefix) {
+            this.mdcPrefix = mdcPrefix;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setEventPrefix(String eventPrefix) {
+            this.eventPrefix = eventPrefix;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setAppName(String appName) {
+            this.appName = appName;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setMessageId(String messageId) {
+            this.messageId = messageId;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setExcludes(String excludes) {
+            this.excludes = excludes;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setIncludes(String includes) {
+            this.includes = includes;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setRequired(String required) {
+            this.required = required;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setCharset(Charset charset) {
+            this.charset = charset;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setExceptionPattern(String exceptionPattern) {
+            this.exceptionPattern = exceptionPattern;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setUseTLSMessageFormat(boolean useTLSMessageFormat) {
+            this.useTLSMessageFormat = useTLSMessageFormat;
+            return this;
+        }
+
+        public Rfc5424LayoutBuilder setLoggerFields(LoggerFields[] loggerFields) {
+            this.loggerFields = loggerFields;
+            return this;
+        }
+
+        public Rfc5424Layout build() {
+            if (includes != null && excludes != null) {
+                LOGGER.error("mdcIncludes and mdcExcludes are mutually exclusive. Includes wil be ignored");
+                includes = null;
+            }
+
+            if (ein != null && !ENTERPRISE_ID_PATTERN.matcher(ein).matches()) {
+                LOGGER.warn(String.format("provided EID %s is not in valid format!", ein));
+                return null;
+            }
+
+            return new Rfc5424Layout(config, facility, id, ein, includeMDC, includeNL, escapeNL, mdcId, mdcPrefix, eventPrefix, appName, messageId, excludes, includes, required, charset, exceptionPattern, useTLSMessageFormat, loggerFields);
+        }
+    }
+
     private class FieldFormatter {
 
         private final Map<String, List<PatternFormatter>> delegateMap;
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index 8ef8d893ea..6b24870dec 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -253,10 +253,20 @@ public final class FlumeAppender extends AbstractAppender implements FlumeEventF
         final int delayMillis = Integers.parseInt(maxDelayMillis, DEFAULT_MAX_DELAY);
 
         if (layout == null) {
-            final int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
-            layout = Rfc5424Layout.createLayout(Facility.LOCAL0, null, enterpriseNumber, true, Rfc5424Layout.DEFAULT_MDCID,
-                    mdcPrefix, eventPrefix, false, null, null, null, excludes, includes, required, null, false, null,
-                    null);
+            final String enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
+            layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+                    .setFacility(Facility.LOCAL0)
+                    .setEin(enterpriseNumber)
+                    .setIncludeMDC(true)
+                    .setMdcId(Rfc5424Layout.DEFAULT_MDCID)
+                    .setMdcPrefix(mdcPrefix)
+                    .setEventPrefix(eventPrefix)
+                    .setIncludeNL(false)
+                    .setExcludes(excludes)
+                    .setIncludes(includes)
+                    .setRequired(required)
+                    .setUseTLSMessageFormat(false)
+                    .build();
         }
 
         if (name == null) {