http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java
new file mode 100644
index 0000000..86b9984
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.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.yaml;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.LevelMixInTest;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Category(Layouts.Yaml.class)
+public class LevelMixInYamlTest extends LevelMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jYamlObjectMapper();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java
new file mode 100644
index 0000000..98132cd
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.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.yaml;
+
+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.Yaml.class)
+public class MarkerMixInYamlTest extends AbstractMarkerMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jYamlObjectMapper();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java
new file mode 100644
index 0000000..9746655
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 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;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+
+@Category(Layouts.Json.class)
+public class StackTraceElementYamlMixInTest {
+
+    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 testFromYamlWithLog4jModule() throws Exception {
+        final ObjectMapper mapper = new YAMLMapper();
+        final boolean encodeThreadContextAsList = false;
+        final SimpleModule module = new 
Log4jYamlModule(encodeThreadContextAsList, true, false);
+        module.addDeserializer(StackTraceElement.class, new 
Log4jStackTraceElementDeserializer());
+        mapper.registerModule(module);
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java",
+                123);
+        final StackTraceElement actual = mapper.readValue(
+                "---\nclass: package.SomeClass\nmethod: someMethod\nfile: 
SomeClass.java\nline: 123\n...",
+                StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFromYamlWithSimpleModule() throws Exception {
+        final ObjectMapper mapper = new YAMLMapper();
+        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 StackTraceElement actual = mapper.readValue(
+                "---\nclass: package.SomeClass\nmethod: someMethod\nfile: 
SomeClass.java\nline: 123\n...",
+                StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testLog4jYamlObjectMapper() throws Exception {
+        this.roundtrip(new Log4jYamlObjectMapper());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java
new file mode 100644
index 0000000..a0e821c
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 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 ConcurrentLoggingWithYamlLayoutTest {
+
+    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-yaml-layout.xml");
+
+    private static final String PATH = "target/test-yaml-layout.log";
+
+    @AfterClass
+    public static void after() {
+        new File(PATH).delete();
+    }
+
+    @Test
+    public void testConcurrentLogging() throws Throwable {
+        final Logger log = 
context.getLogger(ConcurrentLoggingWithYamlLayoutTest.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());
+            assertThat(lines.get(0), startsWith("---"));
+            // TODO more
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
new file mode 100644
index 0000000..b8e3ee6
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
@@ -0,0 +1,382 @@
+/*
+ * 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 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.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+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.Configuration;
+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.yaml.Log4jYamlObjectMapper;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Tests the YamlLayout class.
+ */
+@Category(Layouts.Yaml.class)
+public class YamlLayoutTest {
+    static ConfigurationFactory cf = new BasicConfigurationFactory();
+
+    @AfterClass
+    public static void cleanupClass() {
+        ConfigurationFactory.removeConfigurationFactory(cf);
+        ThreadContext.clearAll();
+    }
+
+    @BeforeClass
+    public static void setupClass() {
+        ThreadContext.clearAll();
+        ConfigurationFactory.setConfigurationFactory(cf);
+        final LoggerContext ctx = LoggerContext.getContext();
+        ctx.reconfigure();
+    }
+
+    LoggerContext ctx = LoggerContext.getContext();
+
+    Logger rootLogger = this.ctx.getRootLogger();
+
+    private void checkAt(final String expected, final int lineIndex, final 
List<String> list) {
+        final String trimedLine = list.get(lineIndex).trim();
+        assertTrue("Incorrect line index " + lineIndex + ": " + 
Strings.dquote(trimedLine),
+                trimedLine.equals(expected));
+    }
+
+    private void checkContains(final String expected, final List<String> list) 
{
+        for (final String string : list) {
+            final String trimedLine = string.trim();
+            if (trimedLine.equals(expected)) {
+                return;
+            }
+        }
+        Assert.fail("Cannot find " + expected + " in " + list);
+    }
+
+    private void checkMapEntry(final String key, final String value, final 
boolean compact, final String str) {
+        // "name":"value"
+        //final String expected = String.format("- key: \"%s\"\n  value: 
\"%s\"", key, value);
+        final String expected = String.format("%s: \"%s\"", key, value);
+        assertTrue("Cannot find " + expected + " in " + str, 
str.contains(expected));
+    }
+
+    private void checkProperty(final String key, final String value, final 
boolean compact, final String str,
+            final boolean isValue) {
+        final String propSep = this.toPropertySeparator(compact, isValue);
+        // {"key":"MDC.B","value":"B_Value"}
+        final String expected = String.format("%s%s\"%s\"", key, propSep, 
value);
+        assertTrue("Cannot find " + expected + " in " + str, 
str.contains(expected));
+    }
+
+    private void checkPropertyName(final String name, final boolean compact, 
final String str, final boolean isValue) {
+        final String propSep = this.toPropertySeparator(compact, isValue);
+        assertTrue(str, str.contains(name + propSep));
+    }
+
+    private void checkPropertyNameAbsent(final String name, final boolean 
compact, final String str, final boolean isValue) {
+        final String propSep = this.toPropertySeparator(compact, isValue);
+        assertFalse(str, str.contains(name + propSep));
+    }
+
+    private String prepareYAMLForStacktraceTests(final boolean 
stacktraceAsString) {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        // @formatter:off
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .setIncludeStacktrace(true)
+                .setStacktraceAsString(stacktraceAsString)
+                .build();
+        // @formatter:off
+        return layout.toSerializable(expected);
+    }
+
+    @Test
+    public void testAdditionalFields() throws Exception {
+        final AbstractJacksonLayout layout = YamlLayout.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\""));
+        assertTrue(str, str.contains("KEY2: \"" + new 
JavaLookup().getRuntime() + "\""));
+    }
+
+    private void testAllFeatures(final boolean includeSource, final boolean 
compact, final boolean eventEol,
+            final boolean includeContext, final boolean contextMapAslist, 
final boolean includeStacktrace) throws Exception {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .setLocationInfo(includeSource)
+                .setProperties(includeContext)
+                .setIncludeStacktrace(includeStacktrace)
+                .setCharset(StandardCharsets.UTF_8)
+                .build();
+        final String str = layout.toSerializable(expected);
+        // System.out.println(str);
+        // Just check for \n since \r might or might not be there.
+        assertEquals(str, !compact || eventEol, str.contains("\n"));
+        assertEquals(str, includeSource, str.contains("source"));
+        assertEquals(str, includeContext, str.contains("contextMap"));
+        final Log4jLogEvent actual = new 
Log4jYamlObjectMapper(contextMapAslist, includeStacktrace,false).readValue(str, 
Log4jLogEvent.class);
+        LogEventFixtures.assertEqualLogEvents(expected, actual, includeSource, 
includeContext, includeStacktrace);
+        if (includeContext) {
+            this.checkMapEntry("MDC.A", "A_Value", compact, str);
+            this.checkMapEntry("MDC.B", "B_Value", compact, str);
+        }
+        //
+        assertNull(actual.getThrown());
+        // make sure the names we want are used
+        this.checkPropertyName("instant", compact, str, false);
+        this.checkPropertyName("thread", compact, str, true); // and not 
threadName
+        this.checkPropertyName("level", compact, str, true);
+        this.checkPropertyName("loggerName", compact, str, true);
+        this.checkPropertyName("marker", compact, str, false);
+        this.checkPropertyName("name", compact, str, true);
+        this.checkPropertyName("parents", compact, str, false);
+        this.checkPropertyName("message", compact, str, true);
+        this.checkPropertyName("thrown", compact, str, false);
+        this.checkPropertyName("cause", compact, str, false);
+        this.checkPropertyName("commonElementCount", compact, str, true);
+        this.checkPropertyName("localizedMessage", compact, str, true);
+        if (includeStacktrace) {
+            this.checkPropertyName("extendedStackTrace", compact, str, false);
+            this.checkPropertyName("class", compact, str, true);
+            this.checkPropertyName("method", compact, str, true);
+            this.checkPropertyName("file", compact, str, true);
+            this.checkPropertyName("line", compact, str, true);
+            this.checkPropertyName("exact", compact, str, true);
+            this.checkPropertyName("location", compact, str, true);
+            this.checkPropertyName("version", compact, str, true);
+        } else {
+            this.checkPropertyNameAbsent("extendedStackTrace", compact, str, 
false);
+        }
+        this.checkPropertyName("suppressed", compact, str, false);
+        this.checkPropertyName("loggerFqcn", compact, str, true);
+        this.checkPropertyName("endOfBatch", compact, str, true);
+        if (includeContext) {
+            this.checkPropertyName("contextMap", compact, str, false);
+        } else {
+            this.checkPropertyNameAbsent("contextMap", compact, str, false);
+        }
+        this.checkPropertyName("contextStack", compact, str, false);
+        if (includeSource) {
+            this.checkPropertyName("source", compact, str, false);
+        } else {
+            this.checkPropertyNameAbsent("source", compact, str, false);
+        }
+        // check some attrs
+        this.checkProperty("loggerFqcn", "f.q.c.n", compact, str, true);
+        this.checkProperty("loggerName", "a.B", compact, str, true);
+    }
+
+    @Test
+    public void testContentType() {
+        final AbstractJacksonLayout layout = YamlLayout.createDefaultLayout();
+        assertEquals("application/yaml; charset=UTF-8", 
layout.getContentType());
+    }
+
+    @Test
+    public void testDefaultCharset() {
+        final AbstractJacksonLayout layout = YamlLayout.createDefaultLayout();
+        assertEquals(StandardCharsets.UTF_8, layout.getCharset());
+    }
+
+    @Test
+    public void testEscapeLayout() throws Exception {
+        final Map<String, Appender> appenders = this.rootLogger.getAppenders();
+        for (final Appender appender : appenders.values()) {
+            this.rootLogger.removeAppender(appender);
+        }
+        final Configuration configuration = 
rootLogger.getContext().getConfiguration();
+        // set up appender
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .setLocationInfo(true)
+                .setProperties(true)
+                .setIncludeStacktrace(true)
+                .setConfiguration(configuration)
+                .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("Here is a quote ' and then a double quote \"");
+
+        appender.stop();
+
+        final List<String> list = appender.getMessages();
+
+        this.checkAt("---", 0, list);
+        this.checkContains("level: \"DEBUG\"", list);
+        this.checkContains("message: \"Here is a quote ' and then a double 
quote \\\"\"", list);
+        this.checkContains("loggerFqcn: \"" + AbstractLogger.class.getName() + 
"\"", list);
+        for (final Appender app : appenders.values()) {
+            this.rootLogger.addAppender(app);
+        }
+    }
+
+    @Test
+    public void testExcludeStacktrace() throws Exception {
+        this.testAllFeatures(false, false, false, false, false, false);
+    }
+
+    @Test
+    public void testIncludeNullDelimiterFalse() throws Exception {
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .setIncludeNullDelimiter(false)
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertFalse(str.endsWith("\0"));
+    }
+
+    @Test
+    public void testIncludeNullDelimiterTrue() throws Exception {
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .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);
+        }
+        final Configuration configuration = 
rootLogger.getContext().getConfiguration();
+        // set up appender
+        // Use [[ and ]] to test header and footer (instead of [ and ])
+        final AbstractJacksonLayout layout = 
YamlLayout.createLayout(configuration, true, true, "[[", "]]", null, true);
+        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"));
+
+        appender.stop();
+
+        final List<String> list = appender.getMessages();
+
+        this.checkAt("---", 0, list);
+        this.checkContains("loggerFqcn: \"" + AbstractLogger.class.getName() + 
"\"", list);
+        this.checkContains("level: \"DEBUG\"", list);
+        this.checkContains("message: \"starting mdc pattern test\"", list);
+        for (final Appender app : appenders.values()) {
+            this.rootLogger.addAppender(app);
+        }
+    }
+
+    @Test
+    public void testLayoutLoggerName() throws Exception {
+        final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+                .setLocationInfo(false)
+                .setProperties(false)
+                .setIncludeStacktrace(true)
+                .setCharset(StandardCharsets.UTF_8)
+                .build();
+        final Log4jLogEvent expected = 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(expected);
+        assertTrue(str, str.contains("loggerName: \"a.B\""));
+        final Log4jLogEvent actual = new Log4jYamlObjectMapper(false, true, 
false).readValue(str, Log4jLogEvent.class);
+        assertEquals(expected.getLoggerName(), actual.getLoggerName());
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testLocationOffCompactOffMdcOff() throws Exception {
+        this.testAllFeatures(false, false, false, false, false, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOffEventEolOffMdcOn() throws Exception {
+        this.testAllFeatures(true, false, false, true, false, true);
+    }
+
+    @Test
+    public void testStacktraceAsNonString() throws Exception {
+        final String str = prepareYAMLForStacktraceTests(false);
+        assertTrue(str, str.contains("extendedStackTrace:\n    - "));
+    }
+
+    @Test
+    public void testStacktraceAsString() throws Exception {
+        final String str = prepareYAMLForStacktraceTests(true);
+        assertTrue(str, str.contains("extendedStackTrace: 
\"java.lang.NullPointerException"));
+    }
+
+    private String toPropertySeparator(final boolean compact, final boolean 
value) {
+        return value ? ": " : ":";
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java
 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java
new file mode 100644
index 0000000..7e689e6
--- /dev/null
+++ 
b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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 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 YamlLogEventParserTest extends AbstractLogEventParserTest {
+
+    private static final String YAML = "---\n" +
+            "timeMillis: 1493121664118\n" +
+            "instant:\n" +
+            " epochSecond: 1493121664\n" +
+            " nanoOfSecond: 118000000\n" +
+            "thread: \"main\"\n" +
+            "level: \"INFO\"\n" +
+            "loggerName: \"HelloWorld\"\n" +
+            "marker:\n" +
+            " name: \"child\"\n" +
+            " parents:\n" +
+            " - name: \"parent\"\n" +
+            "   parents:\n" +
+            "   - name: \"grandparent\"\n" +
+            "message: \"Hello, world!\"\n" +
+            "thrown:\n" +
+            " commonElementCount: 0\n" +
+            " message: \"error message\"\n" +
+            " name: \"java.lang.RuntimeException\"\n" +
+            " extendedStackTrace:\n" +
+            " - class: \"logtest.Main\"\n" +
+            "   method: \"main\"\n" +
+            "   file: \"Main.java\"\n" +
+            "   line: 29\n" +
+            "   exact: true\n" +
+            "   location: \"classes/\"\n" +
+            "   version: \"?\"\n" +
+            "contextStack:\n" +
+            "- \"one\"\n" +
+            "- \"two\"\n" +
+            "endOfBatch: false\n" +
+            "loggerFqcn: \"org.apache.logging.log4j.spi.AbstractLogger\"\n" +
+            "contextMap:\n" +
+            " bar: \"BAR\"\n" +
+            " foo: \"FOO\"\n" +
+            "threadId: 1\n" +
+            "threadPriority: 5\n" +
+            "source:\n" +
+            " class: \"logtest.Main\"\n" +
+            " method: \"main\"\n" +
+            " file: \"Main.java\"\n" +
+            " line: 29";
+
+    private YamlLogEventParser parser;
+
+    @Before
+    public void setup() {
+        parser = new YamlLogEventParser();
+    }
+
+    @Test
+    public void testByteArray() throws ParseException {
+        final LogEvent logEvent = 
parser.parseFrom(YAML.getBytes(StandardCharsets.UTF_8));
+        assertLogEvent(logEvent);
+    }
+
+    @Test
+    public void testByteArrayOffsetLength() throws ParseException {
+        final byte[] bytes = ("abc" + YAML + 
"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("---\n");
+    }
+
+    @Test
+    public void testString() throws ParseException {
+        final LogEvent logEvent = parser.parseFrom(YAML);
+        assertLogEvent(logEvent);
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringEmpty() throws ParseException {
+        parser.parseFrom("");
+    }
+
+    @Test
+    public void testStringIgnoreInvalidProperty() throws ParseException {
+        parser.parseFrom("---\nfoo: \"bar\"\n");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringInvalidYaml() throws ParseException {
+        parser.parseFrom("foobar");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringWrongPropertyType() throws ParseException {
+        parser.parseFrom("---\nthreadId: \"foobar\"\n");
+    }
+
+    @Test
+    public void testTimeMillisIgnored() throws ParseException {
+        parser.parseFrom("---\ntimeMillis: \"foobar\"\n");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml 
b/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml
new file mode 100644
index 0000000..f01d1e6
--- /dev/null
+++ b/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-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-yaml-layout.log" append="false">
+      <YamlLayout 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/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson/pom.xml b/log4j-layout-jackson/pom.xml
new file mode 100644
index 0000000..ad61835
--- /dev/null
+++ b/log4j-layout-jackson/pom.xml
@@ -0,0 +1,214 @@
+<?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</artifactId>
+  <name>Apache Log4j Layout for Jackson</name>
+  <description>
+    Apache Log4j Layout for Jackson.
+  </description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>Log4j Layout for Jackson Documentation</docLabel>
+    <projectDir>/log4j-layout-jackson</projectDir>
+    <module.name>org.apache.logging.log4j.jackson</module.name>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</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>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+            <configuration>
+              <archive>
+                <manifestFile>${manifestfile}</manifestFile>
+                <manifestEntries>
+                  <Specification-Title>${project.name}</Specification-Title>
+                  
<Specification-Version>${project.version}</Specification-Version>
+                  
<Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                  <Implementation-Title>${project.name}</Implementation-Title>
+                  
<Implementation-Version>${project.version}</Implementation-Version>
+                  
<Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                  
<Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
+                  
<X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
+                  
<X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
+                </manifestEntries>
+              </archive>
+            </configuration>
+          </execution>
+          <execution>
+            <id>default</id>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+            <configuration>
+              <archive>
+                <manifestFile>${manifestfile}</manifestFile>
+                <manifestEntries>
+                  <Specification-Title>${project.name}</Specification-Title>
+                  
<Specification-Version>${project.version}</Specification-Version>
+                  
<Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                  <Implementation-Title>${project.name}</Implementation-Title>
+                  
<Implementation-Version>${project.version}</Implementation-Version>
+                  
<Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                  
<Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
+                  
<X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
+                  
<X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
+                </manifestEntries>
+              </archive>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Fragment-Host>org.apache.logging.log4j.jackson</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/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java
new file mode 100644
index 0000000..ad4503c
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+
+import com.fasterxml.jackson.core.PrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
+
+public abstract class AbstractJacksonFactory {
+
+    protected final boolean includeStacktrace;
+
+    protected final boolean stacktraceAsString;
+    public AbstractJacksonFactory(final boolean includeStacktrace, final 
boolean stacktraceAsString) {
+        super();
+        this.includeStacktrace = includeStacktrace;
+        this.stacktraceAsString = stacktraceAsString;
+    }
+
+    abstract protected String getPropertyNameForContextMap();
+
+    abstract protected String getPropertyNameForNanoTime();
+
+    abstract protected String getPropertyNameForSource();
+
+    abstract protected String getPropertyNameForStackTrace();
+
+    abstract protected PrettyPrinter newCompactPrinter();
+
+    abstract protected ObjectMapper newObjectMapper();
+
+    abstract protected PrettyPrinter newPrettyPrinter();
+
+    public ObjectWriter newWriter(final boolean locationInfo, final boolean 
properties, final boolean compact) {
+        final SimpleFilterProvider filters = new SimpleFilterProvider();
+        final Set<String> except = new HashSet<>(4);
+        if (!locationInfo) {
+            except.add(this.getPropertyNameForSource());
+        }
+        if (!properties) {
+            except.add(this.getPropertyNameForContextMap());
+        }
+        if (!includeStacktrace) {
+            except.add(this.getPropertyNameForStackTrace());
+        }
+        except.add(this.getPropertyNameForNanoTime());
+        filters.addFilter(Log4jLogEvent.class.getName(), 
SimpleBeanPropertyFilter.serializeAllExcept(except));
+        final ObjectWriter writer = this.newObjectMapper()
+                .writer(compact ? this.newCompactPrinter() : 
this.newPrettyPrinter());
+        return writer.with(filters);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
new file mode 100644
index 0000000..da66b9d
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
@@ -0,0 +1,351 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.impl.MutableLogEvent;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.core.util.StringBuilderWriter;
+import org.apache.logging.log4j.util.Strings;
+
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+public abstract class AbstractJacksonLayout extends AbstractStringLayout {
+
+    public static abstract class Builder<B extends Builder<B>> extends 
AbstractStringLayout.Builder<B> {
+
+        @PluginBuilderAttribute
+        private boolean eventEol;
+
+        @PluginBuilderAttribute
+        private boolean compact;
+
+        @PluginBuilderAttribute
+        private boolean complete;
+
+        @PluginBuilderAttribute
+        private boolean locationInfo;
+
+        @PluginBuilderAttribute
+        private boolean properties;
+
+        @PluginBuilderAttribute
+        private boolean includeStacktrace = true;
+
+        @PluginBuilderAttribute
+        private boolean stacktraceAsString = false;
+
+        @PluginBuilderAttribute
+        private boolean includeNullDelimiter = false;
+
+        @PluginElement("AdditionalField")
+        private KeyValuePair[] additionalFields;
+
+        public KeyValuePair[] getAdditionalFields() {
+            return additionalFields;
+        }
+
+        public boolean getEventEol() {
+            return eventEol;
+        }
+
+        public boolean isCompact() {
+            return compact;
+        }
+
+        public boolean isComplete() {
+            return complete;
+        }
+
+        public boolean isIncludeNullDelimiter() {
+            return includeNullDelimiter;
+        }
+
+        /**
+         * If "true", includes the stack trace of any Throwable in the 
generated data, defaults to "true".
+         *
+         * @return If "true", includes the stack trace of any Throwable in the 
generated data, defaults to "true".
+         */
+        public boolean isIncludeStacktrace() {
+            return includeStacktrace;
+        }
+
+        public boolean isLocationInfo() {
+            return locationInfo;
+        }
+
+        public boolean isProperties() {
+            return properties;
+        }
+
+        public boolean isStacktraceAsString() {
+            return stacktraceAsString;
+        }
+
+        /**
+         * Additional fields to set on each log event.
+         *
+         * @return this builder
+         */
+        public B setAdditionalFields(final KeyValuePair[] additionalFields) {
+            this.additionalFields = additionalFields;
+            return asBuilder();
+        }
+
+        public B setCompact(final boolean compact) {
+            this.compact = compact;
+            return asBuilder();
+        }
+
+        public B setComplete(final boolean complete) {
+            this.complete = complete;
+            return asBuilder();
+        }
+
+        public B setEventEol(final boolean eventEol) {
+            this.eventEol = eventEol;
+            return asBuilder();
+        }
+
+        /**
+         * Whether to include NULL byte as delimiter after each event 
(optional, default to false).
+         *
+         * @return this builder
+         */
+        public B setIncludeNullDelimiter(final boolean includeNullDelimiter) {
+            this.includeNullDelimiter = includeNullDelimiter;
+            return asBuilder();
+        }
+
+        /**
+         * If "true", includes the stacktrace of any Throwable in the 
generated JSON, defaults to "true".
+         *
+         * @param includeStacktrace
+         *            If "true", includes the stacktrace of any Throwable in 
the generated JSON, defaults to "true".
+         * @return this builder
+         */
+        public B setIncludeStacktrace(final boolean includeStacktrace) {
+            this.includeStacktrace = includeStacktrace;
+            return asBuilder();
+        }
+
+        public B setLocationInfo(final boolean locationInfo) {
+            this.locationInfo = locationInfo;
+            return asBuilder();
+        }
+
+        public B setProperties(final boolean properties) {
+            this.properties = properties;
+            return asBuilder();
+        }
+
+        /**
+         * Whether to format the stacktrace as a string, and not a nested 
object (optional, defaults to false).
+         *
+         * @return this builder
+         */
+        public B setStacktraceAsString(final boolean stacktraceAsString) {
+            this.stacktraceAsString = stacktraceAsString;
+            return asBuilder();
+        }
+
+        protected String toStringOrNull(final byte[] header) {
+            return header == null ? null : new String(header, 
Charset.defaultCharset());
+        }
+    }
+    /**
+     * Subclasses can annotate with Jackson annotations for JSON example.
+     */
+    public static class LogEventWithAdditionalFields {
+
+        private final Object logEvent;
+        private final Map<String, String> additionalFields;
+
+        public LogEventWithAdditionalFields(final Object logEvent, final 
Map<String, String> additionalFields) {
+            this.logEvent = logEvent;
+            this.additionalFields = additionalFields;
+        }
+
+        public Map<String, String> getAdditionalFields() {
+            return additionalFields;
+        }
+
+        public Object getLogEvent() {
+            return logEvent;
+        }
+    }
+
+    protected static class ResolvableKeyValuePair {
+
+        final String key;
+        final String value;
+        final boolean valueNeedsLookup;
+
+        ResolvableKeyValuePair(final KeyValuePair pair) {
+            this.key = pair.getKey();
+            this.value = pair.getValue();
+            this.valueNeedsLookup = 
AbstractJacksonLayout.valueNeedsLookup(this.value);
+        }
+    }
+
+    protected static final String DEFAULT_EOL = "\r\n";
+    protected static final String COMPACT_EOL = Strings.EMPTY;
+    private static LogEvent convertMutableToLog4jEvent(final LogEvent event) {
+        // TODO Jackson-based layouts have certain filters set up for 
Log4jLogEvent.
+        // TODO Need to set up the same filters for MutableLogEvent but don't 
know how...
+        // This is a workaround.
+        return event instanceof MutableLogEvent ? ((MutableLogEvent) 
event).createMemento() : event;
+    }
+    private static ResolvableKeyValuePair[] prepareAdditionalFields(final 
Configuration config,
+            final KeyValuePair[] additionalFields) {
+        if (additionalFields == null || additionalFields.length == 0) {
+            // No fields set
+            return new ResolvableKeyValuePair[0];
+        }
+
+        // Convert to specific class which already determines whether values 
needs lookup during serialization
+        final ResolvableKeyValuePair[] resolvableFields = new 
ResolvableKeyValuePair[additionalFields.length];
+
+        for (int i = 0; i < additionalFields.length; i++) {
+            final ResolvableKeyValuePair resolvable = resolvableFields[i] = 
new ResolvableKeyValuePair(additionalFields[i]);
+
+            // Validate
+            if (config == null && resolvable.valueNeedsLookup) {
+                throw new IllegalArgumentException(
+                        "configuration needs to be set when there are 
additional fields with variables");
+            }
+        }
+
+        return resolvableFields;
+    }
+    protected static boolean valueNeedsLookup(final String value) {
+        return value != null && value.contains("${");
+    }
+    protected final String eol;
+
+    protected final ObjectWriter objectWriter;
+
+    protected final boolean compact;
+
+    protected final boolean complete;
+
+    protected final boolean includeNullDelimiter;
+
+    protected final ResolvableKeyValuePair[] additionalFields;
+
+    @Deprecated
+    protected AbstractJacksonLayout(final Configuration config, final 
ObjectWriter objectWriter, final Charset charset,
+            final boolean compact, final boolean complete, final boolean 
eventEol, final Serializer headerSerializer,
+            final Serializer footerSerializer) {
+        this(config, objectWriter, charset, compact, complete, eventEol, 
headerSerializer, footerSerializer, false);
+    }
+
+    @Deprecated
+    protected AbstractJacksonLayout(final Configuration config, final 
ObjectWriter objectWriter, final Charset charset,
+            final boolean compact, final boolean complete, final boolean 
eventEol, final Serializer headerSerializer,
+            final Serializer footerSerializer, final boolean 
includeNullDelimiter) {
+        this(config, objectWriter, charset, compact, complete, eventEol, 
headerSerializer, footerSerializer,
+                includeNullDelimiter, null);
+    }
+
+    protected AbstractJacksonLayout(final Configuration config, final 
ObjectWriter objectWriter, final Charset charset,
+            final boolean compact, final boolean complete, final boolean 
eventEol, final Serializer headerSerializer,
+            final Serializer footerSerializer, final boolean 
includeNullDelimiter,
+            final KeyValuePair[] additionalFields) {
+        super(config, charset, headerSerializer, footerSerializer);
+        this.objectWriter = objectWriter;
+        this.compact = compact;
+        this.complete = complete;
+        this.eol = compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL;
+        this.includeNullDelimiter = includeNullDelimiter;
+        this.additionalFields = prepareAdditionalFields(config, 
additionalFields);
+    }
+
+    protected LogEventWithAdditionalFields 
createLogEventWithAdditionalFields(final LogEvent event,
+            final Map<String, String> additionalFieldsMap) {
+        return new LogEventWithAdditionalFields(event, additionalFieldsMap);
+    }
+
+    private Map<String, String> resolveAdditionalFields(final LogEvent 
logEvent) {
+        // Note: LinkedHashMap retains order
+        final Map<String, String> additionalFieldsMap = new 
LinkedHashMap<>(additionalFields.length);
+        final StrSubstitutor strSubstitutor = 
configuration.getStrSubstitutor();
+
+        // Go over each field
+        for (final ResolvableKeyValuePair pair : additionalFields) {
+            if (pair.valueNeedsLookup) {
+                // Resolve value
+                additionalFieldsMap.put(pair.key, 
strSubstitutor.replace(logEvent, pair.value));
+            } else {
+                // Plain text value
+                additionalFieldsMap.put(pair.key, pair.value);
+            }
+        }
+
+        return additionalFieldsMap;
+    }
+
+    /**
+     * Formats a {@link org.apache.logging.log4j.core.LogEvent}.
+     *
+     * @param event
+     *            The LogEvent.
+     * @return The XML representation of the LogEvent.
+     */
+    @Override
+    public String toSerializable(final LogEvent event) {
+        try (final StringBuilderWriter writer = new StringBuilderWriter()) {
+            toSerializable(event, writer);
+            return writer.toString();
+        } catch (final IOException e) {
+            // Should this be an ISE or IAE?
+            LOGGER.error(e);
+            return Strings.EMPTY;
+        }
+    }
+
+    public void toSerializable(final LogEvent event, final Writer writer) 
throws IOException {
+        objectWriter.writeValue(writer, 
wrapLogEvent(convertMutableToLog4jEvent(event)));
+        writer.write(eol);
+        if (includeNullDelimiter) {
+            writer.write('\0');
+        }
+        markEvent();
+    }
+
+    protected Object wrapLogEvent(final LogEvent event) {
+        if (additionalFields.length > 0) {
+            // Construct map for serialization - note that we are 
intentionally using original LogEvent
+            final Map<String, String> additionalFieldsMap = 
resolveAdditionalFields(event);
+            // This class combines LogEvent with AdditionalFields during 
serialization
+            return createLogEventWithAdditionalFields(event, 
additionalFieldsMap);
+        }
+        // No additional fields, return original object
+        return event;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java
new file mode 100644
index 0000000..43784d6
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+import java.util.Map;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.message.Message;
+
+import com.fasterxml.jackson.annotation.JsonFilter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+/**
+ * <pre>
+ * AbstractLogEventMixIn
+*├─ AbstractLogEventXmlMixIn
+*├──── LogEventWithContextListXmlMixIn
+*├──── LogEventWithContextMapXmlMixIn
+*├─ AbstractLogEventJsonMixIn
+*├──── LogEventWithContextListJsonMixIn
+*├──── LogEventWithContextMapJsonMixIn
+ * </pre>
+ */
+@JsonFilter(AbstractLogEventMixIn.JSON_FILTER_ID)
+public abstract class AbstractLogEventMixIn implements LogEvent {
+
+    public static final String ATTR_END_OF_BATCH = "endOfBatch";
+    public static final String ATTR_LEVEL = "level";
+    public static final String ATTR_LOGGER_FQCN = "loggerFqcn";
+    public static final String ATTR_LOGGER_NAME = "loggerName";
+    public static final String ATTR_MARKER = "marker";
+    public static final String ATTR_THREAD = "thread";
+    public static final String ATTR_THREAD_ID = "threadId";
+    public static final String ATTR_THREAD_PRIORITY = "threadPriority";
+    public static final String ELT_MESSAGE = "message";
+    public static final String JSON_FILTER_ID = 
"org.apache.logging.log4j.core.impl.Log4jLogEvent";
+
+    private static final long serialVersionUID = 1L;
+
+    @Deprecated
+    @Override
+    @JsonIgnore
+    public abstract Map<String, String> getContextMap();
+
+    @JsonSerialize(using = MessageSerializer.class)
+    @JsonDeserialize(using = SimpleMessageDeserializer.class)
+    @Override
+    public abstract Message getMessage();
+
+    @JsonIgnore
+    @Override
+    public abstract Throwable getThrown();
+
+    @JsonIgnore // ignore from 2.11.0
+    @Override
+    public abstract long getTimeMillis();
+
+    @JsonIgnore
+    @Override
+    public abstract boolean isIncludeLocation();
+
+    @Override
+    public abstract void setEndOfBatch(boolean endOfBatch);
+
+    @Override
+    public abstract void setIncludeLocation(boolean locationRequired);
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
new file mode 100644
index 0000000..6efee4f
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.impl.ContextDataFactory;
+import org.apache.logging.log4j.util.StringMap;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class ContextDataAsEntryListDeserializer extends 
StdDeserializer<StringMap> {
+
+    private static final long serialVersionUID = 1L;
+
+    ContextDataAsEntryListDeserializer() {
+        super(Map.class);
+    }
+
+    @Override
+    public StringMap deserialize(final JsonParser jp, final 
DeserializationContext ctxt)
+            throws IOException, JsonProcessingException {
+        final List<MapEntry> list = jp.readValueAs(new 
TypeReference<List<MapEntry>>() {
+            // do nothing
+        });
+        final StringMap contextData = ContextDataFactory.createContextData();
+        for (final MapEntry mapEntry : list) {
+            contextData.putValue(mapEntry.getKey(), mapEntry.getValue());
+        }
+        return contextData;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java
new file mode 100644
index 0000000..d3c7551
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class ContextDataAsEntryListSerializer extends 
StdSerializer<ReadOnlyStringMap> {
+
+    private static final long serialVersionUID = 1L;
+
+    protected ContextDataAsEntryListSerializer() {
+        super(Map.class, false);
+    }
+
+    protected MapEntry createMapEntry(final String key, final String value) {
+        return new MapEntry(key, value);
+    }
+
+    protected MapEntry[] createMapEntryArray(final int size) {
+        return new MapEntry[size];
+    }
+
+    @Override
+    public void serialize(final ReadOnlyStringMap contextData, final 
JsonGenerator jgen,
+            final SerializerProvider provider) throws IOException, 
JsonGenerationException {
+
+        final MapEntry[] pairs = createMapEntryArray(contextData.size());
+        contextData.forEach(new BiConsumer<String, Object>() {
+            int i = 0;
+
+            @Override
+            public void accept(final String key, final Object value) {
+                pairs[i++] = createMapEntry(key, String.valueOf(value));
+            }
+        });
+        jgen.writeObject(pairs);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java
new file mode 100644
index 0000000..9d6843a
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java
@@ -0,0 +1,65 @@
+
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.impl.ContextDataFactory;
+import org.apache.logging.log4j.util.StringMap;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class ContextDataDeserializer extends StdDeserializer<StringMap> {
+
+    private static final long serialVersionUID = 1L;
+
+    ContextDataDeserializer() {
+        super(Map.class);
+    }
+
+    @Override
+    public StringMap deserialize(final JsonParser jp, final 
DeserializationContext ctxt) throws IOException,
+            JsonProcessingException {
+
+        // Sanity check: verify that we got "Json Object":
+//        JsonToken tok = jp.nextToken();
+//        if (tok != JsonToken.START_OBJECT) {
+//            throw new IOException("Expected data to start with an Object");
+//        }
+        final StringMap contextData = ContextDataFactory.createContextData();
+        // Iterate over object fields:
+        while (jp.nextToken() != JsonToken.END_OBJECT) {
+            final String fieldName = jp.getCurrentName();
+
+            // move to value
+            jp.nextToken();
+            contextData.putValue(fieldName, jp.getText());
+        }
+        return contextData;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java
new file mode 100644
index 0000000..245e436
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.TriConsumer;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class ContextDataSerializer extends StdSerializer<ReadOnlyStringMap> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final TriConsumer<String, Object, JsonGenerator> 
WRITE_STRING_FIELD_INTO =
+            new TriConsumer<String, Object, JsonGenerator>() {
+
+        @Override
+        public void accept(final String key, final Object value, final 
JsonGenerator jsonGenerator) {
+            try {
+                jsonGenerator.writeStringField(key, String.valueOf(value));
+            } catch (final Exception ex) {
+                throw new IllegalStateException("Problem with key " + key, ex);
+            }
+        }
+    };
+
+    protected ContextDataSerializer() {
+        super(Map.class, false);
+    }
+
+    @Override
+    public void serialize(final ReadOnlyStringMap contextData, final 
JsonGenerator jgen,
+            final SerializerProvider provider) throws IOException, 
JsonGenerationException {
+
+        jgen.writeStartObject();
+        contextData.forEach(WRITE_STRING_FIELD_INTO, jgen);
+        jgen.writeEndObject();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java
new file mode 100644
index 0000000..2642e42
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.impl.ExtendedClassInfo;
+import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+/**
+ * Mix-in for {@link ExtendedStackTraceElement}.
+ */
+@JsonPropertyOrder({
+    //@formatter:off
+    ExtendedStackTraceElementMixIn.ATTR_CLASS,
+    ExtendedStackTraceElementMixIn.ATTR_METHOD,
+    ExtendedStackTraceElementMixIn.ATTR_FILE,
+    ExtendedStackTraceElementMixIn.ATTR_LINE,
+    ExtendedStackTraceElementMixIn.ATTR_EXACT,
+    ExtendedStackTraceElementMixIn.ATTR_LOCATION,
+    ExtendedStackTraceElementMixIn.ATTR_VERSION
+    //@formatter:on
+})
+public abstract class ExtendedStackTraceElementMixIn implements Serializable {
+
+    protected static final String ATTR_CLASS = 
StackTraceElementConstants.ATTR_CLASS;
+    protected static final String ATTR_METHOD = 
StackTraceElementConstants.ATTR_METHOD;
+    protected static final String ATTR_FILE = 
StackTraceElementConstants.ATTR_FILE;
+    protected static final String ATTR_LINE = 
StackTraceElementConstants.ATTR_LINE;
+    protected static final String ATTR_EXACT = "exact";
+    protected static final String ATTR_LOCATION = "location";
+    protected static final String ATTR_VERSION = "version";
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonCreator
+    public ExtendedStackTraceElementMixIn(
+    // @formatter:off
+            @JsonProperty(ATTR_CLASS) final String declaringClass,
+            @JsonProperty(ATTR_METHOD) final String methodName,
+            @JsonProperty(ATTR_FILE) final String fileName,
+            @JsonProperty(ATTR_LINE) final int lineNumber,
+            @JsonProperty(ATTR_EXACT) final boolean exact,
+            @JsonProperty(ATTR_LOCATION) final String location,
+            @JsonProperty(ATTR_VERSION) final String version
+   // @formatter:on
+    ) {
+        // empty
+    }
+
+    @JsonProperty(ATTR_CLASS)
+    public abstract String getClassName();
+
+    @JsonProperty(ATTR_EXACT)
+    public abstract boolean getExact();
+
+    @JsonIgnore
+    public abstract ExtendedClassInfo getExtraClassInfo();
+
+    @JsonProperty(ATTR_FILE)
+    public abstract String getFileName();
+
+    @JsonProperty(ATTR_LINE)
+    public abstract int getLineNumber();
+
+    @JsonProperty(ATTR_LOCATION)
+    public abstract String getLocation();
+
+    @JsonProperty(ATTR_METHOD)
+    public abstract String getMethodName();
+
+    @JsonIgnore
+    abstract StackTraceElement getStackTraceElement();
+
+    @JsonProperty(ATTR_VERSION)
+    public abstract String getVersion();
+
+    @JsonIgnore
+    public abstract boolean isNativeMethod();
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java
 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java
new file mode 100644
index 0000000..16a3bb5
--- /dev/null
+++ 
b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.time.Instant;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Jackson mix-in for {@link Instant}.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ *
+ * @see Marker
+ */
+@JsonIgnoreProperties({ "epochMillisecond", "nanoOfMillisecond" })
+public abstract class InstantMixIn {
+
+    protected static final String ATTR_NANO_OF_SECOND = "nanoOfSecond";
+    protected static final String ATTR_EPOCH_SECOND = "epochSecond";
+
+    @JsonCreator
+    protected InstantMixIn(
+    // @formatter:off
+            @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond,
+            @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond)
+            // @formatter:on
+    {
+        // empty
+    }
+
+    @JsonProperty(ATTR_EPOCH_SECOND)
+    public abstract long getEpochSecond();
+
+    @JsonProperty(ATTR_NANO_OF_SECOND)
+    public abstract int getNanoOfSecond();
+}

Reply via email to