Index: log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
===================================================================
--- log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java	(revision 1519924)
+++ log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java	(working copy)
@@ -115,7 +115,7 @@
             @PluginConfiguration final Configuration config,
             @PluginAttribute("charset") final String charsetName,
             @PluginAttribute("exceptionPattern") final String exceptionPattern,
-            @PluginElement("LoggerFields") final LoggerFields loggerFields,
+            @PluginElement("LoggerFields") final LoggerFields[] loggerFields,
             @PluginAttribute("advertise") final String advertise) {
 
         final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
Index: log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
===================================================================
--- log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java	(revision 1519924)
+++ log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java	(working copy)
@@ -21,9 +21,12 @@
 import java.util.Map;
 
 import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.Booleans;
 import org.apache.logging.log4j.core.helpers.KeyValuePair;
+import org.apache.logging.log4j.message.StructuredDataId;
 
 /**
  * A LoggerFields container.
@@ -32,9 +35,15 @@
 public final class LoggerFields {
 
     private final Map<String, String> map;
+    private String sdId;
+    private String enterpriseId;
+    private boolean discardIfAllFieldsAreEmpty;
 
-    private LoggerFields(final Map<String, String> map) {
+    private LoggerFields(final Map<String, String> map, String sdId, String enterpriseId, boolean discardIfAllFieldsAreEmpty) {
+        this.sdId = sdId;
+        this.enterpriseId = enterpriseId;
         this.map = Collections.unmodifiableMap(map);
+        this.discardIfAllFieldsAreEmpty = discardIfAllFieldsAreEmpty;
     }
 
     public Map<String, String> getMap() {
@@ -50,11 +59,17 @@
      * Create a LoggerFields from KeyValuePairs.
      *
      * @param keyValuePairs An array of KeyValuePairs.
+     * @param sdId The SD-ID in an SD-ELEMENT
+     * @param enterpriseId The IANA assigned enterprise number
+     * @param discardIfAllFieldsAreEmpty this SD-ELEMENT should be discarded if all fields are empty
      * @return A LoggerFields instance containing a Map<String, String>.
      */
     @PluginFactory
     public static LoggerFields createLoggerFields(
-        @PluginElement("LoggerFields") final KeyValuePair[] keyValuePairs) {
+        @PluginElement("LoggerFields") final KeyValuePair[] keyValuePairs,
+        @PluginAttribute("sdId") final String sdId,
+        @PluginAttribute("enterpriseId") String enterpriseId,
+        @PluginAttribute("discardIfAllFieldsAreEmpty") String discardIfAllFieldsAreEmpty) {
         final Map<String, String> map =
             new HashMap<String, String>();
 
@@ -62,6 +77,21 @@
             map.put(keyValuePair.getKey(), keyValuePair.getValue());
         }
 
-        return new LoggerFields(map);
+        boolean discardIfEmpty = Booleans.parseBoolean(discardIfAllFieldsAreEmpty, false);
+        return new LoggerFields(map, sdId, enterpriseId, discardIfEmpty);
     }
+
+    public StructuredDataId getSdId() {
+        if (enterpriseId == null || sdId == null)  {
+            return null;
+        }
+        else {
+            int eId = Integer.valueOf(enterpriseId);
+            return new StructuredDataId(sdId, eId, null, null);
+        }
+    }
+
+    public boolean getDiscardIfAllFieldsAreEmpty() {
+        return discardIfAllFieldsAreEmpty;
+    }
 }
Index: log4j-core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java
===================================================================
--- log4j-core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java	(revision 1519924)
+++ log4j-core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java	(working copy)
@@ -28,6 +28,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -87,9 +88,10 @@
 
     private final Facility facility;
     private final String defaultId;
-    private final int enterpriseNumber;
+    private final Integer enterpriseNumber;
     private final boolean includeMDC;
     private final String mdcId;
+    private final StructuredDataId mdcSDID;
     private final String localHostName;
     private final String appName;
     private final String messageId;
@@ -108,14 +110,14 @@
     private String timestamppStr;
 
     private final List<PatternFormatter> exceptionFormatters;
-    private final Map<String, List<PatternFormatter>> fieldFormatters;
+    private final Map<String,  FieldFormatter> fieldFormatters;
 
     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 Map<String, String> loggerFields) {
+                          final LoggerFields[] loggerFields) {
         super(charset);
         final PatternParser exceptionParser = createPatternParser(config, ThrowablePatternConverter.class);
         exceptionFormatters = exceptionPattern == null ? null : exceptionParser.parse(exceptionPattern, false);
@@ -126,6 +128,7 @@
         this.includeNewLine = includeNL;
         this.escapeNewLine = escapeNL == null ? null : Matcher.quoteReplacement(escapeNL);
         this.mdcId = mdcId;
+        this.mdcSDID = new StructuredDataId(mdcId, enterpriseNumber, null, null);
         this.mdcPrefix = mdcPrefix;
         this.eventPrefix = eventPrefix;
         this.appName = appName;
@@ -177,18 +180,30 @@
         this.checker = c != null ? c : noopChecker;
         final String name = config == null ? null : config.getName();
         configName = name != null && name.length() > 0 ? name : null;
-        if (loggerFields != null && !loggerFields.isEmpty()) {
-            final PatternParser fieldParser = createPatternParser(config, null);
+        this.fieldFormatters = createFieldFormatters(loggerFields, config);
+    }
 
-            final Map<String, List<PatternFormatter>> map = new HashMap<String, List<PatternFormatter>>();
-            for (final Map.Entry<String, String> entry : loggerFields.entrySet()) {
-                final List<PatternFormatter> formatters = fieldParser.parse(entry.getValue(), false);
-                map.put(entry.getKey(), formatters);
+    private Map<String,  FieldFormatter> createFieldFormatters(final LoggerFields[] loggerFields, final Configuration config) {
+        final Map<String,  FieldFormatter> sdIdMap = new HashMap<String,  FieldFormatter>();
+
+        if (loggerFields != null) {
+            for (final LoggerFields lField: loggerFields) {
+                StructuredDataId key = lField.getSdId() == null ? mdcSDID : lField.getSdId();
+                Map<String, List<PatternFormatter>> sdParams = new HashMap<String, List<PatternFormatter>>();
+                Map<String, String> fields = lField.getMap();
+                if (!fields.isEmpty()) {
+                    final PatternParser fieldParser = createPatternParser(config, null);
+
+                    for (final Map.Entry<String, String> entry : fields.entrySet()) {
+                        final List<PatternFormatter> formatters = fieldParser.parse(entry.getValue(), false);
+                        sdParams.put(entry.getKey(), formatters);
+                    }
+                    FieldFormatter fieldFormatter = new FieldFormatter(sdParams, lField.getDiscardIfAllFieldsAreEmpty());
+                    sdIdMap.put(key.toString(), fieldFormatter);
+                }
             }
-            this.fieldFormatters = map;
-        } else {
-            this.fieldFormatters = null;
         }
+        return sdIdMap.size() > 0 ? sdIdMap : null;
     }
 
     /**
@@ -236,88 +251,150 @@
      */
     @Override
     public String toSerializable(final LogEvent event) {
-        final Message msg = event.getMessage();
-        final boolean isStructured = msg instanceof StructuredDataMessage;
         final StringBuilder buf = new StringBuilder();
 
-        buf.append("<");
-        buf.append(Priority.getPriority(facility, event.getLevel()));
-        buf.append(">1 ");
-        buf.append(computeTimeStampString(event.getMillis()));
-        buf.append(' ');
-        buf.append(localHostName);
-        buf.append(' ');
+        appendPriority(buf, event.getLevel());
+        appendTimestamp(buf, event.getMillis());
+        appendSpace(buf);
+        appendHostName(buf);
+        appendSpace(buf);
+        appendAppName(buf);
+        appendSpace(buf);
+        appendProcessId(buf);
+        appendSpace(buf);
+        appendMessageId(buf, event.getMessage());
+        appendSpace(buf);
+        appendStructuredElements(buf, event);
+        appendMessage(buf, event);
+        return buf.toString();
+    }
+
+    private void appendPriority(final StringBuilder buffer, final Level logLevel) {
+        buffer.append("<");
+        buffer.append(Priority.getPriority(facility, logLevel));
+        buffer.append(">1 ");
+    }
+
+    private void appendTimestamp(final StringBuilder buffer, final long milliseconds)  {
+        buffer.append(computeTimeStampString(milliseconds));
+    }
+
+    private void appendSpace(final StringBuilder buffer) {
+        buffer.append(" ");
+    }
+
+    private void appendHostName(final StringBuilder buffer) {
+        buffer.append(localHostName);
+    }
+
+    private void appendAppName(final StringBuilder buffer) {
         if (appName != null) {
-            buf.append(appName);
+            buffer.append(appName);
         } else if (configName != null) {
-            buf.append(configName);
+            buffer.append(configName);
         } else {
-            buf.append("-");
+            buffer.append("-");
         }
-        buf.append(" ");
-        buf.append(getProcId());
-        buf.append(" ");
-        final String type = isStructured ? ((StructuredDataMessage) msg).getType() : null;
+    }
+
+    private void appendProcessId(final StringBuilder buffer) {
+        buffer.append(getProcId());
+    }
+
+    private void appendMessageId(final StringBuilder buffer, final Message message) {
+        final boolean isStructured = message instanceof StructuredDataMessage;
+        final String type = isStructured ? ((StructuredDataMessage) message).getType() : null;
         if (type != null) {
-            buf.append(type);
+            buffer.append(type);
         } else if (messageId != null) {
-            buf.append(messageId);
+            buffer.append(messageId);
         } else {
-            buf.append("-");
+            buffer.append("-");
         }
-        buf.append(" ");
-        if (isStructured || includeMDC) {
-            StructuredDataId id = null;
-            String text;
-            if (isStructured) {
-                final StructuredDataMessage data = (StructuredDataMessage) msg;
-                final Map<String, String> map = data.getData();
-                id = data.getId();
-                formatStructuredElement(id, eventPrefix, map, buf, noopChecker);
-                text = data.getFormat();
-            } else {
-                text = msg.getFormattedMessage();
-            }
-            if (includeMDC) {
-                Map<String, String> map = event.getContextMap();
-                if (mdcRequired != null) {
-                    checkRequired(map);
-                }
-                final int ein = id == null || id.getEnterpriseNumber() < 0 ?
-                    enterpriseNumber : id.getEnterpriseNumber();
-                final StructuredDataId mdcSDID = new StructuredDataId(mdcId, ein, null, null);
-                if (fieldFormatters != null) {
-                    map = new HashMap<String, String>(map);
-                    for (final Map.Entry<String, List<PatternFormatter>> entry : fieldFormatters.entrySet()) {
-                        final StringBuilder value = new StringBuilder();
-                        for (final PatternFormatter formatter : entry.getValue()) {
-                            formatter.format(event, value);
-                        }
-                        map.put(entry.getKey(), value.toString());
-                    }
-                }
-                formatStructuredElement(mdcSDID, mdcPrefix, map, buf, checker);
-            }
-            if (text != null && text.length() > 0) {
-                buf.append(" ").append(escapeNewlines(text, escapeNewLine));
-            }
-        } else {
-            buf.append("- ");
-            buf.append(escapeNewlines(msg.getFormattedMessage(), escapeNewLine));
+    }
+
+    private void appendMessage(final StringBuilder buffer, final LogEvent event) {
+        Message message = event.getMessage();
+        String text = message.getFormat();
+
+        if (text != null && text.length() > 0) {
+            buffer.append(" ").append(escapeNewlines(text, escapeNewLine));
         }
+
         if (exceptionFormatters != null && event.getThrown() != null) {
             final StringBuilder exception = new StringBuilder("\n");
             for (final PatternFormatter formatter : exceptionFormatters) {
                 formatter.format(event, exception);
             }
-            buf.append(escapeNewlines(exception.toString(), escapeNewLine));
+            buffer.append(escapeNewlines(exception.toString(), escapeNewLine));
         }
         if (includeNewLine) {
-            buf.append("\n");
+            buffer.append("\n");
         }
-        return buf.toString();
     }
 
+    private void appendStructuredElements(final StringBuilder buffer, final LogEvent event) {
+        final Message message = event.getMessage();
+        final boolean isStructured = message instanceof StructuredDataMessage;
+
+        if (!isStructured && (fieldFormatters!= null && fieldFormatters.size() == 0) && !includeMDC) {
+            buffer.append("-");
+            return;
+        }
+
+        Map<String, StructuredDataElement> sdElements = new HashMap<String, StructuredDataElement>();
+        Map<String, String> contextMap = event.getContextMap();
+
+        if (mdcRequired != null) {
+            checkRequired(contextMap);
+        }
+
+        if (fieldFormatters != null) {
+            for (Map.Entry<String, FieldFormatter> sdElement: fieldFormatters.entrySet()) {
+                String sdId = sdElement.getKey();
+
+                Map<String, String> map = new HashMap<String, String>();
+                StructuredDataElement elem = sdElement.getValue().format(event);
+                sdElements.put(sdId, elem);
+            }
+        }
+
+        if (includeMDC && contextMap.size() > 0) {
+            if (sdElements.containsKey(mdcSDID.toString())) {
+                StructuredDataElement union = sdElements.get(mdcSDID.toString());
+                union.union(contextMap);
+                sdElements.put(mdcSDID.toString(), union);
+            } else {
+                StructuredDataElement formattedContextMap = new StructuredDataElement(contextMap, false);
+                sdElements.put(mdcSDID.toString(), formattedContextMap);
+            }
+        }
+
+        if (isStructured) {
+            final StructuredDataMessage data = (StructuredDataMessage) message;
+            final Map<String, String> map = data.getData();
+            StructuredDataId id = data.getId();
+
+            if (sdElements.containsKey(id.toString())) {
+                StructuredDataElement union = sdElements.get(id.toString());
+                union.union(map);
+                sdElements.put(id.toString(), union);
+            } else {
+                StructuredDataElement formattedData = new StructuredDataElement(map, false);
+                sdElements.put(id.toString(), formattedData);
+            }
+        }
+
+        if (sdElements.size() == 0) {
+            buffer.append("-");
+            return;
+        }
+
+        for (Map.Entry<String, StructuredDataElement> entry: sdElements.entrySet()) {
+            formatStructuredElement(entry.getKey(), mdcPrefix, entry.getValue(), buffer, checker);
+        }
+    }
+
     private String escapeNewlines(final String text, final String escapeNewLine) {
         if (null == escapeNewLine) {
             return text;
@@ -402,14 +479,18 @@
         buf.append(Integer.toString(val));
     }
 
-    private void formatStructuredElement(final StructuredDataId id, final String prefix, final Map<String, String> data,
+    private void formatStructuredElement(final String id, final String prefix, final StructuredDataElement data,
                                          final StringBuilder sb, final ListChecker checker) {
-        if (id == null && defaultId == null) {
+        if ((id == null && defaultId == null) || data.shouldBeDiscarded()) {
             return;
         }
+
         sb.append("[");
-        sb.append(getId(id));
-        appendMap(prefix, data, sb, checker);
+        sb.append(id);
+        if (!mdcSDID.toString().equals(id))
+            appendMap(prefix, data.getFields(), sb, noopChecker);
+        else
+            appendMap(prefix, data.getFields(), sb, checker);
         sb.append("]");
     }
 
@@ -548,7 +629,7 @@
             @PluginAttribute("mdcIncludes") String includes,
             @PluginAttribute("mdcRequired") final String required,
             @PluginAttribute("exceptionPattern") final String exceptionPattern,
-            @PluginElement("LoggerFields") final LoggerFields loggerFields,
+            @PluginElement("LoggerFields") final LoggerFields[] loggerFields,
             @PluginConfiguration final Configuration config) {
         final Charset charset = Charsets.UTF_8;
         if (includes != null && excludes != null) {
@@ -559,13 +640,74 @@
         final int enterpriseNumber = Integers.parseInt(ein, DEFAULT_ENTERPRISE_NUMBER);
         final boolean isMdc = Booleans.parseBoolean(includeMDC, true);
         final boolean includeNewLine = Boolean.parseBoolean(includeNL);
-        final Map<String, String> loggerFieldValues = loggerFields == null ? null : loggerFields.getMap();
         if (mdcId == null) {
             mdcId = DEFAULT_MDCID;
         }
 
         return new RFC5424Layout(config, f, id, enterpriseNumber, isMdc, includeNewLine, escapeNL, mdcId, mdcPrefix,
             eventPrefix, appName, msgId, excludes, includes, required, charset, exceptionPattern,
-            loggerFieldValues);
+            loggerFields);
     }
+
+    private class FieldFormatter {
+
+        private Map<String, List<PatternFormatter>> delegate;
+        private boolean mustBeDiscardedIfAllFieldValuesAreEmpty;
+
+        public FieldFormatter(
+                final Map<String, List<PatternFormatter>> field,
+                final boolean mustBeDiscardedIfAllFieldValuesAreEmpty) {
+            this.mustBeDiscardedIfAllFieldValuesAreEmpty = mustBeDiscardedIfAllFieldValuesAreEmpty;
+            this.delegate = field;
+        }
+
+        public StructuredDataElement format(final LogEvent event) {
+            Map<String, String> map = new HashMap<String, String>();
+
+            for (final Map.Entry<String, List<PatternFormatter>> entry : delegate.entrySet()) {
+                final StringBuilder value = new StringBuilder();
+                for (final PatternFormatter formatter : entry.getValue()) {
+                    formatter.format(event, value);
+                }
+                map.put(entry.getKey(), value.toString());
+            }
+            StructuredDataElement formattedElement = new StructuredDataElement(map, mustBeDiscardedIfAllFieldValuesAreEmpty);
+            return formattedElement;
+        }
+    }
+
+    private class StructuredDataElement {
+
+        private Map<String, String> fields;
+        private boolean mustBeDiscardedIfAllFieldValuesAreEmpty;
+
+        public StructuredDataElement(
+                final Map<String, String> fields,
+                final boolean mustBeDiscardedIfAllFieldValuesAreEmpty) {
+            this.mustBeDiscardedIfAllFieldValuesAreEmpty = mustBeDiscardedIfAllFieldValuesAreEmpty;
+            this.fields = fields;
+        }
+
+        public boolean shouldBeDiscarded() {
+            if (mustBeDiscardedIfAllFieldValuesAreEmpty == false)
+                return false;
+
+            boolean foundNotEmptyValue = false;
+            for(Map.Entry<String, String> entry : fields.entrySet()) {
+                if (!entry.getValue().equals("")) {
+                    foundNotEmptyValue = true;
+                    break;
+                }
+            }
+            return !foundNotEmptyValue;
+        }
+
+        public void union(final Map<String, String> fields) {
+            this.fields.putAll(fields);
+        }
+
+        public Map<String, String> getFields() {
+            return this.fields;
+        }
+    }
 }
Index: log4j-core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java
===================================================================
--- log4j-core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java	(revision 1519924)
+++ log4j-core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java	(working copy)
@@ -32,15 +32,15 @@
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.Assert;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
 import static org.junit.Assert.assertTrue;
 
-/**
- *
- */
 public class RFC5424LayoutTest {
     LoggerContext ctx = (LoggerContext) LogManager.getContext();
     Logger root = ctx.getLogger("");
@@ -51,11 +51,11 @@
     private static final String line3 = "ATM - - [RequestContext@3692 loginId=\"JohnDoe\"] filled mdc";
     private static final String line4 =
         "ATM - Audit [Transfer@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"]" +
-        "[RequestContext@18060 ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete";
+        "[RequestContext@3692 ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete";
     private static final String lineEscaped3 = "ATM - - [RequestContext@3692 escaped=\"Testing escaping #012 \\\" \\] \\\"\" loginId=\"JohnDoe\"] filled mdc";
     private static final String lineEscaped4 =
         "ATM - Audit [Transfer@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"]" +
-        "[RequestContext@18060 escaped=\"Testing escaping #012 \\\" \\] \\\"\" ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete";
+        "[RequestContext@3692 escaped=\"Testing escaping #012 \\\" \\] \\\"\" ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete";
 
     static ConfigurationFactory cf = new BasicConfigurationFactory();
 
@@ -247,9 +247,10 @@
             root.removeAppender(appender);
         }
 
-        final LoggerFields loggerFields = LoggerFields.createLoggerFields(new KeyValuePair[] {
-        		new KeyValuePair("source", "%C.%M")
-        });
+        final LoggerFields[] loggerFields = new LoggerFields[] {
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source", "%C.%M")}, null, null, null),
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source2", "%C.%M")}, null, null, null)
+        };
 
         // set up layout/appender
         final AbstractStringLayout layout = RFC5424Layout.createLayout("Local0", "Event", "3692", "true", "RequestContext",
@@ -278,4 +279,134 @@
             appender.stop();
         }
     }
+
+    @Test
+    public void testLoggerFields() {
+        List<String> expectedToContain = Arrays.asList(
+                "[BAZ@32473 baz=\"org.apache.logging.log4j.core.layout.RFC5424LayoutTest.testLoggerFields\"]"  +
+                "[RequestContext@3692 bar=\"org.apache.logging.log4j.core.layout.RFC5424LayoutTest.testLoggerFields\"]" +
+                "[SD-ID@32473 source=\"org.apache.logging.log4j.core.layout.RFC5424LayoutTest.testLoggerFields\"]"
+        );
+
+        for (final Appender appender : root.getAppenders().values()) {
+            root.removeAppender(appender);
+        }
+
+        final LoggerFields[] loggerFields = new LoggerFields[] {
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source", "%C.%M")}, "SD-ID",
+                        "32473", null),
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("baz", "%C.%M"),
+                        new KeyValuePair("baz", "%C.%M") }, "BAZ", "32473", null),
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("bar", "%C.%M")}, null, null, null)
+        };
+
+        final AbstractStringLayout layout = RFC5424Layout.createLayout("Local0", "Event", "3692", "true", "RequestContext",
+                null, null, "true", null, "ATM", null, "key1, key2, locale", null, null, null, loggerFields, null);
+        final ListAppender appender = new ListAppender("List", null, layout, true, false);
+        appender.start();
+
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+
+        root.info("starting logger fields test");
+
+        try {
+
+            final List<String> list = appender.getMessages();
+            assertTrue("Not enough list entries", list.size() > 0);
+            String message =  list.get(0);
+            assertTrue("No class/method", message.contains("RFC5424LayoutTest.testLoggerFields"));
+            for (String value : expectedToContain) {
+                Assert.assertTrue("Not expected message received", message.contains(value));
+            }
+            appender.clear();
+        } finally {
+            root.removeAppender(appender);
+            ThreadContext.clear();
+
+            appender.stop();
+        }
+    }
+
+    @Test
+    public void testDiscardEmptyLoggerFields() {
+        String mdcId = "RequestContext";
+
+        List<String> expectedToContain = Arrays.asList(
+                "[BAZ@32473 baz=\"org.apache.logging.log4j.core.layout.RFC5424LayoutTest.testLoggerFields\"]"  +
+                        "[RequestContext@3692 bar=\"org.apache.logging.log4j.core.layout.RFC5424LayoutTest.testLoggerFields\"]"
+        );
+
+        for (final Appender appender : root.getAppenders().values()) {
+            root.removeAppender(appender);
+        }
+
+        final LoggerFields[] loggerFields = new LoggerFields[] {
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("dummy", ""),
+                        new KeyValuePair("empty", "")}, "SD-ID", "32473", "true"),
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("baz", "%C.%M"),
+                        new KeyValuePair("baz", "%C.%M") }, "BAZ", "32473", "false"),
+                LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("bar", "%C.%M")}, null, null, "false")
+        };
+
+        final AbstractStringLayout layout = RFC5424Layout.createLayout("Local0", "Event", "3692", "true", mdcId,
+                null, null, "true", null, "ATM", null, "key1, key2, locale", null, null, null, loggerFields, null);
+        final ListAppender appender = new ListAppender("List", null, layout, true, false);
+        appender.start();
+
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+
+        root.info("starting logger fields test");
+
+        try {
+
+            final List<String> list = appender.getMessages();
+            assertTrue("Not enough list entries", list.size() > 0);
+            String message =  list.get(0);
+            Assert.assertTrue("SD-ID should have been discarded", !message.contains("SD-ID"));
+            Assert.assertTrue("BAZ should have been included", message.contains("BAZ"));
+            Assert.assertTrue(mdcId + "should have been included", message.contains(mdcId));
+            appender.clear();
+        } finally {
+            root.removeAppender(appender);
+            ThreadContext.clear();
+
+            appender.stop();
+        }
+    }
+
+    @Test
+    public void testSubstituteStructuredData() {
+        String mdcId = "RequestContext";
+
+        String expectedToContain = "ATM - MSG-ID - Message";
+
+        for (final Appender appender : root.getAppenders().values()) {
+            root.removeAppender(appender);
+        }
+
+        final AbstractStringLayout layout = RFC5424Layout.createLayout("Local0", "Event", "3692", "false", mdcId,
+                null, null, "true", null, "ATM", "MSG-ID", "key1, key2, locale", null, null, null, null, null);
+        final ListAppender appender = new ListAppender("List", null, layout, true, false);
+        appender.start();
+
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+
+        root.info("Message");
+
+        try {
+            final List<String> list = appender.getMessages();
+            assertTrue("Not enough list entries", list.size() > 0);
+            String message =  list.get(0);
+            Assert.assertTrue("Not the expected message received", message.contains(expectedToContain));
+            appender.clear();
+        } finally {
+            root.removeAppender(appender);
+            ThreadContext.clear();
+
+            appender.stop();
+        }
+    }
 }
