http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java
 
b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java
new file mode 100644
index 0000000..32776a2
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.xml.parser;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser;
+import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper;
+
+/**
+ * Parses the output from XmlLayout layout into instances of {@link LogEvent}.
+ */
+public class XmlLogEventParser extends AbstractJacksonLogEventParser {
+
+    public XmlLogEventParser() {
+        super(new Log4jXmlObjectMapper());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/site/manual/index.md
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-xml/src/site/manual/index.md 
b/log4j-layout-jackson-xml/src/site/manual/index.md
new file mode 100644
index 0000000..216fe05
--- /dev/null
+++ b/log4j-layout-jackson-xml/src/site/manual/index.md
@@ -0,0 +1,33 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+
+# Apache Log4j Layout for Jackson XML module
+
+As of Log4j 3.0.0, the layout based on Jackson XML has moved from the existing 
module logj-core to the new modules log4j-layout-jackson-xml.
+
+## Requirements
+
+This module was introduced in Log4j 2.11.0 and requires Jackson.
+
+Some features may require optional
+[dependencies](../runtime-dependencies.html). These dependencies are specified 
in the
+documentation for those features.
+
+Some Log4j features require external dependencies.
+See the [Dependency Tree](dependencies.html#Dependency_Tree)
+for the exact list of JAR files needed for these features.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/site/site.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-xml/src/site/site.xml 
b/log4j-layout-jackson-xml/src/site/site.xml
new file mode 100644
index 0000000..6d4cddc
--- /dev/null
+++ b/log4j-layout-jackson-xml/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+
+-->
+<project name="Log4j Core"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 
http://maven.apache.org/xsd/decoration-1.4.0.xsd";>
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/"; />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+       <!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" 
href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" 
/>
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java
new file mode 100644
index 0000000..36e8532
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package org.apache.logging.log4j.jackson.xml;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.LevelMixInTest;
+import org.junit.Ignore;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Ignore("Fails for #testNameOnly()")
+@Category(Layouts.Xml.class)
+public class LevelMixInXmlTest extends LevelMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jXmlObjectMapper();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java
new file mode 100644
index 0000000..b909453
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java
@@ -0,0 +1,34 @@
+/*
+* 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.
+*/
+
+package org.apache.logging.log4j.jackson.xml;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.AbstractMarkerMixInTest;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Category(Layouts.Xml.class)
+public class MarkerMixInXmlTest extends AbstractMarkerMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jXmlObjectMapper(true, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java
new file mode 100644
index 0000000..1d45672
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.xml;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+@Category(Layouts.Json.class)
+public class StackTraceElementXmlMixInTest {
+
+    protected String aposToQuotes(final String json) {
+        return json.replace("'", "\"");
+    }
+
+    private void roundtrip(final ObjectMapper mapper)
+            throws JsonProcessingException, IOException, JsonParseException, 
JsonMappingException {
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java",
+                123);
+        final String s = mapper.writeValueAsString(expected);
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFromJsonWithLog4jModule() throws Exception {
+        final ObjectMapper mapper = new ObjectMapper();
+        final boolean encodeThreadContextAsList = false;
+        final Log4jXmlModule module = new Log4jXmlModule(true, false);
+        module.addDeserializer(StackTraceElement.class, new 
Log4jStackTraceElementDeserializer());
+        mapper.registerModule(module);
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java",
+                123);
+        final String s = this
+                
.aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}");
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFromJsonWithSimpleModule() throws Exception {
+        final ObjectMapper mapper = new ObjectMapper();
+        final SimpleModule module = new SimpleModule();
+        module.addDeserializer(StackTraceElement.class, new 
Log4jStackTraceElementDeserializer());
+        mapper.registerModule(module);
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java",
+                123);
+        final String s = this
+                
.aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}");
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testLog4jXmlObjectMapper() throws Exception {
+        this.roundtrip(new Log4jXmlObjectMapper());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java
new file mode 100644
index 0000000..afbff8a
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.xml.layout;
+
+import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+/**
+ * Like the test for LOG4J2-1769.
+ */
+public class ConcurrentLoggingWithXmlLayoutTest {
+
+    private class LoggingThread extends Thread {
+        private final Set<Thread> threads;
+        private final Logger log;
+
+        LoggingThread(final Set<Thread> threads, final Logger log) {
+            this.threads = threads;
+            this.log = log;
+        }
+
+        @Override
+        public void run() {
+            log.info(threads.size());
+            try {
+                for (int i = 0; i < 64; i++) {
+                    log.info("First message.");
+                    log.info("Second message.");
+                }
+            } finally {
+                threads.remove(this);
+            }
+        }
+    }
+
+    @ClassRule
+    public static LoggerContextRule context = new 
LoggerContextRule("log4j2-xml-layout.xml");
+
+    private static final String PATH = "target/test-xml-layout.log";
+
+    @AfterClass
+    public static void after() {
+        new File(PATH).delete();
+    }
+
+    @Test
+    public void testConcurrentLogging() throws Throwable {
+        final Logger log = 
context.getLogger(ConcurrentLoggingWithXmlLayoutTest.class);
+        final Set<Thread> threads = Collections.synchronizedSet(new 
HashSet<Thread>());
+        final List<Throwable> thrown = Collections.synchronizedList(new 
ArrayList<Throwable>());
+
+        for (int x = 0; x < Runtime.getRuntime().availableProcessors() * 2; 
x++) {
+            final Thread t = new LoggingThread(threads, log);
+            threads.add(t);
+
+            // Appender is configured with ignoreExceptions="false";
+            // any exceptions are propagated to the caller, so we can catch 
them here.
+            t.setUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(final Thread t, final Throwable 
e) {
+                    thrown.add(e);
+                }
+            });
+            t.start();
+        }
+
+        while (!threads.isEmpty()) {
+            log.info("not done going to sleep...");
+            Thread.sleep(10);
+        }
+
+        // if any error occurred, fail this test
+        if (!thrown.isEmpty()) {
+            throw thrown.get(0);
+        }
+
+        // simple test to ensure content is not corrupted
+        if (new File(PATH).exists()) {
+            final List<String> lines = Files.readAllLines(new 
File(PATH).toPath(), Charset.defaultCharset());
+            for (final String line : lines) {
+                assertThat(line, startsWith("<Event "));
+                assertThat(line, endsWith("</Event>"));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java
new file mode 100644
index 0000000..7fb9177
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package org.apache.logging.log4j.jackson.xml.layout;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.jackson.ThrowableProxyJacksonTest;
+import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper;
+import org.junit.Test;
+
+public class ThrowableProxyXmlTest extends ThrowableProxyJacksonTest {
+
+    @Test
+    public void testIoContainerAsXml() throws IOException {
+        testIoContainer(new Log4jXmlObjectMapper());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
new file mode 100644
index 0000000..5323163
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.xml.layout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.BasicConfigurationFactory;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.LogEventFixtures;
+import org.apache.logging.log4j.core.lookup.JavaLookup;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.jackson.XmlConstants;
+import org.apache.logging.log4j.jackson.xml.AbstractLogEventXmlMixIn;
+import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper;
+import org.apache.logging.log4j.junit.ThreadContextRule;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+/**
+ * Tests {@link XmlLayout}.
+ */
+@Category(Layouts.Xml.class)
+public class XmlLayoutTest {
+    private static final int NOT_FOUND = -1;
+    private static final String body = "<Message>empty mdc</Message>";
+    static ConfigurationFactory cf = new BasicConfigurationFactory();
+    private static final String markerTag = "<Marker name=\"EVENT\"/>";
+
+    @AfterClass
+    public static void cleanupClass() {
+        ConfigurationFactory.removeConfigurationFactory(cf);
+    }
+
+    @BeforeClass
+    public static void setupClass() {
+        ConfigurationFactory.setConfigurationFactory(cf);
+        final LoggerContext ctx = LoggerContext.getContext();
+        ctx.reconfigure();
+    }
+
+    @Rule
+    public final ThreadContextRule threadContextRule = new ThreadContextRule();
+
+    LoggerContext ctx = LoggerContext.getContext();
+
+    Logger rootLogger = this.ctx.getRootLogger();
+
+    private void checkAttribute(final String name, final String value, final 
boolean compact, final String str) {
+        Assert.assertTrue(str, str.contains(name + "=\"" + value + "\""));
+    }
+
+    private void checkAttributeName(final String name, final boolean compact, 
final String str) {
+        Assert.assertTrue(str, str.contains(name + "=\""));
+    }
+
+    private void checkContains(final String expected, final List<String> list) 
{
+        for (final String string : list) {
+            final String trimedLine = string.trim();
+            if (trimedLine.contains(expected)) {
+                return;
+            }
+        }
+        Assert.fail("Cannot find " + expected + " in " + list);
+    }
+
+    private void checkContextMapElement(final String key, final String value, 
final boolean compact, final String str) {
+        // <item key="MDC.A" value="A_Value"/>
+        assertTrue(str, str.contains(String.format("<item key=\"%s\" 
value=\"%s\"/>", key, value)));
+    }
+
+    private void checkContextStackElement(final String value, final boolean 
compact, final String str) {
+        // <ContextStackItem>stack_msg1</ContextStackItem>
+        assertTrue(str, 
str.contains(String.format("<ContextStackItem>%s</ContextStackItem>", value)));
+    }
+
+    private void checkElementName(final String name, final boolean compact, 
final String str,
+            final boolean withAttributes, final boolean withChildren) {
+        // simple checks, don't try to be too smart here, we're just looking 
for the names and basic shape.
+        // start
+        final String startStr = withAttributes ? "<" + name + " " : "<" + name 
+ ">";
+        final int startPos = str.indexOf(startStr);
+        Assert.assertTrue(String.format("Missing text '%s' in: %s", startStr, 
str), startPos >= 0);
+        // end
+        final String endStr = withChildren ? "</" + name + ">" : "/>";
+        final int endPos = str.indexOf(endStr, startPos + startStr.length());
+        Assert.assertTrue(str, endPos >= 0);
+    }
+
+    private void checkElementNameAbsent(final String name, final boolean 
compact, final String str) {
+        Assert.assertFalse(str.contains("<" + name));
+    }
+
+    private void checkJsonPropertyOrder(final boolean includeContextStack, 
final boolean includeContextMap,
+            final boolean includeStacktrace, final String str) {
+        final JsonPropertyOrder annotation = 
AbstractLogEventXmlMixIn.class.getAnnotation(JsonPropertyOrder.class);
+        Assert.assertNotNull(annotation);
+        int previousIndex = 0;
+        String previousName = null;
+        for (final String name : annotation.value()) {
+            final int currentIndex = str.indexOf(name);
+            if (!includeContextStack && 
XmlConstants.ELT_CONTEXT_STACK.equals(name)) {
+                Assert.assertTrue(String.format("Unexpected element '%s' in: 
%s", name, str),
+                        currentIndex == NOT_FOUND);
+                break;
+            }
+            if (!includeContextMap && 
XmlConstants.ELT_CONTEXT_MAP.equals(name)) {
+                Assert.assertTrue(String.format("Unexpected element '%s' in: 
%s", name, str),
+                        currentIndex == NOT_FOUND);
+                break;
+            }
+            if (!includeStacktrace && 
XmlConstants.ELT_EXTENDED_STACK_TRACE.equals(name)) {
+                Assert.assertTrue(String.format("Unexpected element '%s' in: 
%s", name, str),
+                        currentIndex == NOT_FOUND);
+                break;
+            }
+            if (!includeStacktrace && 
XmlConstants.ELT_EXTENDED_STACK_TRACE_ITEM.equals(name)) {
+                Assert.assertTrue(String.format("Unexpected element '%s' in: 
%s", name, str),
+                        currentIndex == NOT_FOUND);
+                break;
+            }
+            // TODO
+            // Bug: The method
+            // 
com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._sortProperties(Map<String,
+            // POJOPropertyBuilder>) messes up the order defined in 
AbstractXmlLogEventMixIn's JsonPropertyOrder
+            // annotations.
+            // Assert.assertTrue(String.format("name='%s', previousIndex=%,d, 
previousName='%s', currentIndex=%,d: %s",
+            // name, previousIndex, previousName, currentIndex, str), 
previousIndex < currentIndex);
+            previousIndex = currentIndex;
+            previousName = name;
+        }
+    }
+
+    private String prepareXMLForStacktraceTests(final boolean 
stacktraceAsString) {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        // @formatter:off
+        final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+                .setCompact(true)
+                .setIncludeStacktrace(true)
+                .setStacktraceAsString(stacktraceAsString)
+                .build();
+        // @formatter:off
+        return layout.toSerializable(expected);
+    }
+
+    @Test
+    public void testAdditionalFields() throws Exception {
+        final AbstractJacksonLayout layout = 
XmlLayout.newBuilder().setLocationInfo(false).setProperties(false)
+                .setIncludeStacktrace(false)
+                .setAdditionalFields(new KeyValuePair[] { new 
KeyValuePair("KEY1", "VALUE1"),
+                        new KeyValuePair("KEY2", "${java:runtime}"), })
+                
.setCharset(StandardCharsets.UTF_8).setConfiguration(ctx.getConfiguration()).build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertTrue(str, str.contains("<KEY1>VALUE1</KEY1>"));
+        assertTrue(str, str.contains("<KEY2>" + new JavaLookup().getRuntime() 
+ "</KEY2>"));
+    }
+
+    /**
+     * @param includeLocationInfo
+     *            TODO
+     * @param compact
+     * @param includeContextMap
+     *            TODO
+     * @param includeContextStack
+     *            TODO
+     * @throws IOException
+     * @throws JsonParseException
+     * @throws JsonMappingException
+     */
+    private void testAllFeatures(final boolean includeLocationInfo, final 
boolean compact,
+            final boolean includeContextMap, final boolean 
includeContextStack, final boolean includeStacktrace)
+            throws IOException, JsonParseException, JsonMappingException {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        // @formatter:off
+        final XmlLayout layout = XmlLayout.newBuilder()
+                .setLocationInfo(includeLocationInfo)
+                .setProperties(includeContextMap)
+                .setComplete(false)
+                .setCompact(compact)
+                .setIncludeStacktrace(includeStacktrace)
+                .setCharset(StandardCharsets.UTF_8)
+                .build();
+        final String str = layout.toSerializable(expected);
+        // @formatter:on
+        // System.out.println(str);
+        assertEquals(str, !compact, str.contains("\n"));
+        assertEquals(str, includeLocationInfo, str.contains("Source"));
+        assertEquals(str, includeContextMap, str.contains("ContextMap"));
+        final Log4jLogEvent actual = new Log4jXmlObjectMapper().readValue(str, 
Log4jLogEvent.class);
+        LogEventFixtures.assertEqualLogEvents(expected, actual, 
includeLocationInfo, includeContextMap,
+                includeStacktrace);
+        if (includeContextMap) {
+            this.checkContextMapElement("MDC.A", "A_Value", compact, str);
+            this.checkContextMapElement("MDC.B", "B_Value", compact, str);
+        }
+        if (includeContextStack) {
+            this.checkContextStackElement("stack_msg1", compact, str);
+            this.checkContextStackElement("stack_msg2", compact, str);
+        }
+
+        //
+        assertNull(actual.getThrown());
+        // check some attrs
+        assertTrue(str, str.contains("loggerFqcn=\"f.q.c.n\""));
+        assertTrue(str, str.contains("loggerName=\"a.B\""));
+        // make sure short names are used
+        assertTrue(str, str.contains("<Event "));
+        if (includeStacktrace) {
+            assertTrue("Missing \"class=\" in: " + str, 
str.contains("class="));
+            assertTrue("Missing \"method=\" in: " + str, 
str.contains("method="));
+            assertTrue("Missing \"file=\" in: " + str, str.contains("file="));
+            assertTrue("Missing \"line=\" in: " + str, str.contains("line="));
+        }
+        //
+        // make sure the names we want are used
+        // this.checkAttributeName("timeMillis", compact, str);
+        this.checkElementName("Instant", compact, str, true, false);
+        this.checkAttributeName("epochSecond", compact, str);
+        this.checkAttributeName("nanoOfSecond", compact, str);
+        this.checkAttributeName("thread", compact, str); // and not threadName
+        this.checkAttributeName("level", compact, str);
+        this.checkAttributeName("loggerName", compact, str);
+        this.checkElementName("Marker", compact, str, true, true);
+        this.checkAttributeName("name", compact, str);
+        this.checkElementName("Parents", compact, str, false, true);
+        this.checkElementName("Message", compact, str, false, true);
+        this.checkElementName("Thrown", compact, str, true, true);
+        this.checkElementName("Cause", compact, str, true, includeStacktrace);
+        this.checkAttributeName("commonElementCount", compact, str);
+        this.checkAttributeName("message", compact, str);
+        this.checkAttributeName("localizedMessage", compact, str);
+        if (includeStacktrace) {
+            this.checkElementName("ExtendedStackTrace", compact, str, false, 
true);
+            this.checkAttributeName("class", compact, str);
+            this.checkAttributeName("method", compact, str);
+            this.checkAttributeName("file", compact, str);
+            this.checkAttributeName("line", compact, str);
+            this.checkAttributeName("exact", compact, str);
+            this.checkAttributeName("location", compact, str);
+            this.checkAttributeName("version", compact, str);
+        } else {
+            this.checkElementNameAbsent("ExtendedStackTrace", compact, str);
+        }
+        this.checkElementName("Suppressed", compact, str, false, true);
+        this.checkAttributeName("loggerFqcn", compact, str);
+        this.checkAttributeName("endOfBatch", compact, str);
+        if (includeContextMap) {
+            this.checkElementName("ContextMap", compact, str, false, true);
+        } else {
+            this.checkElementNameAbsent("ContextMap", compact, str);
+        }
+        this.checkElementName("ContextStack", compact, str, false, true);
+        if (includeLocationInfo) {
+            this.checkElementName("Source", compact, str, true, false);
+        } else {
+            this.checkElementNameAbsent("Source", compact, str);
+        }
+        // check some attrs
+        this.checkAttribute("loggerFqcn", "f.q.c.n", compact, str);
+        this.checkAttribute("loggerName", "a.B", compact, str);
+        this.checkJsonPropertyOrder(includeContextStack, includeContextMap, 
includeStacktrace, str);
+    }
+
+    @Test
+    public void testContentType() {
+        final XmlLayout layout = XmlLayout.createDefaultLayout();
+        assertEquals("text/xml; charset=UTF-8", layout.getContentType());
+    }
+
+    @Test
+    public void testDefaultCharset() {
+        final XmlLayout layout = XmlLayout.createDefaultLayout();
+        assertEquals(StandardCharsets.UTF_8, layout.getCharset());
+    }
+
+    @Test
+    public void testExcludeStacktrace() throws Exception {
+        this.testAllFeatures(false, false, false, false, false);
+    }
+
+    @Test
+    public void testIncludeNullDelimiterFalse() throws Exception {
+        final AbstractJacksonLayout layout = 
XmlLayout.newBuilder().setCompact(true).setIncludeNullDelimiter(false)
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertFalse(str.endsWith("\0"));
+    }
+
+    @Test
+    public void testIncludeNullDelimiterTrue() throws Exception {
+        final AbstractJacksonLayout layout = 
XmlLayout.newBuilder().setCompact(true).setIncludeNullDelimiter(true)
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertTrue(str.endsWith("\0"));
+    }
+
+    /**
+     * Test case for MDC conversion pattern.
+     */
+    @Test
+    public void testLayout() throws Exception {
+        final Map<String, Appender> appenders = this.rootLogger.getAppenders();
+        for (final Appender appender : appenders.values()) {
+            this.rootLogger.removeAppender(appender);
+        }
+        // set up appender
+        final XmlLayout layout = 
XmlLayout.newBuilder().setLocationInfo(true).setProperties(true).setComplete(true)
+                .setCompact(false).setIncludeStacktrace(true).build();
+
+        final ListAppender appender = new ListAppender("List", null, layout, 
true, false);
+        appender.start();
+
+        // set appender on root and set level to debug
+        this.rootLogger.addAppender(appender);
+        this.rootLogger.setLevel(Level.DEBUG);
+
+        // output starting message
+        this.rootLogger.debug("starting mdc pattern test");
+
+        this.rootLogger.debug("empty mdc");
+
+        ThreadContext.put("key1", "value1");
+        ThreadContext.put("key2", "value2");
+
+        this.rootLogger.debug("filled mdc");
+
+        ThreadContext.remove("key1");
+        ThreadContext.remove("key2");
+
+        this.rootLogger.error("finished mdc pattern test", new 
NullPointerException("test"));
+
+        final Marker marker = MarkerManager.getMarker("EVENT");
+        this.rootLogger.error(marker, "marker test");
+
+        appender.stop();
+
+        final List<String> list = appender.getMessages();
+
+        final String string = list.get(0);
+        assertTrue("Incorrect header: " + string, string.equals("<?xml 
version=\"1.0\" encoding=\"UTF-8\"?>"));
+        assertTrue("Incorrect footer", list.get(list.size() - 
1).equals("</Events>"));
+        this.checkContains("loggerFqcn=\"" + AbstractLogger.class.getName() + 
"\"", list);
+        this.checkContains("level=\"DEBUG\"", list);
+        this.checkContains(">starting mdc pattern test</Message>", list);
+        // this.checkContains("<Message>starting mdc pattern test</Message>", 
list);
+
+        // <Marker xmlns="" 
_class="org.apache.logging.log4j.MarkerManager..Log4jMarker" name="EVENT"/>
+        this.checkContains("<Marker", list);
+        this.checkContains("name=\"EVENT\"/>", list);
+
+        for (final Appender app : appenders.values()) {
+            this.rootLogger.addAppender(app);
+        }
+    }
+
+    @Test
+    public void testLayoutLoggerName() {
+        final XmlLayout layout = 
XmlLayout.newBuilder().setLocationInfo(false).setProperties(true).setComplete(true)
+                .setCompact(false).setIncludeStacktrace(true).build();
+
+        final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
+                .setLoggerName("a.B") //
+                .setLoggerFqcn("f.q.c.n") //
+                .setLevel(Level.DEBUG) //
+                .setMessage(new SimpleMessage("M")) //
+                .setThreadName("threadName") //
+                .setTimeMillis(1).build();
+        final String str = layout.toSerializable(event);
+        assertTrue(str, str.contains("loggerName=\"a.B\""));
+    }
+
+    @Test
+    public void testLocationOffCompactOffMdcOff() throws Exception {
+        this.testAllFeatures(false, false, false, false, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOnMdcOn() throws Exception {
+        this.testAllFeatures(true, true, true, true, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOnNdcOn() throws Exception {
+        this.testAllFeatures(false, false, false, true, false);
+    }
+
+    @Test
+    public void testStacktraceAsNonString() throws Exception {
+        final String str = prepareXMLForStacktraceTests(false);
+        assertTrue(str, 
str.contains("<ExtendedStackTrace><ExtendedStackTraceItem"));
+    }
+
+    @Test
+    public void testStacktraceAsString() throws Exception {
+        final String str = prepareXMLForStacktraceTests(true);
+        assertTrue(str, 
str.contains("<ExtendedStackTrace>java.lang.NullPointerException"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java
 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java
new file mode 100644
index 0000000..93e30b5
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.xml.parser;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.parser.AbstractLogEventParserTest;
+import org.apache.logging.log4j.core.parser.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class XmlLogEventParserTest extends AbstractLogEventParserTest {
+
+    private static final String XML = "<Event 
xmlns=\"http://logging.apache.org/log4j/2.0/events\"\n"; +
+            "       timeMillis=\"1493121664118\"\n" +
+            "       level=\"INFO\"\n" +
+            "       loggerName=\"HelloWorld\"\n" +
+            "       endOfBatch=\"false\"\n" +
+            "       thread=\"main\"\n" +
+            "       
loggerFqcn=\"org.apache.logging.log4j.spi.AbstractLogger\"\n" +
+            "       threadId=\"1\"\n" +
+            "       threadPriority=\"5\">\n" +
+            "  <Instant epochSecond=\"1493121664\" 
nanoOfSecond=\"118000000\"/>\n" +
+            "  <Marker name=\"child\">\n" +
+            "    <Parents>\n" +
+            "      <Marker name=\"parent\">\n" +
+            "        <Parents>\n" +
+            "          <Marker name=\"grandparent\"/>\n" +
+            "        </Parents>\n" +
+            "      </Marker>\n" +
+            "    </Parents>\n" +
+            "  </Marker>\n" +
+            "  <Message>Hello, world!</Message>\n" +
+            "  <ContextMap>\n" +
+            "    <item key=\"bar\" value=\"BAR\"/>\n" +
+            "    <item key=\"foo\" value=\"FOO\"/>\n" +
+            "  </ContextMap>\n" +
+            "  <ContextStack>\n" +
+            "    <ContextStackItem>one</ContextStackItem>\n" +
+            "    <ContextStackItem>two</ContextStackItem>\n" +
+            "  </ContextStack>\n" +
+            "  <Source\n" +
+            "      class=\"logtest.Main\"\n" +
+            "      method=\"main\"\n" +
+            "      file=\"Main.java\"\n" +
+            "      line=\"29\"/>\n" +
+            "  <Thrown commonElementCount=\"0\" message=\"error message\" 
name=\"java.lang.RuntimeException\">\n" +
+            "    <ExtendedStackTrace>\n" +
+            "      <ExtendedStackTraceItem\n" +
+            "          class=\"logtest.Main\"\n" +
+            "          method=\"main\"\n" +
+            "          file=\"Main.java\"\n" +
+            "          line=\"29\"\n" +
+            "          exact=\"true\"\n" +
+            "          location=\"classes/\"\n" +
+            "          version=\"?\"/>\n" +
+            "    </ExtendedStackTrace>\n" +
+            "  </Thrown>\n" +
+            "</Event>";
+
+    private XmlLogEventParser parser;
+
+    @Before
+    public void setup() {
+        parser = new XmlLogEventParser();
+    }
+
+    @Test
+    public void testByteArray() throws ParseException {
+        final LogEvent logEvent = 
parser.parseFrom(XML.getBytes(StandardCharsets.UTF_8));
+        assertLogEvent(logEvent);
+    }
+
+    @Test
+    public void testByteArrayOffsetLength() throws ParseException {
+        final byte[] bytes = ("abc" + XML + 
"def").getBytes(StandardCharsets.UTF_8);
+        final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6);
+        assertLogEvent(logEvent);
+    }
+
+    @Test
+    public void testEmptyObject() throws ParseException {
+        parser.parseFrom("<Event></Event>");
+    }
+
+    @Test
+    public void testString() throws ParseException {
+        final LogEvent logEvent = parser.parseFrom(XML);
+        assertLogEvent(logEvent);
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringEmpty() throws ParseException {
+        parser.parseFrom("");
+    }
+
+    @Test
+    public void testStringIgnoreInvalidProperty() throws ParseException {
+        parser.parseFrom("<Event><foo>bar</foo></Event>");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringInvalidXml() throws ParseException {
+        parser.parseFrom("foobar");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringWrongPropertyType() throws ParseException {
+        parser.parseFrom("<Event><Instant 
epochSecond=\"bar\">foobar</Instant></Event>");
+    }
+
+    @Test
+    public void testTimeMillisIgnored() throws ParseException {
+        parser.parseFrom("<Event><timeMillis>foobar</timeMillis></Event>");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml 
b/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml
new file mode 100644
index 0000000..f0b1709
--- /dev/null
+++ b/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml
@@ -0,0 +1,31 @@
+<?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.
+
+-->
+<Configuration status="INFO" packages="">
+  <Appenders>
+    <File name="stdout" ignoreExceptions="false" 
fileName="target/test-xml-layout.log" append="false">
+      <XmlLayout compact="true" eventEol="true" />
+    </File>
+  </Appenders>
+
+  <Loggers>
+    <Root level="INFO">
+      <AppenderRef ref="stdout" />
+    </Root>
+  </Loggers>
+</Configuration>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-yaml/pom.xml 
b/log4j-layout-jackson-yaml/pom.xml
new file mode 100644
index 0000000..9df9743
--- /dev/null
+++ b/log4j-layout-jackson-yaml/pom.xml
@@ -0,0 +1,171 @@
+<?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. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <parent>
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>log4j-layout-jackson-yaml</artifactId>
+  <name>Apache Log4j Layout for Jackson YAML</name>
+  <description>
+    Apache Log4j Layout for Jackson YAML.
+  </description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>Log4j Layout for Jackson YAML Documentation</docLabel>
+    <projectDir>/log4j-layout-yaml</projectDir>
+    <module.name>org.apache.logging.log4j.jackson.yaml</module.name>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-layout-jackson</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-yaml</artifactId>
+    </dependency>
+    <!-- Test Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <type>test-jar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <type>test-jar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-layout-jackson</artifactId>
+      <type>test-jar</type>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            
<Fragment-Host>org.apache.logging.log4j.jackson.yaml</Fragment-Host>
+            <Export-Package>*</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <version>${changes.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+          <useJql>true</useJql>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.plugin.version}</version>
+        <configuration>
+          
<!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
 -->
+          <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+          
<suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+          <enableRulesSummary>false</enableRulesSummary>
+          <propertyExpansion>basedir=${basedir}</propertyExpansion>
+          
<propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>${javadoc.plugin.version}</version>
+        <configuration>
+          <bottom><![CDATA[<p align="center">Copyright &#169; 
{inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+            Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather 
logo, the Apache Logging project logo,
+            and the Apache Log4j logo are trademarks of The Apache Software 
Foundation.</p>]]></bottom>
+          <!-- module link generation is completely broken in the javadoc 
plugin for a multi-module non-aggregating project -->
+          <detectOfflineLinks>false</detectOfflineLinks>
+          <linksource>true</linksource>
+        </configuration>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+        <version>${findbugs.plugin.version}</version>
+        <configuration>
+          <fork>true</fork>
+          <jvmArgs>-Duser.language=en</jvmArgs>
+          <threshold>Normal</threshold>
+          <effort>Default</effort>
+          
<excludeFilterFile>${log4jParentDir}/findbugs-exclude-filter.xml</excludeFilterFile>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>${jxr.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>jxr</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <version>${pmd.plugin.version}</version>
+        <configuration>
+          <targetJdk>${maven.compiler.target}</targetJdk>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java
new file mode 100644
index 0000000..8446a9d
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.yaml;
+
+import org.apache.logging.log4j.jackson.SetupContextInitializer;
+import org.apache.logging.log4j.jackson.SimpleModuleInitializer;
+
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+final class Log4jYamlModule extends SimpleModule {
+
+    private static final long serialVersionUID = 1L;
+    private final boolean encodeThreadContextAsList;
+    private final boolean includeStacktrace;
+    private final boolean stacktraceAsString;
+
+    Log4jYamlModule(final boolean encodeThreadContextAsList, final boolean 
includeStacktrace,
+            final boolean stacktraceAsString) {
+        super(Log4jYamlModule.class.getName(), new Version(2, 0, 0, null, 
null, null));
+        this.encodeThreadContextAsList = encodeThreadContextAsList;
+        this.includeStacktrace = includeStacktrace;
+        this.stacktraceAsString = stacktraceAsString;
+        // MUST call initialize() here.
+        // Calling this from setupModule is too late!
+        // noinspection ThisEscapedInObjectConstruction
+        new SimpleModuleInitializer().initialize(this, false);
+    }
+
+    @Override
+    public void setupModule(final SetupContext context) {
+        // MUST call super here.
+        super.setupModule(context);
+        if (encodeThreadContextAsList) {
+            new SetupContextInitializer().setupModule(context, 
includeStacktrace, stacktraceAsString);
+        } else {
+            new YamlSetupContextInitializer().setupModule(context, 
includeStacktrace, stacktraceAsString);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java
new file mode 100644
index 0000000..62c6483
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.yaml;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+
+/**
+ * A Jackson {@link ObjectMapper} initialized for Log4j.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class Log4jYamlObjectMapper extends YAMLMapper {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new instance using the {@link Log4jYamlModule}.
+     */
+    public Log4jYamlObjectMapper() {
+        this(false, true, false);
+    }
+
+    /**
+     * Create a new instance using the {@link Log4jYamlModule}.
+     */
+    public Log4jYamlObjectMapper(final boolean encodeThreadContextAsList, 
final boolean includeStacktrace, final boolean stacktraceAsString) {
+        this.registerModule(new Log4jYamlModule(encodeThreadContextAsList, 
includeStacktrace, stacktraceAsString));
+        this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java
new file mode 100644
index 0000000..67f6fd1
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java
@@ -0,0 +1,47 @@
+package org.apache.logging.log4j.jackson.yaml;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
+import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.time.Instant;
+import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn;
+import org.apache.logging.log4j.jackson.InstantMixIn;
+import org.apache.logging.log4j.jackson.LevelMixIn;
+import org.apache.logging.log4j.jackson.LogEventJsonMixIn;
+import org.apache.logging.log4j.jackson.MarkerMixIn;
+import org.apache.logging.log4j.jackson.StackTraceElementMixIn;
+import org.apache.logging.log4j.jackson.ThrowableProxyMixIn;
+import 
org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn;
+import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn;
+
+import com.fasterxml.jackson.databind.Module.SetupContext;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+/**
+ * Used to set up {@link SetupContext} from different {@link SimpleModule}s.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+class YamlSetupContextInitializer {
+
+    public void setupModule(final SetupContext context, final boolean 
includeStacktrace,
+            final boolean stacktraceAsString) {
+        // JRE classes: we cannot edit those with Jackson annotations
+        context.setMixInAnnotations(StackTraceElement.class, 
StackTraceElementMixIn.class);
+        // Log4j API classes: we do not want to edit those with Jackson 
annotations because the API module should not
+        // depend on Jackson.
+        context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
+        context.setMixInAnnotations(Level.class, LevelMixIn.class);
+        context.setMixInAnnotations(Instant.class, InstantMixIn.class);
+        context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); 
// different ThreadContext handling
+        // Log4j Core classes: we do not want to bring in Jackson at runtime 
if we do not have to.
+        context.setMixInAnnotations(ExtendedStackTraceElement.class, 
ExtendedStackTraceElementMixIn.class);
+        context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace
+                ? (stacktraceAsString ? 
ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class)
+                : ThrowableProxyWithoutStacktraceMixIn.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java
new file mode 100644
index 0000000..856a201
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package org.apache.logging.log4j.jackson.yaml.layout;
+
+public class YamlConstants {
+
+    static final String EVENT = "event";
+    static final String ELT_CAUSE = "cause";
+    static final String ELT_CONTEXT_MAP = "contextMap";
+    static final String ELT_CONTEXT_STACK = "contextStack";
+    static final String ELT_MARKER = "marker";
+    static final String ELT_PARENTS = "parents";
+    static final String ELT_SOURCE = "source";
+    static final String ELT_SUPPRESSED = "suppressed";
+    static final String ELT_THROWN = "thrown";
+    static final String ELT_MESSAGE = "message";
+    static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
+    static final String ELT_NANO_TIME = "nanoTime";
+    static final String ELT_INSTANT = "instant";
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java
new file mode 100644
index 0000000..e32041a
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package org.apache.logging.log4j.jackson.yaml.layout;
+
+import org.apache.logging.log4j.jackson.AbstractJacksonFactory;
+import org.apache.logging.log4j.jackson.yaml.Log4jYamlObjectMapper;
+
+import com.fasterxml.jackson.core.PrettyPrinter;
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+class YamlJacksonFactory extends AbstractJacksonFactory {
+
+    public YamlJacksonFactory(final boolean includeStacktrace, final boolean 
stacktraceAsString) {
+        super(includeStacktrace, stacktraceAsString);
+    }
+
+    @Override
+    protected String getPropertyNameForContextMap() {
+        return YamlConstants.ELT_CONTEXT_MAP;
+    }
+
+    @Override
+    protected String getPropertyNameForNanoTime() {
+        return YamlConstants.ELT_NANO_TIME;
+    }
+
+    @Override
+    protected String getPropertyNameForSource() {
+        return YamlConstants.ELT_SOURCE;
+    }
+
+    @Override
+    protected String getPropertyNameForStackTrace() {
+        return YamlConstants.ELT_EXTENDED_STACK_TRACE;
+    }
+
+    @Override
+    protected PrettyPrinter newCompactPrinter() {
+        return new MinimalPrettyPrinter();
+    }
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jYamlObjectMapper(false, includeStacktrace, 
stacktraceAsString);
+    }
+
+    @Override
+    protected PrettyPrinter newPrettyPrinter() {
+        return new DefaultPrettyPrinter();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
new file mode 100644
index 0000000..418ef9a
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+package org.apache.logging.log4j.jackson.yaml.layout;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.util.Strings;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+/**
+ * Appends a series of YAML events as strings serialized as bytes.
+ *
+ * <h3>Encoding</h3>
+ * <p>
+ * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise
+ * events containing non ASCII characters could result in corrupted log files.
+ * </p>
+ * <h3>Additional Fields</h3>
+ * <p>
+ * This property allows addition of custom fields into generated JSON.
+ * {@code <YamlLayout><KeyValuePair key="foo" value="bar"/></YamlLayout>} 
inserts {@code foo: "bar"} directly into YAML
+ * output. Supports Lookup expressions.
+ * </p>
+ */
+@Plugin(name = "YamlLayout", category = Node.CATEGORY, elementType = 
Layout.ELEMENT_TYPE, printObject = true)
+public final class YamlLayout extends AbstractJacksonLayout {
+
+    public static class Builder<B extends Builder<B>> extends 
AbstractJacksonLayout.Builder<B>
+            implements org.apache.logging.log4j.core.util.Builder<YamlLayout> {
+
+        public Builder() {
+            super();
+            setCharset(StandardCharsets.UTF_8);
+        }
+
+        @Override
+        public YamlLayout build() {
+            final String headerPattern = toStringOrNull(getHeader());
+            final String footerPattern = toStringOrNull(getFooter());
+            return new YamlLayout(getConfiguration(), isLocationInfo(), 
isProperties(), isComplete(), isCompact(),
+                    getEventEol(), headerPattern, footerPattern, getCharset(), 
isIncludeStacktrace(),
+                    isStacktraceAsString(), isIncludeNullDelimiter(), 
getAdditionalFields());
+        }
+    }
+
+    @JsonRootName(YamlConstants.EVENT)
+    public static class YamlLogEventWithAdditionalFields extends 
LogEventWithAdditionalFields {
+
+        public YamlLogEventWithAdditionalFields(final Object logEvent, final 
Map<String, String> additionalFields) {
+            super(logEvent, additionalFields);
+        }
+
+        @Override
+        @JsonAnyGetter
+        public Map<String, String> getAdditionalFields() {
+            return super.getAdditionalFields();
+        }
+
+        @Override
+        @JsonUnwrapped
+        public Object getLogEvent() {
+            return super.getLogEvent();
+        }
+
+    }
+
+    private static final String DEFAULT_FOOTER = Strings.EMPTY;
+
+    private static final String DEFAULT_HEADER = Strings.EMPTY;
+
+    static final String CONTENT_TYPE = "application/yaml";
+
+    /**
+     * Creates a YAML Layout using the default settings. Useful for testing.
+     *
+     * @return A YAML Layout.
+     */
+    public static AbstractJacksonLayout createDefaultLayout() {
+        return new YamlLayout(new DefaultConfiguration(), false, false, false, 
false, false, DEFAULT_HEADER,
+                DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, 
null);
+    }
+
+    /**
+     * Creates a YAML Layout.
+     *
+     * @param config
+     *            The plugin configuration.
+     * @param locationInfo
+     *            If "true", includes the location information in the 
generated YAML.
+     * @param properties
+     *            If "true", includes the thread context map in the generated 
YAML.
+     * @param headerPattern
+     *            The header pattern, defaults to {@code ""} if null.
+     * @param footerPattern
+     *            The header pattern, defaults to {@code ""} if null.
+     * @param charset
+     *            The character set to use, if {@code null}, uses "UTF-8".
+     * @param includeStacktrace
+     *            If "true", includes the stacktrace of any Throwable in the 
generated YAML, defaults to "true".
+     * @return A YAML Layout.
+     *
+     * @deprecated Use {@link #newBuilder()} instead
+     */
+    @Deprecated
+    public static AbstractJacksonLayout createLayout(final Configuration 
config, final boolean locationInfo,
+            final boolean properties, final String headerPattern, final String 
footerPattern, final Charset charset,
+            final boolean includeStacktrace) {
+        return new YamlLayout(config, locationInfo, properties, false, false, 
true, headerPattern, footerPattern,
+                charset, includeStacktrace, false, false, null);
+    }
+
+    @PluginBuilderFactory
+    public static <B extends Builder<B>> B newBuilder() {
+        return new Builder<B>().asBuilder();
+    }
+
+    /**
+     * @deprecated Use {@link #newBuilder()} instead
+     */
+    @Deprecated
+    protected YamlLayout(final Configuration config, final boolean 
locationInfo, final boolean properties,
+            final boolean complete, final boolean compact, final boolean 
eventEol, final String headerPattern,
+            final String footerPattern, final Charset charset, final boolean 
includeStacktrace) {
+        super(config, new YamlJacksonFactory(includeStacktrace, 
false).newWriter(locationInfo, properties, compact),
+                charset, compact, complete, eventEol,
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern)
+                        .setDefaultPattern(DEFAULT_HEADER).build(),
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern)
+                        .setDefaultPattern(DEFAULT_FOOTER).build(),
+                false, null);
+    }
+
+    private YamlLayout(final Configuration config, final boolean locationInfo, 
final boolean properties,
+            final boolean complete, final boolean compact, final boolean 
eventEol, final String headerPattern,
+            final String footerPattern, final Charset charset, final boolean 
includeStacktrace,
+            final boolean stacktraceAsString, final boolean 
includeNullDelimiter,
+            final KeyValuePair[] additionalFields) {
+        super(config,
+                new YamlJacksonFactory(includeStacktrace, 
stacktraceAsString).newWriter(locationInfo, properties,
+                        compact),
+                charset, compact, complete, eventEol,
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern)
+                        .setDefaultPattern(DEFAULT_HEADER).build(),
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern)
+                        .setDefaultPattern(DEFAULT_FOOTER).build(),
+                includeNullDelimiter, additionalFields);
+    }
+
+    @Override
+    protected LogEventWithAdditionalFields 
createLogEventWithAdditionalFields(final LogEvent event,
+            final Map<String, String> additionalFieldsMap) {
+        return new YamlLogEventWithAdditionalFields(event, 
additionalFieldsMap);
+    }
+
+    @Override
+    public Map<String, String> getContentFormat() {
+        final Map<String, String> result = new HashMap<>();
+        result.put("version", "3.0");
+        return result;
+    }
+
+    /**
+     * @return The content type.
+     */
+    @Override
+    public String getContentType() {
+        return CONTENT_TYPE + "; charset=" + this.getCharset();
+    }
+
+    /**
+     * Returns appropriate YAML footer.
+     *
+     * @return a byte array containing the footer, closing the YAML array.
+     */
+    @Override
+    public byte[] getFooter() {
+        if (!this.complete) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        buf.append(this.eol);
+        final String str = serializeToString(getFooterSerializer());
+        if (str != null) {
+            buf.append(str);
+        }
+        buf.append(this.eol);
+        return getBytes(buf.toString());
+    }
+
+    /**
+     * Returns appropriate YAML header.
+     *
+     * @return a byte array containing the header, opening the YAML array.
+     */
+    @Override
+    public byte[] getHeader() {
+        if (!this.complete) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        final String str = serializeToString(getHeaderSerializer());
+        if (str != null) {
+            buf.append(str);
+        }
+        buf.append(this.eol);
+        return getBytes(buf.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java
 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java
new file mode 100644
index 0000000..0ef4049
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.jackson.yaml.parser;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser;
+import org.apache.logging.log4j.jackson.yaml.Log4jYamlObjectMapper;
+
+/**
+ * Parses the output from YamlLayout layout into instances of {@link LogEvent}.
+ */
+public class YamlLogEventParser extends AbstractJacksonLogEventParser {
+
+    public YamlLogEventParser() {
+        super(new Log4jYamlObjectMapper());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/site/manual/index.md
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-yaml/src/site/manual/index.md 
b/log4j-layout-jackson-yaml/src/site/manual/index.md
new file mode 100644
index 0000000..83112af
--- /dev/null
+++ b/log4j-layout-jackson-yaml/src/site/manual/index.md
@@ -0,0 +1,33 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+
+# Apache Log4j Layout for Jackson YAML module
+
+As of Log4j 3.0.0, the layout based on Jackson YAML has moved from the 
existing module logj-core to the new modules log4j-layout-jackson-yaml.
+
+## Requirements
+
+This module was introduced in Log4j 2.11.0 and requires Jackson.
+
+Some features may require optional
+[dependencies](../runtime-dependencies.html). These dependencies are specified 
in the
+documentation for those features.
+
+Some Log4j features require external dependencies.
+See the [Dependency Tree](dependencies.html#Dependency_Tree)
+for the exact list of JAR files needed for these features.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/site/site.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-yaml/src/site/site.xml 
b/log4j-layout-jackson-yaml/src/site/site.xml
new file mode 100644
index 0000000..6d4cddc
--- /dev/null
+++ b/log4j-layout-jackson-yaml/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+
+-->
+<project name="Log4j Core"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 
http://maven.apache.org/xsd/decoration-1.4.0.xsd";>
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/"; />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+       <!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" 
href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" 
/>
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>

Reply via email to