You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2021/12/19 23:44:50 UTC

[logging-log4j2] 01/01: [LOG4J2-3242] Rename JNDI enablement property from 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'.

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

ggregory pushed a commit to branch release-2.12.x/LOG4J2-3242
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit a70e2383caf70c2cb2fe827e6eb136109ed57c25
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Dec 17 15:48:27 2021 -0500

    [LOG4J2-3242] Rename JNDI enablement property from 'log4j2.enableJndi'
    to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and
    'log4j2.enableJndiContextSelector'.
    
    Cherry-pick from branch release-2.x, resolve conflicts, and tweak.
---
 .../log4j/core/appender/AbstractManager.java       |   3 +-
 .../log4j/core/appender/mom/JmsManager.java        |  13 +-
 .../logging/log4j/core/lookup/Interpolator.java    |  13 +-
 .../logging/log4j/core/lookup/JndiLookup.java      |  52 +-
 .../apache/logging/log4j/core/net/JndiManager.java |  39 +-
 .../log4j/core/selector/JndiContextSelector.java   |   4 +-
 .../log4j/core/appender/mom/JmsAppenderTest.java   |   7 +-
 .../routing/RoutingAppenderWithJndiTest.java       | 125 ++++
 .../log4j/core/lookup/InterpolatorTest.java        |   2 +
 .../log4j/core/lookup/JndiDisabledLookupTest.java  |  38 ++
 .../logging/log4j/core/lookup/JndiLookupTest.java  |  42 +-
 .../core/lookup/JndiRestrictedLookupTest.java      |  43 ++
 .../logging/log4j/core/net/JndiManagerTest.java    |  98 +++
 .../apache/logging/log4j/test/JUnit5Bridge.java    |  35 ++
 src/changes/changes.xml                            | 693 +++++++++++++++++++++
 src/site/xdoc/manual/appenders.xml                 |   6 +
 src/site/xdoc/manual/configuration.xml.vm          |  53 ++
 17 files changed, 1235 insertions(+), 31 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
index e85871f..bf2c53a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.appender;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -110,7 +111,7 @@ public abstract class AbstractManager implements AutoCloseable {
             @SuppressWarnings("unchecked")
             M manager = (M) MAP.get(name);
             if (manager == null) {
-                manager = factory.createManager(name, data);
+                manager = Objects.requireNonNull(factory, "factory").createManager(name, data);
                 if (manager == null) {
                     throw new IllegalStateException("ManagerFactory [" + factory + "] unable to create manager for ["
                             + name + "] with data [" + data + "]");
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
index c9f105b..d2d397d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
@@ -125,17 +125,16 @@ public class JmsManager extends AbstractManager {
 
         @Override
         public JmsManager createManager(final String name, final JmsManagerConfiguration data) {
-            if (JndiManager.isJndiEnabled()) {
+            if (JndiManager.isJndiJmsEnabled()) {
                 try {
                     return new JmsManager(name, data);
                 } catch (final Exception e) {
                     logger().error("Error creating JmsManager using JmsManagerConfiguration [{}]", data, e);
                     return null;
                 }
-            } else {
-                logger().error("Jndi has not been enabled. The log4j2.enableJndi property must be set to true");
-                return null;
             }
+            logger().error("JNDI must be enabled by setting log4j2.enableJndiJms=true");
+            return null;
         }
     }
 
@@ -354,7 +353,7 @@ public class JmsManager extends AbstractManager {
      * @param object
      *            The LogEvent or String message to wrap.
      * @return A new JMS message containing the provided object.
-     * @throws JMSException
+     * @throws JMSException if the JMS provider fails to create a message due to some internal error.
      */
     public Message createMessage(final Serializable object) throws JMSException {
         if (object instanceof String) {
@@ -375,7 +374,7 @@ public class JmsManager extends AbstractManager {
      * Creates a MessageConsumer on this Destination using the current Session.
      *
      * @return A MessageConsumer on this Destination.
-     * @throws JMSException
+     * @throws JMSException if the session fails to create a consumer due to some internal error.
      */
     public MessageConsumer createMessageConsumer() throws JMSException {
         return this.session.createConsumer(this.destination);
@@ -389,7 +388,7 @@ public class JmsManager extends AbstractManager {
      * @param destination
      *            The JMS Destination for the MessageProducer
      * @return A MessageProducer on this Destination.
-     * @throws JMSException
+     * @throws JMSException if the session fails to create a MessageProducer due to some internal error.
      */
     public MessageProducer createMessageProducer(final Session session, final Destination destination)
             throws JMSException {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
index c8409ab..3d8c07d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.ConfigurationAware;
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
+import org.apache.logging.log4j.core.net.JndiManager;
 import org.apache.logging.log4j.core.util.Loader;
 import org.apache.logging.log4j.core.util.ReflectionUtil;
 import org.apache.logging.log4j.status.StatusLogger;
@@ -73,7 +74,7 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
         for (final Map.Entry<String, PluginType<?>> entry : plugins.entrySet()) {
             try {
                 final Class<? extends StrLookup> clazz = entry.getValue().getPluginClass().asSubclass(StrLookup.class);
-                if (!clazz.getName().equals("org.apache.logging.log4j.core.lookup.JndiLookup")) {
+                if (!clazz.getName().equals("org.apache.logging.log4j.core.lookup.JndiLookup") || JndiManager.isJndiLookupEnabled()) {
                     strLookupMap.put(entry.getKey().toLowerCase(), ReflectionUtil.instantiate(clazz));
                 }
             } catch (final Throwable t) {
@@ -101,6 +102,16 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
         strLookupMap.put("main", MainMapLookup.MAIN_SINGLETON);
         strLookupMap.put("marker", new MarkerLookup());
         strLookupMap.put("java", new JavaLookup());
+        // JNDI
+        if (JndiManager.isJndiLookupEnabled()) {
+            try {
+                // [LOG4J2-703] We might be on Android
+                strLookupMap.put(LOOKUP_KEY_JNDI,
+                        Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JndiLookup", StrLookup.class));
+            } catch (final LinkageError | Exception e) {
+                handleError(LOOKUP_KEY_JNDI, e);
+            }
+        }
         // JMX input args
         try {
             // We might be on Android
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
index bd19e54..a783ea4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
@@ -16,9 +16,16 @@
  */
 package org.apache.logging.log4j.core.lookup;
 
+import java.util.Objects;
+
+import javax.naming.NamingException;
+
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.net.JndiManager;
 import org.apache.logging.log4j.status.StatusLogger;
 
 /**
@@ -26,17 +33,54 @@ import org.apache.logging.log4j.status.StatusLogger;
  */
 @Plugin(name = "jndi", category = StrLookup.CATEGORY)
 public class JndiLookup extends AbstractLookup {
+
     private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final String RESULT = "JNDI is not supported";
+    private static final Marker LOOKUP = MarkerManager.getMarker("LOOKUP");
+
+    /** JNDI resource path prefix used in a J2EE container */
+    static final String CONTAINER_JNDI_RESOURCE_PATH_PREFIX = "java:comp/env/";
+
+    /**
+     * Constructs a new instance or throw IllegalStateException if this feature is disabled.
+     */
+    public JndiLookup() {
+        if (!JndiManager.isJndiLookupEnabled()) {
+            throw new IllegalStateException("JNDI must be enabled by setting log4j2.enableJndiLookup=true");
+        }
+    }
+
     /**
      * Looks up the value of the JNDI resource.
+     * 
      * @param event The current LogEvent (is ignored by this StrLookup).
-     * @param key  the JNDI resource name to be looked up, may be null
+     * @param key the JNDI resource name to be looked up, may be null
      * @return The String value of the JNDI resource.
      */
     @Override
     public String lookup(final LogEvent event, final String key) {
-        LOGGER.warn("Attempt to use JNDI Lookup");
-        return RESULT;
+        if (key == null) {
+            return null;
+        }
+        final String jndiName = convertJndiName(key);
+        try (final JndiManager jndiManager = JndiManager.getDefaultManager()) {
+            return Objects.toString(jndiManager.lookup(jndiName), null);
+        } catch (final NamingException e) {
+            LOGGER.warn(LOOKUP, "Error looking up JNDI resource [{}].", jndiName, e);
+            return null;
+        }
+    }
+
+    /**
+     * Convert the given JNDI name to the actual JNDI name to use. Default implementation applies the "java:comp/env/"
+     * prefix unless other scheme like "java:" is given.
+     * 
+     * @param jndiName The name of the resource.
+     * @return The fully qualified name to look up.
+     */
+    private String convertJndiName(final String jndiName) {
+        if (!jndiName.startsWith(CONTAINER_JNDI_RESOURCE_PATH_PREFIX) && jndiName.indexOf(':') == -1) {
+            return CONTAINER_JNDI_RESOURCE_PATH_PREFIX + jndiName;
+        }
+        return jndiName;
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
index 06e2793..e005c62 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
@@ -39,11 +39,29 @@ import org.apache.logging.log4j.util.PropertiesUtil;
 public class JndiManager extends AbstractManager {
 
     private static final JndiManagerFactory FACTORY = new JndiManagerFactory();
+    private static final String PREFIX = "log4j2.enableJndi";
+    private static final String JAVA_SCHEME = "java";
 
     private final Context context;
 
+    private static boolean isJndiEnabled(final String subKey) {
+        return PropertiesUtil.getProperties().getBooleanProperty(PREFIX + subKey, false);
+    }
+
     public static boolean isJndiEnabled() {
-        return PropertiesUtil.getProperties().getBooleanProperty("log4j2.enableJndi", false);
+        return isJndiContextSelectorEnabled() || isJndiJmsEnabled() || isJndiLookupEnabled();
+    }
+
+    public static boolean isJndiContextSelectorEnabled() {
+        return isJndiEnabled("ContextSelector");
+    }
+
+    public static boolean isJndiJmsEnabled() {
+        return isJndiEnabled("Jms");
+    }
+
+    public static boolean isJndiLookupEnabled() {
+        return isJndiEnabled("Lookup");
     }
 
     private JndiManager(final String name, final Context context) {
@@ -181,7 +199,7 @@ public class JndiManager extends AbstractManager {
         }
         try {
             URI uri = new URI(name);
-            if (uri.getScheme() == null || uri.getScheme().equals("java")) {
+            if (uri.getScheme() == null || uri.getScheme().equals(JAVA_SCHEME)) {
                 return (T) this.context.lookup(name);
             }
             LOGGER.warn("Unsupported JNDI URI - {}", name);
@@ -195,15 +213,14 @@ public class JndiManager extends AbstractManager {
 
         @Override
         public JndiManager createManager(final String name, final Properties data) {
-            if (isJndiEnabled()) {
-                try {
-                    return new JndiManager(name, new InitialContext(data));
-                } catch (final NamingException e) {
-                    LOGGER.error("Error creating JNDI InitialContext.", e);
-                    return null;
-                }
-            } else {
-                return new JndiManager(name, null);
+            if (!isJndiEnabled()) {
+                throw new IllegalStateException(String.format("JNDI must be enabled by setting one of the %s* properties to true", PREFIX));
+            }
+            try {
+                return new JndiManager(name, new InitialContext(data));
+            } catch (final NamingException e) {
+                LOGGER.error("Error creating JNDI InitialContext for '{}'.", name, e);
+                return null;
             }
         }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
index 81ec3f3..7da852d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
@@ -93,8 +93,8 @@ public class JndiContextSelector implements NamedContextSelector {
     private static final StatusLogger LOGGER = StatusLogger.getLogger();
 
     public JndiContextSelector() {
-        if (!JndiManager.isJndiEnabled()) {
-            throw new IllegalStateException("JNDI must be enabled by setting log4j2.enableJndi=true");
+        if (!JndiManager.isJndiContextSelectorEnabled()) {
+            throw new IllegalStateException("JNDI must be enabled by setting log4j2.enableJndiContextSelector=true");
         }
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
index daf2d0e..4c5b1a9 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
@@ -85,8 +85,13 @@ public class JmsAppenderTest {
     public RuleChain rules = RuleChain.outerRule(jndiRule).around(ctx);
 
     @BeforeClass
+    public static void afterClass() throws Exception {
+        System.clearProperty("log4j2.enableJndiJms");
+    }
+
+    @BeforeClass
     public static void beforeClass() throws Exception {
-        System.setProperty("log4j2.enableJndi", "true");
+        System.setProperty("log4j2.enableJndiJms", "true");
     }
 
     public JmsAppenderTest() throws Exception {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
new file mode 100644
index 0000000..899fd5e
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.core.appender.routing;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.EventLogger;
+import org.apache.logging.log4j.junit.JndiRule;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+import static org.junit.Assert.*;
+
+/**
+ * RoutingAppenderWithJndiTest
+ */
+public class RoutingAppenderWithJndiTest {
+
+    public static final String JNDI_CONTEXT_NAME = "java:comp/env/logging/context-name";
+    private ListAppender listAppender1;
+    private ListAppender listAppender2;
+
+    public static LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-routing-by-jndi.xml");
+
+    @ClassRule
+    public static RuleChain rules = RuleChain.outerRule(new JndiRule(initBindings())).around(loggerContextRule);
+
+    private static Map<String, Object> initBindings() {
+        System.setProperty("log4j2.enableJndiLookup", "true");
+        //System.setProperty("log4j2.enableJndiJms", "true");
+        //System.setProperty("log4j2.enableJndiContextSelector", "true");
+        return Collections.emptyMap();
+    }
+
+    @Before
+    public void before() {
+        listAppender1 = RoutingAppenderWithJndiTest.loggerContextRule.getListAppender("List1");
+        listAppender2 = RoutingAppenderWithJndiTest.loggerContextRule.getListAppender("List2");
+    }
+
+    @After
+    public void after() {
+        if (listAppender1 != null) {
+            listAppender1.clear();
+        }
+        if (listAppender2 != null) {
+            listAppender2.clear();
+        }
+    }
+
+    @Test
+    public void routingTest() throws NamingException {
+        // default route when there's no jndi resource
+        StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a message from unknown context", "Context");
+        EventLogger.logEvent(msg);
+        final File defaultLogFile = new File("target/routingbyjndi/routingbyjnditest-unknown.log");
+        assertTrue("The default log file was not created", defaultLogFile.exists());
+
+        // now set jndi resource to Application1
+        final Context context = new InitialContext();
+        context.bind(JNDI_CONTEXT_NAME, "Application1");
+
+        msg = new StructuredDataMessage("Test", "This is a message from Application1", "Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender1.getEvents());
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(), listAppender1.getEvents().size() == 1);
+
+        // now set jndi resource to Application2
+        context.rebind(JNDI_CONTEXT_NAME, "Application2");
+
+        msg = new StructuredDataMessage("Test", "This is a message from Application2", "Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender2.getEvents());
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender2.getEvents().size(), listAppender2.getEvents().size() == 1);
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(), listAppender1.getEvents().size() == 1);
+
+        msg = new StructuredDataMessage("Test", "This is another message from Application2", "Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender2.getEvents());
+        assertTrue("Incorrect number of events. Expected 2, got " + listAppender2.getEvents().size(), listAppender2.getEvents().size() == 2);
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(), listAppender1.getEvents().size() == 1);
+
+        // now set jndi resource to Application3.
+        // The context name, 'Application3', will be used as log file name by the default route.
+        context.rebind("java:comp/env/logging/context-name", "Application3");
+        msg = new StructuredDataMessage("Test", "This is a message from Application3", "Context");
+        EventLogger.logEvent(msg);
+        final File application3LogFile = new File("target/routingbyjndi/routingbyjnditest-Application3.log");
+        assertTrue("The Application3 log file was not created", application3LogFile.exists());
+
+        // now set jndi resource to Application4
+        // The context name, 'Application4', will be used as log file name by the default route.
+        context.rebind("java:comp/env/logging/context-name", "Application4");
+        msg = new StructuredDataMessage("Test", "This is a message from Application4", "Context");
+        EventLogger.logEvent(msg);
+        final File application4LogFile = new File("target/routingbyjndi/routingbyjnditest-Application4.log");
+        assertTrue("The Application3 log file was not created", application4LogFile.exists());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
index 0af36fd..fc6f3d8 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
@@ -44,12 +44,14 @@ public class InterpolatorTest {
         protected void before() throws Throwable {
             System.setProperty(TESTKEY, TESTVAL);
             System.setProperty(TESTKEY2, TESTVAL);
+            System.setProperty("log4j2.enableJndiLookup", "true");
         }
 
         @Override
         protected void after() {
             System.clearProperty(TESTKEY);
             System.clearProperty(TESTKEY2);
+            System.clearProperty("log4j2.enableJndiLookup");
         }
     });
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java
new file mode 100644
index 0000000..362a67d
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.core.lookup;
+
+import org.apache.logging.log4j.test.JUnit5Bridge;
+import org.junit.Test;
+
+/**
+ * JndiDisabledLookupTest
+ *
+ * Verifies the Lookups are disabled without the log4j2.enableJndiLookup property set to true.
+ */
+public class JndiDisabledLookupTest {
+
+    @Test
+    public void testLookup() {
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                new JndiLookup();
+            }
+        });
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
index ba45808..d02364b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
@@ -16,17 +16,20 @@
  */
 package org.apache.logging.log4j.core.lookup;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.logging.log4j.junit.JndiRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
 /**
  * JndiLookupTest
  */
@@ -42,8 +45,22 @@ public class JndiLookupTest {
     @Rule
     public JndiRule jndiRule = new JndiRule(createBindings());
 
+    @AfterClass
+    public static void afterClass() {
+        System.setProperty("log4j2.enableJndiLookup", "true");
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.clearProperty("log4j2.enableJndiLookup");
+    }
+
     private Map<String, Object> createBindings() {
-        return new HashMap<>();
+        final Map<String, Object> map = new HashMap<>();
+        map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME, TEST_CONTEXT_NAME);
+        map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_INTEGRAL_NAME, TEST_INTEGRAL_VALUE);
+        map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_STRINGS_NAME, TEST_STRINGS_COLLECTION);
+        return map;
     }
 
     @Test
@@ -51,6 +68,23 @@ public class JndiLookupTest {
         final StrLookup lookup = new JndiLookup();
 
         String contextName = lookup.lookup(TEST_CONTEXT_RESOURCE_NAME);
-        assertEquals("JNDI is not supported", contextName);
+        assertEquals(TEST_CONTEXT_NAME, contextName);
+
+        contextName = lookup.lookup(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME);
+        assertEquals(TEST_CONTEXT_NAME, contextName);
+
+        final String nonExistingResource = lookup.lookup("logging/non-existing-resource");
+        assertNull(nonExistingResource);
+    }
+
+    @Test
+    public void testNonStringLookup() throws Exception {
+        // LOG4J2-1310
+        final StrLookup lookup = new JndiLookup();
+        final String integralValue = lookup.lookup(TEST_INTEGRAL_NAME);
+        assertEquals(String.valueOf(TEST_INTEGRAL_VALUE), integralValue);
+        final String collectionValue = lookup.lookup(TEST_STRINGS_NAME);
+        assertEquals(String.valueOf(TEST_STRINGS_COLLECTION), collectionValue);
     }
+
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java
new file mode 100644
index 0000000..e40cdb2
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.core.lookup;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * JndiLookupTest
+ */
+public class JndiRestrictedLookupTest {
+
+    private static final String DOMAIN = "apache.org";
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("log4j2.enableJndiLookup", "true");
+    }
+
+    @Test
+    public void testDnsLookup() throws Exception {
+        final StrLookup lookup = new JndiLookup();
+        String result = lookup.lookup("dns:/" + DOMAIN);
+        assertNull("DNS data returend", result);
+
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/JndiManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/JndiManagerTest.java
new file mode 100644
index 0000000..e2fd8f7
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/JndiManagerTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.core.net;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.Properties;
+
+import org.apache.logging.log4j.test.JUnit5Bridge;
+import org.junit.Test;
+
+/**
+ * Tests {@link JndiManager}.
+ */
+public class JndiManagerTest {
+
+    @Test
+    public void testIsJndiEnabled() {
+        assertFalse(JndiManager.isJndiEnabled());
+    }
+
+    @Test
+    public void testIsJndiContextSelectorEnabled() {
+        assertFalse(JndiManager.isJndiContextSelectorEnabled());
+    }
+
+    @Test
+    public void testIsJndiJmsEnabled() {
+        assertFalse(JndiManager.isJndiJmsEnabled());
+    }
+
+    @Test
+    public void testIsJndiLookupEnabled() {
+        assertFalse(JndiManager.isJndiLookupEnabled());
+    }
+
+    @Test
+    public void testNoInstanceByDefault() {
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getDefaultManager();
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getDefaultManager(null);
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getDefaultManager("A");
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getJndiManager(null);
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getJndiManager(new Properties());
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getJndiManager(null, null, null, null, null, null);
+            }
+        });
+        JUnit5Bridge.assertThrows(IllegalStateException.class, new Runnable() {
+            @Override
+            public void run() {
+                JndiManager.getJndiManager("A", "A", "A", "A", "A", new Properties());
+            }
+        });
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/JUnit5Bridge.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/JUnit5Bridge.java
new file mode 100644
index 0000000..c331433
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/JUnit5Bridge.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.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class JUnit5Bridge {
+
+    /** This branch is on Java 7 and uses JUnit 4, hence this hack. */
+    public static <T> void assertThrows(Class<T> expectedType, Runnable runnable) {
+        try {
+            runnable.run();
+            fail("Expected " + expectedType.getCanonicalName());
+        } catch (Throwable t) {
+            assertEquals(expectedType, t.getClass());
+        }
+    
+    }
+
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index c060fee..e9355ce 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -29,9 +29,702 @@
          - "update" - Change
          - "remove" - Removed
     -->
+<<<<<<< log4j-2.12
     <release version="2.12.3" date="2021-12-dd" description="GA Release 2.12.3">
       <action issue="LOG4J2-3230" dev="ckozak" type="fix">
         Fix string substitution recursion.
+=======
+    <release version="2.17.0" date="2021-MM-dd" description="GA Release 2.17.0">
+      <action issue="LOG4J2-3242" dev="rgoers, ggregory" type="fix">
+        Limit JNDI to the java protocol only. JNDI will remain disabled by default. Rename JNDI enablement property from
+        'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'.
+      </action>
+      <action issue="LOG4J2-3241" dev="rgoers" type="fix">
+        Do not declare log4j-api-java9 and log4j-core-java9 as dependencies as it causes problems with the
+        Maven enforcer plugin.
+      </action>
+      <action issue="LOG4J2-3247" dev="ggregory" type="fix">
+        PropertiesConfiguration.parseAppenderFilters NPE when parsing properties file filters.
+      </action>
+      <action issue="LOG4J2-3249" dev="ggregory" type="fix">
+        Log4j 1.2 bridge for Syslog Appender defaults to port 512 instead of 514.
+      </action>
+      <action issue="LOG4J2-3237" dev="ggregory" type="fix">
+        Log4j 1.2 bridge API hard codes the Syslog protocol to TCP.
+      </action>
+    </release>
+    <release version="2.16.0" date="2021-12-13" description="GA Release 2.16.0">
+      <action issue="LOG4J2-3208" dev="rgoers" type="fix">
+        Disable JNDI by default. Require log4j2.enableJndi to be set to true to allow JNDI.
+      </action>
+      <action issue="LOG4J2-3211" dev="rgoers" type="fix">
+        Completely remove support for Message Lookups.
+      </action>
+    </release>
+    <release version="2.15.0" date="2021-12-06" description="GA Release 2.15.0">
+      <!-- ADDS -->
+      <action issue="LOG4J2-3198" dev="ckozak" type="add">
+        Pattern layout no longer enables lookups within message text by default for cleaner API boundaries and reduced
+        formatting overhead. The old 'log4j2.formatMsgNoLookups' which enabled this behavior has been removed as well
+        as the 'nolookups' message pattern converter option. The old behavior can be enabled on a per-pattern basis
+        using '%m{lookups}'.
+      </action>
+      <action issue="LOG4J2-3194" dev="rgoers" type="add" due-to="markuss">
+        Allow fractional attributes for size attribute of SizeBsaedTriggeringPolicy.
+      </action>
+      <action issue="LOG4J2-2978" dev="rgoers" type="add" due-to="Michael Seele">
+        Add support for Jakarta EE 9 (Tomcat 10 / Jetty 11)
+      </action>
+      <action issue="LOG4J2-3189" dev="ckozak" type="add">
+        Improve NameAbbreviator worst-case performance.
+      </action>
+      <action issue="LOG4J2-3170" dev="vy" type="add" due-to="Gareth Smith">
+        Make CRLF/HTML encoding run in O(n) worst-case time, rather than O(n^2).
+      </action>
+      <action issue="LOG4J2-3133" dev="ckozak" type="add">
+        Add missing slf4j-api singleton accessors to log4j-slf4j-impl (1.7) StaticMarkerBinder and StaticMDCBinder.
+        This doesn't impact behavior or correctness, but avoids throwing and catching NoSuchMethodErrors when slf4j
+        is initialized and avoids linkage linting warnings.
+      </action>
+      <action issue="LOG4J2-2885" dev="vy" type="add" due-to="Markus Spann">
+        Add support for US-style date patterns and micro/nano seconds to FixedDateTime.
+      </action>
+      <action issue="LOG4J2-3116" dev="rgupta" type="add">
+        Add JsonTemplateLayout for Google Cloud Platform structured logging layout.
+      </action>
+      <action issue="LOG4J2-3067" dev="vy" type="add">
+        Add CounterResolver to JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-3074" dev="vy" type="add">
+        Add replacement parameter to ReadOnlyStringMapResolver.
+      </action>
+      <action issue="LOG4J2-3051" dev="vy" type="add">
+        Add CaseConverterResolver to JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-3064" dev="rgoers" type="add">
+        Add Arbiters and SpringProfile plugin.
+      </action>
+      <action issue="LOG4J2-3056" dev="vy" type="add" due-to="Marcono1234">
+        Refactor MD5 usage for sharing sensitive information.
+      </action>
+      <action issue="LOG4J2-3004" dev="vy" type="add">
+        Add plugin support to JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-3050" dev="rgoers" type="add">
+        Allow AdditionalFields to be ignored if their value is null or a zero-length String.
+      </action>
+      <action issue="LOG4J2-3049" dev="rgoers" type="add">
+        Allow MapMessage and ThreadContext attributes to be prefixed.
+      </action>
+      <action issue="LOG4J2=3048" dev="rgoers" type="add">
+        Add improved MapMessge support to GelfLayout.
+      </action>
+      <action issue="LOG4J2-3044" dev="rgoers" type="add">
+        Add RepeatPatternConverter.
+      </action>
+      <action issue="LOG4J2-2940" dev="ckozak" type="add">
+        Context selectors are aware of their dependence upon the callers ClassLoader, allowing
+        basic context selectors to avoid the unnecessary overhead of walking the stack to
+        determine the caller's ClassLoader.
+      </action>
+      <action issue="LOG4J2-2940" dev="ckozak" type="add">
+        Add BasicAsyncLoggerContextSelector equivalent to AsyncLoggerContextSelector for
+        applications with a single LoggerContext. This selector avoids classloader lookup
+        overhead incurred by the existing AsyncLoggerContextSelector.
+      </action>
+      <action issue="LOG4J2-3041" dev="rgoers" type="add">
+        Allow a PatternSelector to be specified on GelfLayout.
+      </action>
+      <action issue="LOG4J2-3141" dev="ckozak" type="add">
+        Avoid ThreadLocal overhead in RandomAccessFileAppender, RollingRandomAccessFileManager,
+        and MemoryMappedFileManager due to the unused setEndOfBatch and isEndOfBatch methods.
+        The methods on LogEvent are preferred.
+      </action>
+      <action issue="LOG4J2-3144" dev="ckozak" type="add">
+        Prefer string.getBytes(Charset) over string.getBytes(String)
+	based on performance improvements in modern Java releases.
+      </action>
+      <action issue="LOG4J2-3171" dev="ckozak" type="add">
+        Improve PatternLayout performance by reducing unnecessary indirection and branching.
+      </action>
+      <!-- FIXES -->
+      <action issue="LOG4J2-3166" dev="rgoers">
+        Fix Log Event Level vs Logger Config Level table.
+      </action>
+      <action issue="LOG4J2-2540" dev="rgoers">
+        Minor documentation correctsion regarding log levels.
+      </action>
+      <action issue="LOG4J2-2541" dev="rgoers" due-to="Gerold Broser">
+        Minor documentation corrections in the configuration section.
+      </action>
+      <action issue="LOG4J2-2553" dev="rgoers">
+        Correct documentation for SyslogAppender when using TLS.
+      </action>
+      <action issue="LOG4J2-1798" dev="rgoers" due-to="Viacheslav Zhivaev">
+        Handle interrupted exceptions that occur during rollover.
+      </action>
+      <action issue="LOG4J2-2951" dev="rgoers">
+        Log4j 1.x properties were not being substituted.
+      </action>
+      <action issue="LOG4J2-3201" dev="rgoers" type="fix">
+        Limit the protocols JNDI can use by default. Limit the servers and classes that can be accessed via LDAP.
+      </action>
+      <action issue="LOG4J2-3114" dev="rgoers" type="fix" due-to="Barnabas Bodnar">
+        Enable immediate flush on RollingFileAppender when buffered i/o is not enabled.
+      </action>
+      <action issue="LOG4J2-3168" dev="rgoers" type="fix" due-to="Benjamin Wöster">
+       Fix bug when file names contain regex characters.
+      </action>
+      <action issue="LOG4J2-3110" dev="rgoers" type="fix" due-to="Arturo Bernal">
+        Fix the number of {}-placeholders in the string literal argument does not match the number of other arguments
+        to the logging call.
+      </action>
+      <action issue="LOG4J2-3060" dev="vy" type="fix" due-to=" Nikita Mikhailov">
+        Fix thread-safety issues in DefaultErrorHandler.
+      </action>
+      <action issue="LOG4J2-3185" dev="vy" type="fix" due-to="mzbonnt">
+        Fix thread-safety issues in DefaultErrorHandler.
+      </action>
+      <action issue="LOG4J2-3183" dev="vy" type="fix">
+        Avoid using MutableInstant of the event as a cache key in JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-2829" dev="vy" type="fix">
+        SocketAppender should propagate failures when reconnection fails.
+      </action>
+      <action issue="LOG4J2-3172" dev="vy" type="fix" due-to="Barry Fleming">
+        Buffer immutable log events in the SmtpManager.
+      </action>
+      <action issue="LOG4J2-3175" dev="vy" type="fix" due-to="wuqian0808">
+        Avoid KafkaManager override when topics differ.
+      </action>
+      <action issue="LOG4J2-3160" dev="vy" type="fix" due-to="Lars Bohl">
+        Fix documentation on how to toggle log4j2.debug system property.
+      </action>
+      <action issue="LOG4J2-3159" dev="ckozak" type="fix">
+        Fixed an unlikely race condition in Log4jMarker.getParents() volatile access.
+      </action>
+      <action issue="LOG4J2-3153" dev="ckozak" type="fix">
+        DatePatternConverter performance is not impacted by microsecond-precision clocks when such precision isn't
+        required.
+      </action>
+      <action issue="LOG4J2-2808" dev="ckozak" type="fix" due-to="Asapha Halifa">
+        LoggerContext skips resolving localhost when hostName is configured.
+      </action>
+      <action issue="LOG4J2-3150" dev="ckozak" type="fix">
+        RandomAccessFile appender uses the correct default buffer size of 256 kB
+        rather than the default appender buffer size of 8 kB.
+      </action>
+      <action issue="LOG4J2-3142" dev="ckozak" type="fix" due-to="John Meikle">
+        log4j-1.2-api implements LogEventAdapter.getTimestamp() based on the original event timestamp
+        instead of returning zero.
+      </action>
+      <action issue="LOG4J2-3083" dev="ckozak" type="fix">
+        log4j-slf4j-impl and log4j-slf4j18-impl correctly detect the calling class using both LoggerFactory.getLogger
+        methods as well as LoggerFactory.getILoggerFactory().getLogger.
+      </action>
+      <action issue="LOG4J2-2816" dev="vy" type="fix" due-to="Jacob Shields">
+        Handle Disruptor event translation exceptions.
+      </action>
+      <action issue="LOG4J2-3121" dev="ggregory" type="fix" due-to="Markus Spann">
+          log4j2 config modified at run-time may trigger incomplete MBean re-initialization due to InstanceAlreadyExistsException.
+      </action>
+      <action issue="LOG4J2-3107" dev="vy" type="fix" due-to="Markus Spann">
+        SmtpManager.createManagerName ignores port.
+      </action>
+      <action issue="LOG4J2-3080" dev="vy" type="fix">
+        Use SimpleMessage in Log4j 1 Category whenever possible.
+      </action>
+      <action issue="LOG4J2-3102" dev="ckozak" type="fix">
+        Fix a regression in 2.14.1 which allowed the AsyncAppender background thread to keep the JVM alive because
+        the daemon flag was not set.
+      </action>
+      <action issue="LOG4J2-3103" dev="ckozak" type="fix" due-to="Mike Glazer">
+        Fix race condition which can result in ConcurrentModificationException on context.stop.
+      </action>
+      <action issue="LOG4J2-3092" dev="vy" type="fix" due-to="xmh51">
+        Fix JsonWriter memory leaks due to retained excessive buffer growth.
+      </action>
+      <action issue="LOG4J2-3089" dev="vy" type="fix" due-to="Tim Perry">
+        Fix sporadic JsonTemplateLayoutNullEventDelimiterTest failures on Windows.
+      </action>
+      <action issue="LOG4J2-3075" dev="vy" type="fix">
+        Fix formatting of nanoseconds in JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-3087" dev="vy" type="fix" due-to="Anton Klarén">
+        Fix race in JsonTemplateLayout where a timestamp could end up unquoted.
+      </action>
+      <action issue="LOG4J2-3070" dev="vy" type="fix" due-to="Romain Manni-Bucau">
+        Ensure EncodingPatternConverter#handlesThrowable is implemented.
+      </action>
+      <action issue="LOG4J2-3054" dev="ckozak" type="fix">
+        BasicContextSelector hasContext and shutdown take the default context into account
+      </action>
+      <action issue="LOG4J2-2940" dev="ckozak" type="fix">
+        Slf4j implementations walk the stack at most once rather than twice to determine the caller's class loader.
+      </action>
+      <action issue="LOG4J2-2965" dev="ckozak" type="fix">
+        Fixed a deadlock between the AsyncLoggerContextSelector and java.util.logging.LogManager by updating Disruptor to 3.4.4.
+      </action>
+      <action issue="LOG4J2-3095" dev="ggregory" type="fix" due-to="Kenny MacLeod, Gary Gregory">
+        Category.setLevel should accept null value.
+      </action>
+      <action issue="LOG4J2-3174" dev="vy" type="fix" due-to="romainmoreau">
+        Wrong subject on mail when it depends on the LogEvent
+      </action>
+      <!-- UPDATES -->
+      <action dev="rgoers" issue="" type="update">
+        Update Spring framework to 5.3.13, Spring Boot to 2.5.7, and Spring Cloud to 2020.0.4.
+      </action>
+      <action issue="LOG4J2-2025" dev="rgoers" type="update">
+        Provide support for overriding the Tomcat Log class in Tomcat 8.5+.
+      </action>
+      <action dev="ggregory" issue="" type="update">
+        Updated dependencies.
+
+        - com.fasterxml.jackson.core:jackson-annotations ................. 2.12.2 -> 2.12.4
+        - com.fasterxml.jackson.core:jackson-core ........................ 2.12.2 -> 2.12.4
+        - com.fasterxml.jackson.core:jackson-databind .................... 2.12.2 -> 2.12.4
+        - com.fasterxml.jackson.dataformat:jackson-dataformat-xml ........ 2.12.2 -> 2.12.4
+        - com.fasterxml.jackson.dataformat:jackson-dataformat-yaml ....... 2.12.2 -> 2.12.4
+        - com.fasterxml.jackson.module:jackson-module-jaxb-annotations ... 2.12.2 -> 2.12.4
+        - com.fasterxml.woodstox:woodstox-core ........................... 6.2.4 -> 6.2.6
+        - commons-io:commons-io .......................................... 2.8.0 -> 2.11.0
+        - net.javacrumbs.json-unit:json-unit ............................. 2.24.0 -> 2.25.0
+        - net.javacrumbs.json-unit:json-unit ............................. 2.25.0 -> 2.27.0
+        - org.apache.activemq:activemq-broker ............................ 5.16.1 -> 5.16.2
+        - org.apache.activemq:activemq-broker ............................ 5.16.2 -> 5.16.3
+        - org.apache.commons:commons-compress ............................ 1.20 -> 1.21
+        - org.apache.commons:commons-csv ................................. 1.8 -> 1.9.0
+        - org.apache.commons:commons-dbcp2 ............................... 2.8.0 -> 2.9.0
+        - org.apache.commons:commons-pool2 ............................... 2.9.0 -> 2.11.1
+        - org.apache.maven.plugins:maven-failsafe-plugin ................. 2.22.2 -> 3.0.0-M5
+        - org.apache.maven.plugins:maven-surefire-plugin ................. 2.22.2 -> 3.0.0-M5
+        - org.apache.rat:apache-rat-plugin ............................... 0.12 -> 0.13
+        - org.assertj:assertj-core ....................................... 3.19.0 -> 3.20.2
+        - org.codehaus.groovy:groovy-dateutil ............................ 3.0.7 -> 3.0.8
+        - org.codehaus.groovy:groovy-jsr223 .............................. 3.0.7 -> 3.0.8
+        - org.codehaus.plexus:plexus-utils ............................... 3.3.0 -> 3.4.0
+        - org.eclipse.persistence:javax.persistence ...................... 2.1.1 -> 2.2.1
+        - org.eclipse.persistence:org.eclipse.persistence.jpa ............ 2.6.5 -> 2.6.9
+        - org.eclipse.persistence:org.eclipse.persistence.jpa ............ 2.7.8 -> 2.7.9
+        - org.fusesource.jansi ........................................... 2.3.2 -> 2.3.4
+        - org.fusesource.jansi:jansi ..................................... 2.3.1 -> 2.3.2
+        - org.hsqldb:hsqldb .............................................. 2.5.1 -> 2.5.2
+        - org.junit.jupiter:junit-jupiter-engine ......................... 5.7.1 -> 5.7.2
+        - org.junit.jupiter:junit-jupiter-migrationsupport ............... 5.7.1 -> 5.7.2
+        - org.junit.jupiter:junit-jupiter-params ......................... 5.7.1 -> 5.7.2
+        - org.junit.vintage:junit-vintage-engine ......................... 5.7.1 -> 5.7.2
+        - org.liquibase:liquibase-core ................................... 3.5.3 -> 3.5.5
+        - org.mockito:mockito-core ....................................... 3.8.0 -> 3.11.2
+        - org.mockito:mockito-junit-jupiter .............................. 3.8.0 -> 3.11.2
+        - org.springframework:spring-aop ................................. 5.3.3 -> 5.3.9
+        - org.springframework:spring-beans ............................... 5.3.3 -> 5.3.9
+        - org.springframework:spring-context ............................. 5.3.3 -> 5.3.9
+        - org.springframework:spring-context-support ..................... 5.3.3 -> 5.3.9
+        - org.springframework:spring-core ................................ 5.3.3 -> 5.3.9
+        - org.springframework:spring-expression .......................... 5.3.3 -> 5.3.9
+        - org.springframework:spring-oxm ................................. 5.3.3 -> 5.3.9
+        - org.springframework:spring-test ................................ 5.3.3 -> 5.3.9
+        - org.springframework:spring-web ................................. 5.3.3 -> 5.3.9
+        - org.springframework:spring-webmvc .............................. 5.3.3 -> 5.3.9
+        - org.tukaani:xz ................................................. 1.8 -> 1.9
+      </action>
+    </release>
+    <release version="2.14.1" date="2021-03-06" description="GA Release 2.14.1">
+      <!-- FIXES -->
+      <action issue="LOG4J2-3033" dev="rgoers" type="fix">
+        Add log method with no parameters - i.e. it has an empty message.
+      </action>
+      <action issue="LOG4J2-2947" dev="rgoers" type="fix">
+        Document that LogBuilder default methods do nothing.
+      </action>
+      <action issue="LOG4J2-2948" dev="vy" type="fix">
+        Replace HashSet with IdentityHashMap in ParameterFormatter to detect cycles.
+      </action>
+      <action issue="LOG4J2-3028" dev="ckozak" type="fix" due-to="Jakub Kozlowski">
+        OutputStreamManager.flushBuffer always resets the buffer, previously the buffer was not reset after an exception.
+      </action>
+      <action issue="LOG4J2-2981" dev="rgoers" type="fix">
+        OnStartupTriggeringPolicy would fail to cause the file to roll over with DirectWriteTriggeringPolicy
+        unless minSize was set to 0.
+      </action>
+      <action issue="LOG4J2-2990" dev="rgoers" type="fix" due-to="Diogo Monteiro">
+        Reduce garbage by using putAll when copying the ThreadContext for SLF4J.
+      </action>
+      <action issue="LOG4J2-3006" dev="rgoers" type="fix">
+        Directly create a thread instead of using the common ForkJoin pool when initializing ThreadContextDataInjector"
+      </action>
+      <action issue="LOG4J2-2624" dev="mattsicker" type="fix" due-to="Tim Perry">
+        Allow auto-shutdown of log4j in log4j-web to be turned off and provide a
+        ServletContextListener "Log4jShutdownOnContextDestroyedListener" to stop log4j.
+        Register the listener at the top of web.xml to ensure the shutdown happens last.
+      </action>
+      <action issue="LOG4J2-1606" dev="mattsicker" type="fix" due-to="Tim Perry">
+        Allow auto-shutdown of log4j in log4j-web to be turned off and provide a
+        ServletContextListener "Log4jShutdownOnContextDestroyedListener" to stop log4j.
+        Register the listener at the top of web.xml to ensure the shutdown happens last.
+      </action>
+      <action issue="LOG4J2-2998" dev="vy" type="fix">
+        Fix truncation of excessive strings ending with a high surrogate in JsonWriter.
+      </action>
+      <action issue="LOG4J2-2977" dev="vy" due-to="Ron Grabowski">
+        Replace outdated PatternLayout.createLayout() calls in docs with createDefaultLayout().
+      </action>
+      <action issue="LOG4J2-2973" dev="vy" type="fix" due-to="Fabio Ricchiuti">
+        Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to "format".
+      </action>
+      <action issue="LOG4J2-2972" dev="vy" type="fix">
+        Refactor AsyncAppender and AppenderControl for handling of Throwables.
+      </action>
+      <action issue="LOG4J2-2985" dev="vy" type="fix">
+        Add eventTemplateRootObjectKey parameter to JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-2974" dev="rgoers" type="fix">
+        Log4j would fail to initialize in Java 8 with log4j-spring-boot.
+      </action>
+      <action issue="LOG4J2-2964" dev="vy" type="fix" due-to="Valery Yatsynovich">
+        Merge packages from several Configurations in Composite Configuration.
+      </action>
+      <action issue="LOG4J2-2961" dev="vy" type="fix">
+        Fix reading of JsonTemplateLayout event additional fields from config.
+      </action>
+      <action issue="LOG4J2-2916" dev="vy" type="fix" due-to="wuqian0808">
+        Avoid redundant Kafka producer instantiation causing thread leaks.
+      </action>
+      <action issue="LOG4J2-2967" dev="ckozak" type="fix">
+        Fix JsonTemplateLayout index based parameter resolution when messages contain too few parameters.
+      </action>
+      <action issue="LOG4J2-2976" dev="ckozak" type="fix">
+        JdbcAppender composes an incorrect INSERT statement without a ColumnMapping element.
+      </action>
+      <action issue="LOG4J2-3014" dev="ggregory" type="fix" due-to="Lee Breisacher, Gary Gregory">
+        Log4j1ConfigurationConverter on Windows produces "&#xd;" at end of every line.
+      </action>
+      <action issue="LOG4J2-3131" dev="ggregory" type="fix" due-to="Adam Long, Gary Gregory">
+        Attempting to call getExtendedStackTraceAsString() after deserializing JSON LogEvent results in a NPE.
+      </action>
+      <action issue="LOG4J2-3131" dev="ggregory" type="fix" due-to="Gary Gregory">
+        NoGcLayout allocates empty bytes arrays for its header and footer.
+      </action>
+      <!-- ADDS -->
+      <action issue="LOG4J2-2962" dev="vy" type="add">
+        Enrich "map" resolver by unifying its backend with "mdc" resolver.
+      </action>
+      <action issue="LOG4J2-2999" dev="vy" type="add">
+        Replace JsonTemplateLayout resolver configurations table in docs with sections.
+      </action>
+      <action issue="LOG4J2-2993" dev="vy" type="add">
+        Support stack trace truncation in JsonTemplateLayout.
+      </action>
+      <!-- UPDATES -->
+      <action issue="LOG4J2-2923" dev="rgoers" type="update">
+        Add Rollover Listener to aid in unit test validation.
+      </action>
+      <action issue="LOG4J2-2893" dev="rgoers" type="update">
+        Allow reconfiguration when Log4j 1 configuration files are updated.
+      </action>
+      <action dev="rgoers" type="update">
+        Update Spring dependencies to 5.3.2, Spring Boot to 2.3.6, and Spring Cloud to Hoxton.SR9
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.fusesource.jansi:jansi 1.17.1 -> 2.0.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update commons-codec:commons-codec 1.14 -> 1.15.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-lang3 3.10 -> 3.11.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-pool2 2.8.1 -> 2.9.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-dbcp2 2.4.0 -> 2.8.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update commons-io:commons-io 2.7 -> 2.8.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.codehaus.groovy:* 3.0.5 -> 3.0.6.
+      </action>
+      <action dev="ggregory" type="update">
+        Update com.fasterxml.jackson.*:* 2.11.2 - 2.11.3.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.springframework:* 5.2.8.RELEASE -> 5.3.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update junit:junit 4.13 -> 4.13.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.xmlunit:* 2.7.0 -> 2.8.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.assertj:assertj-core 3.14.0 -> 3.18.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.awaitility:awaitility 4.0.2 -> 4.0.3.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.codehaus.plexus:plexus-utils 3.2.0 -> 3.3.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update MongoDB 3 plugin: org.mongodb:mongodb-driver 3.12.6 -> 3.12.7.
+      </action>
+      <action dev="ggregory" type="update">
+        Update MongoDB 4 plugin: org.mongodb:* 4.1.0 -> 4.1.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.eclipse.tycho:org.eclipse.osgi 3.12.1.v20170821-1548 -> 3.13.0.v20180226-1711.
+      </action>
+      <action dev="ggregory" type="update">
+        Update de.flapdoodle.embed:de.flapdoodle.embed.mongo 2.2.0 -> 3.0.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update net.javacrumbs.json-unit:json-unit 1.31.1 -> 2.22.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update Mockito 3.6.0 -> 3.7.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update XML Unit 2.8.0 -> 2.8.2.
+      </action>
+      <action dev="ggregory" type="update">
+        Update JSON Unit 2.21.0 -> 2.22.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update JaCoCo 0.8.3 -> 0.8.6.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.activemq:* 5.16.0 -> 5.16.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.mockito:mockito-* 3.7.0 -> 3.7.7.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.springframework:* 5.3.2 -> 5.3.3.
+      </action>
+      <action dev="ggregory" type="update">
+        Update mongodb4.version 4.1.1 -> 4.2.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.fusesource.jansi:jansi 1.18 -> 2.2.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.assertj:assertj-core 3.18.1 -> 3.19.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update net.javacrumbs.json-unit:json-unit 2.22.0 -> 2.23.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update Woodstox 5.0.3 -> 6.2.3 to match Jackson 2.12.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.activemq:* 5.16.0 -> 5.16.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.mockito:mockito-* 3.7.0 -> 3.7.7.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.springframework:* 5.3.2 -> 5.3.3.
+      </action>
+      <action dev="ggregory" type="update">
+        Update mongodb4.version 4.1.1 -> 4.2.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.fusesource.jansi:jansi 1.18 -> 2.3.1.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.assertj:assertj-core 3.18.1 -> 3.19.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update net.javacrumbs.json-unit:json-unit 2.22.0 -> 2.23.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update net.javacrumbs.json-unit:json-unit 2.22.0 -> 2.23.0.
+      </action>
+      <action dev="ggregory" type="update">
+        - com.fasterxml.jackson.core:jackson-annotations ................. 2.12.1 -> 2.12.2
+        - com.fasterxml.jackson.core:jackson-core ........................ 2.12.1 -> 2.12.2
+        - com.fasterxml.jackson.core:jackson-databind .................... 2.12.1 -> 2.12.2
+        - com.fasterxml.jackson.dataformat:jackson-dataformat-xml ........ 2.12.1 -> 2.12.2
+        - com.fasterxml.jackson.dataformat:jackson-dataformat-yaml ....... 2.12.1 -> 2.12.2
+        - com.fasterxml.jackson.module:jackson-module-jaxb-annotations ... 2.12.1 -> 2.12.2
+        - org.apache.commons:commons-lang3 ............................... 3.11   -> 3.12.0
+        - org.junit.jupiter:junit-jupiter-engine ......................... 5.7.0  -> 5.7.1
+        - org.junit.jupiter:junit-jupiter-migrationsupport ............... 5.7.0  -> 5.7.1
+        - org.junit.jupiter:junit-jupiter-params ......................... 5.7.0  -> 5.7.1
+        - org.junit.vintage:junit-vintage-engine ......................... 5.7.0  -> 5.7.1
+        - org.mockito:mockito-core ....................................... 3.7.7  -> 3.8.0
+        - org.mockito:mockito-junit-jupiter .............................. 3.7.7  -> 3.8.0
+        - org.mongodb:bson ............................................... 4.2.0  -> 4.2.2
+        - org.mongodb:mongodb-driver-sync ................................ 4.2.0  -> 4.2.2
+      </action>
+    </release>
+    <release version="2.14.0" date="2020-11-06" description="GA Release 2.14.0">
+      <action issue="LOG4J2-2925" dev="rgoers" type="fix">
+        Fix broken link in FAQ.
+      </action>
+      <action issue="LOG4J2-2957" dev="vy" type="add">
+        Add JsonTemplateLayout.
+      </action>
+      <action issue="LOG4J2-2911" dev="rgoers" type="fix">
+        Log4j2EventListener in spring.cloud.config.client listens for wrong event.
+      </action>
+      <action issue="LOG4J2-2889" dev="mattsicker" type="update" due-to="Geng Yuanzhe">
+        Add date pattern support for HTML layout.
+      </action>
+      <action issue="LOG4J2-2919" dev="mattsicker" type="fix" due-to="Geng Yuanzhe">
+        Call ReliabilityStrategy's beforeStopAppenders() method before stopping AsyncAppender.
+      </action>
+      <action issue="LOG4J2-2892" dev="rgoers" type="update" due-to="Jakub Lukes">
+        Allow GelfLayout to produce newline delimited events.
+      </action>
+      <action issue="LOG4J2-2906" dev="rgoers" type="fix" due-to="Stephen Joyner">
+        Fix UnsupportedOperationException when initializing the Log4j2CloudConfigLoggingSystem.
+      </action>
+      <action issue="LOG4J2-2908" dev="rgoers" type="fix">
+        Move Spring Lookup and Spring PropertySource to its own module.
+      </action>
+      <action issue="LOG4J2-2910" dev="rgoers" type="fix">
+        Log4j-web should now stores the servlet context as a map entry instead of in the single external context field.
+      </action>
+      <action issue="LOG4J2-2822" dev="rgoers" type="fix">
+        Javadoc link in ThreadContext description was incorrect.
+      </action>
+      <action issue="LOG4J2-2894" dev="rgoers" type="fix">
+        Fix spelling error in log message.
+      </action>
+      <action issue="LOG4J2-2901" dev="rgoers" type="fix">
+        Missing configuration files should be ignored when creating a composite configuration.
+      </action>
+      <action issue="LOG4J2-2883" dev="rgoers" type="fix">
+        When using DirectFileRolloverStrategy the file pattern was not being recalculated on
+        size based rollover after a time based rollover had occurred.
+      </action>
+      <action issue="LOG4J2-2875" dev="rgoers" type="fix">
+        Rollover was failing to create directories when using a DirectFileeRolloverStrategy.
+      </action>
+      <action issue="LOG4J2-2859" dev="rgoers" type="fix" due-to="Yanming Zhou">
+        Fixed typos where mergeFactory should be mergeStrategy.
+      </action>
+      <action issue="LOG4J2-2832" dev="rgoers" type="fix" due-to="Benjamin Asbach">
+        Correct class name printed in error message in RollingFileAppender.
+      </action>
+      <action issue="LOG4J2-2882" dev="rgoers" type="fix" due-to="Emmanuel Bourg">
+        Support java.util.logging filters when using that API.
+      </action>
+      <action issue="LOG4J2-2880" dev="rgoers" type="fix">
+        Create StackWalker benchmark. Revert back to StackWalker.walk based on benchmark results.
+      </action>
+      <action issue="LOG4J2-2867" dev="rgoers" type="fix">
+        Obtain ContextDataProviders asynchronously.
+      </action>
+      <action issue="LOG4J2-2877" dev="rgoers" type="fix">
+        Determine the container id to obtain container and image information.
+      </action>
+      <action issue="LOG4J2-2844" dev="ggregory" type="fix">
+        Null pointer exception when no network interfaces are available.
+      </action>
+      <action issue="LOG4J2-2848" dev="ggregory" type="add">
+        Create module log4j-mongodb4 to use new major version 4 MongoDB driver.
+      </action>
+      <action issue="LOG4J2-2851" dev="ggregory" type="remove">
+        Drop log4j-mongodb2 module.
+      </action>
+      <action dev="ggregory" type="update">
+        Update MongoDB tests to require Java 8 unconditionally now that Log4j requires Java 8.
+      </action>
+      <action dev="ggregory" type="update">
+		Update mongodb3.version from 3.12.1 to 3.12.6.
+      </action>
+      <action dev="ggregory" type="update">
+        Update com.fasterxml.jackson.* 2.10.2 -> 2.11.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.activemq:activemq-broker 5.15.11 -> 5.16.0.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-compress 1.19 -> 1.20.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-csv 1.7 -> 1.8.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.apache.commons:commons-lang3 3.9 -> 3.10.
+      </action>
+      <action dev="ggregory" type="update">
+        Update org.codehaus.groovy:* 2.5.6 -> 3.0.5.
+      </action>
+      <action dev="ggregory" type="update">
+        Update tests junit:junit 4.12 -> 4.13.
+      </action>
+      <action dev="ggregory" type="update">
+        Update tests commons-io:commons-io 2.6 -> 2.7.
+      </action>
+      <action dev="ggregory" type="update">
+        Update jackson 2.11.0 -> 2.11.2.
+      </action>
+      <action dev="ggregory" type="update">
+        Update tests hsqldb 2.5.0 -> 2.5.1.
+      </action>
+      <action issue="LOG4J2-2895" dev="ckozak" type="fix">
+        Fix potential deadlock in asynchronous logging by avoiding blocking for queue space on Log4jThreads
+      </action>
+      <action issue="LOG4J2-2837" dev="ckozak" type="fix">
+        Disruptor and JUL no longer recursively start the AsyncLoggerDisruptor
+        resulting in an extra disruptor background thread constantly waiting.
+      </action>
+      <action issue="LOG4J2-2867" dev="ckozak" type="fix">
+        RingBufferLogEventTranslator uses a static ContextDataInjector instead of initializing a new object
+        on each thread.
+      </action>
+      <action issue="LOG4J2-2858" dev="ckozak" type="add" due-to="Stepan Gorban">
+        More flexible configuration of the Disruptor WaitStrategy.
+      </action>
+      <action issue="LOG4J2-2898" dev="ckozak" type="fix" due-to="Turbanov Andrey">
+        Avoid initializing volatile fields with default values.
+      </action>
+      <action issue="LOG4J2-2899" dev="ckozak" type="fix">
+        Fix log4j-1.2-api LogEventWrapper threadId and priority accessors when called multiple times.
+      </action>
+      <action issue="LOG4J2-2939" dev="ckozak" type="fix" due-to="Constantin Hirsch">
+        Fix NPE in MDCContextMap on 'contains' and 'isEmpty' invocations.
+      </action>
+      <action issue="LOG4J2-2954" dev="ckozak" type="fix" due-to="Henry Tung">
+        Prevent premature garbage collection of shutdown hooks in DefaultShutdownCallbackRegistry.
+      </action>
+    </release>
+    <release version="2.13.3" date="2020-05-10" description="GA Release 2.13.3">
+      <action issue="LOG4J2-2838" dev="rgoers" type="fix">
+        Fix NullPointerException in ThreadContextDataInjector.
+      </action>
+    </release>
+    <release version="2.13.2" date="2020-04-23" description="GA Release 2.13.2">
+      <action issue="LOG4J2-2824" dev="rgoers" type="fix" due-to="CrazyBills">
+        Implement requiresLocation in GelfLayout to reflect whether location information is used in the message Pattern.
+      </action>
+      <action issue="LOG4J2-2588" dev="rgoers" type="fix">
+        Add option to restore printing timeMillis in the JsonLayout.
+      </action>
+      <action issue="LOG4J2-2766" dev="rgoers" type="fix">
+        Initialize pattern processor before triggering policy during reconfiguration.
+      </action>
+      <action issue="LOG4J2-2457" dev="rgoers" type="update">
+        Allow the file extension in the file pattern to be modified during reconfiguration.
+      </action>
+      <action issue="LOG4J2-2810" dev="rgoers" type="fix">
+        Add information about using a url in log4j.configurationFile.
+      </action>
+      <action issue="LOG4J2-2813" dev="rgoers" type="fix" due-to="Keith D Gregory">
+        serializeToBytes was checking wrong variable for null.
+      </action>
+      <action issue="LOG4J2-2814" dev="rgoers" type="fix">
+        Fix Javadoc for ScriptPatternSelector.
+      </action>
+      <action issue="LOG4J2-2793" dev="rgoers" type="fix" due-to="Renukaprasad C">
+        Allow trailing and leading spaces in log level.
+>>>>>>> 4a4b753 [LOG4J2-3242] Rename JNDI enablement property from 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'.
       </action>
       <action issue="LOG4J2-2819" dev="mattsicker" type="update">
         Add support for specifying an SSL configuration for SmtpAppender.
diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml
index d1c14fa..03c660e 100644
--- a/src/site/xdoc/manual/appenders.xml
+++ b/src/site/xdoc/manual/appenders.xml
@@ -1527,6 +1527,12 @@ public class ConnectionFactory {
         <a name="JMSTopicAppender"/>
         <subsection name="JMS Appender">
           <p>The JMS Appender sends the formatted log event to a JMS Destination.</p>
+<<<<<<< log4j-2.12
+=======
+          <p>The JMS Appender requires JNDI support so as of release 2.16.0 this appender will not function unless
+            <code>log4j2.enableJndiJms=true</code> is configured as a system property or environment
+            variable. See the <a href="./configuration.html#enableJndiJms">enableJndiJms</a> system property.</p>
+>>>>>>> 4a4b753 [LOG4J2-3242] Rename JNDI enablement property from 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'.
           <p>
             Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting
             in Log4j 2.1, these appenders were combined into the JMS Appender which makes no distinction between queues
diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm
index 727a323..ef8280d 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -1938,6 +1938,59 @@ public class AwesomeTest {
     </td>
   </tr>
   <tr>
+<<<<<<< log4j-2.12
+=======
+    <td><a name="enableJndiContextSelector"/>log4j2.enableJndiContextSelector</td>
+    <td>LOG4J_ENABLE_JNDI_CONTEXT_SELECTOR</td>
+    <td>false</td>
+    <td>
+      When true, the Log4j context selector that uses the JNDI java protocol is enabled. When false, the default, they are disabled.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="enableJndiJms"/>log4j2.enableJndiJms</td>
+    <td>LOG4J_ENABLE_JNDI_JMS</td>
+    <td>false</td>
+    <td>
+      When true, the Log4j JMS Appender that uses JNDI's java protocol is enabled. When false, the default, they are disabled.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="enableJndiLookup"/>log4j2.enableJndiLookup</td>
+    <td>LOG4J_ENABLE_JNDI_LOOKUP</td>
+    <td>false</td>
+    <td>
+      When true, the Log4j lookup that uses JNDI's java protocol is enabled. When false, the default, they are disabled.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="allowedLdapClasses"/>log4j2.allowedLdapClasses</td>
+    <td>LOG4J_ALLOWED_LDAP_CLASSES</td>
+    <td>&nbsp;</td>
+    <td>
+      System property that specifies fully qualified class names that may be accessed by LDAP. The classes
+      must implement Serializable. By default only Java primitive classes are allowed.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="allowedLdapHosts"/>log4j2.allowedLdapHosts</td>
+    <td>LOG4J_ALLOWED_LDAP_HOSTS</td>
+    <td>&nbsp;</td>
+    <td>
+      System property that adds host names or ip addresses that may be access by LDAP. By default it only allows
+      the local host names and ip addresses.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="allowedJndiProtocols"/>log4j2.allowedJndiProtocols</td>
+    <td>LOG4J_ALLOWED_JNDI_PROTOCOLS</td>
+    <td>&nbsp;</td>
+    <td>
+      System property that adds protocol names that JNDI will allow. By default it only allows java, ldap, and ldaps.
+    </td>
+  </tr>
+  <tr>
+>>>>>>> 4a4b753 [LOG4J2-3242] Rename JNDI enablement property from 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'.
     <td><a name="uuidSequence"/>log4j2.uuidSequence
       <br />
       (<a name="org.apache.logging.log4j.uuidSequence"/>org.apache.logging.log4j.uuidSequence)