You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2024/04/04 21:50:48 UTC

(logging-log4j2) 10/14: Move non-API classes to core

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

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

commit 827dbe02b406af66e18178fb916d382d557b1a55
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Thu Apr 4 08:14:49 2024 -0700

    Move non-API classes to core
---
 .../org/apache/logging/log4j/test/TestLogger.java  |  10 +-
 .../org/apache/logging/log4j/ScopedContext.java    | 123 +++++++++++++--------
 .../apache/logging/log4j/simple/SimpleLogger.java  |   7 +-
 .../logging/log4j/spi/ContextDataProvider.java     |  76 -------------
 .../log4j/spi/ScopedContextDataProvider.java       | 104 -----------------
 .../logging/log4j/core/async/AsyncLogger.java      |   2 +-
 .../core/async/RingBufferLogEventTranslator.java   |   2 +-
 .../log4j/core/filter/DynamicThresholdFilter.java  |   4 +-
 .../log4j/core/filter/ThreadContextMapFilter.java  |   2 +-
 .../logging/log4j/core/impl}/ContextData.java      |   5 +-
 .../logging/log4j/core/impl/Log4jLogEvent.java     |   1 -
 .../log4j/core/impl/ReusableLogEventFactory.java   |   1 -
 .../log4j/core/impl/ScopedContextDataProvider.java |  27 +++--
 .../log4j/core/impl/ThreadContextDataInjector.java |  11 +-
 .../log4j/core/impl/ThreadContextDataProvider.java |  15 +++
 .../log4j/core/lookup/ContextMapLookup.java        |   2 +-
 .../apache/logging/log4j/core/osgi/Activator.java  |   6 +-
 .../log4j/core/util/ContextDataProvider.java       |  52 ++++++++-
 18 files changed, 190 insertions(+), 260 deletions(-)

diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java
index b308434cfc..5f1fb02de7 100644
--- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java
+++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java
@@ -23,9 +23,10 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ScopedContext;
+import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
@@ -80,8 +81,11 @@ public class TestLogger extends AbstractLogger {
             sb.append(' ');
         }
         sb.append(message.getFormattedMessage());
-        final Map<String, String> mdc = new HashMap<>(ContextData.size());
-        ContextData.addAll(mdc);
+        Map<String, ScopedContext.Renderable> contextMap = ScopedContext.getContextMap();
+        final Map<String, String> mdc = new HashMap<>(ThreadContext.getImmutableContext());
+        if (contextMap != null && !contextMap.isEmpty()) {
+            contextMap.forEach((key, value) -> mdc.put(key, value.render()));
+        }
         if (!mdc.isEmpty()) {
             sb.append(' ');
             sb.append(mdc);
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ScopedContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ScopedContext.java
index 67e2ba97fd..4081be5629 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ScopedContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ScopedContext.java
@@ -16,7 +16,9 @@
  */
 package org.apache.logging.log4j;
 
+import java.util.ArrayDeque;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
@@ -25,7 +27,6 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.function.Supplier;
-import org.apache.logging.log4j.spi.ScopedContextDataProvider;
 import org.apache.logging.log4j.status.StatusLogger;
 
 /**
@@ -52,6 +53,48 @@ public class ScopedContext {
 
     public static final Logger LOGGER = StatusLogger.getLogger();
 
+    private static final ThreadLocal<Deque<Instance>> scopedContext = new ThreadLocal<>();
+
+    /**
+     * Returns an immutable Map containing all the key/value pairs as Renderable objects.
+     * @return An immutable copy of the Map at the current scope.
+     */
+    private static Optional<Instance> getContext() {
+        Deque<Instance> stack = scopedContext.get();
+        if (stack != null) {
+            return Optional.of(stack.getFirst());
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Add the ScopeContext.
+     * @param context The ScopeContext.
+     */
+    private static void addScopedContext(Instance context) {
+        Deque<Instance> stack = scopedContext.get();
+        if (stack == null) {
+            stack = new ArrayDeque<>();
+            scopedContext.set(stack);
+        }
+        stack.addFirst(context);
+    }
+
+    /**
+     * Remove the top ScopeContext.
+     */
+    private static void removeScopedContext() {
+        Deque<Instance> stack = scopedContext.get();
+        if (stack != null) {
+            if (!stack.isEmpty()) {
+                stack.removeFirst();
+            }
+            if (stack.isEmpty()) {
+                scopedContext.remove();
+            }
+        }
+    }
+
     /**
      * @hidden
      * Returns an unmodifiable copy of the current ScopedContext Map. This method should
@@ -59,7 +102,7 @@ public class ScopedContext {
      * @return the Map of Renderable objects.
      */
     public static Map<String, Renderable> getContextMap() {
-        Optional<Instance> context = ScopedContextDataProvider.getContext();
+        Optional<Instance> context = getContext();
         if (context.isPresent()
                 && context.get().contextMap != null
                 && !context.get().contextMap.isEmpty()) {
@@ -74,7 +117,7 @@ public class ScopedContext {
      * @return the number of items in the context map.
      */
     public static int size() {
-        Optional<Instance> context = ScopedContextDataProvider.getContext();
+        Optional<Instance> context = getContext();
         return context.map(instance -> instance.contextMap.size()).orElse(0);
     }
 
@@ -85,7 +128,7 @@ public class ScopedContext {
      */
     @SuppressWarnings("unchecked")
     public static <T> T get(String key) {
-        Optional<Instance> context = ScopedContextDataProvider.getContext();
+        Optional<Instance> context = getContext();
         if (context.isPresent()) {
             Renderable renderable = context.get().contextMap.get(key);
             if (renderable != null) {
@@ -101,7 +144,7 @@ public class ScopedContext {
      * @return The value of the key in the current ScopedContext.
      */
     public static String getString(String key) {
-        Optional<Instance> context = ScopedContextDataProvider.getContext();
+        Optional<Instance> context = getContext();
         if (context.isPresent()) {
             Renderable renderable = context.get().contextMap.get(key);
             if (renderable != null) {
@@ -116,7 +159,7 @@ public class ScopedContext {
      * @param map The Map to add entries to.
      */
     public static void addAll(Map<String, String> map) {
-        Optional<Instance> context = ScopedContextDataProvider.getContext();
+        Optional<Instance> context = getContext();
         if (context.isPresent()) {
             Map<String, Renderable> contextMap = context.get().contextMap;
             if (contextMap != null && !contextMap.isEmpty()) {
@@ -136,16 +179,16 @@ public class ScopedContext {
     public static Instance where(String key, Object value) {
         if (value != null) {
             Renderable renderable = value instanceof Renderable ? (Renderable) value : new ObjectRenderable(value);
-            Instance parent = current().isPresent() ? current().get() : null;
+            Instance parent = getContext().isPresent() ? getContext().get() : null;
             return new Instance(parent, key, renderable);
         } else {
-            if (current().isPresent()) {
+            if (getContext().isPresent()) {
                 Map<String, Renderable> map = getContextMap();
                 map.remove(key);
                 return new Instance(map);
             }
         }
-        return current().isPresent() ? current().get() : new Instance();
+        return getContext().isPresent() ? getContext().get() : new Instance();
     }
 
     /**
@@ -167,8 +210,8 @@ public class ScopedContext {
     public static Instance where(Map<String, ?> map) {
         if (map != null && !map.isEmpty()) {
             Map<String, Renderable> renderableMap = new HashMap<>();
-            if (current().isPresent()) {
-                renderableMap.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                renderableMap.putAll(getContext().get().contextMap);
             }
             map.forEach((key, value) -> {
                 if (value == null || (value instanceof String && ((String) value).isEmpty())) {
@@ -180,7 +223,7 @@ public class ScopedContext {
             });
             return new Instance(renderableMap);
         } else {
-            return current().isPresent() ? current().get() : new Instance();
+            return getContext().isPresent() ? getContext().get() : new Instance();
         }
     }
 
@@ -194,15 +237,15 @@ public class ScopedContext {
         if (obj != null) {
             Renderable renderable = obj instanceof Renderable ? (Renderable) obj : new ObjectRenderable(obj);
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.put(key, renderable);
             new Instance(map).run(op);
         } else {
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.remove(key);
             new Instance(map).run(op);
@@ -220,8 +263,8 @@ public class ScopedContext {
         if (obj != null) {
             Renderable renderable = obj instanceof Renderable ? (Renderable) obj : new ObjectRenderable(obj);
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.put(key, renderable);
             if (executorService != null) {
@@ -233,8 +276,8 @@ public class ScopedContext {
             }
         } else {
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.remove(key);
             if (executorService != null) {
@@ -255,8 +298,8 @@ public class ScopedContext {
     public static void runWhere(Map<String, ?> map, Runnable op) {
         if (map != null && !map.isEmpty()) {
             Map<String, Renderable> renderableMap = new HashMap<>();
-            if (current().isPresent()) {
-                renderableMap.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                renderableMap.putAll(getContext().get().contextMap);
             }
             map.forEach((key, value) -> {
                 renderableMap.put(key, value instanceof Renderable ? (Renderable) value : new ObjectRenderable(value));
@@ -277,15 +320,15 @@ public class ScopedContext {
         if (obj != null) {
             Renderable renderable = obj instanceof Renderable ? (Renderable) obj : new ObjectRenderable(obj);
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.put(key, renderable);
             return new Instance(map).call(op);
         } else {
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.remove(key);
             return new Instance(map).call(op);
@@ -304,8 +347,8 @@ public class ScopedContext {
         if (obj != null) {
             Renderable renderable = obj instanceof Renderable ? (Renderable) obj : new ObjectRenderable(obj);
             Map<String, Renderable> map = new HashMap<>();
-            if (current().isPresent()) {
-                map.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                map.putAll(getContext().get().contextMap);
             }
             map.put(key, renderable);
             if (executorService != null) {
@@ -318,8 +361,8 @@ public class ScopedContext {
         } else {
             if (executorService != null) {
                 Map<String, Renderable> map = new HashMap<>();
-                if (current().isPresent()) {
-                    map.putAll(current().get().contextMap);
+                if (getContext().isPresent()) {
+                    map.putAll(getContext().get().contextMap);
                 }
                 map.remove(key);
                 return executorService.submit(new Caller<R>(
@@ -339,8 +382,8 @@ public class ScopedContext {
     public static <R> R callWhere(Map<String, ?> map, Callable<R> op) throws Exception {
         if (map != null && !map.isEmpty()) {
             Map<String, Renderable> renderableMap = new HashMap<>();
-            if (current().isPresent()) {
-                renderableMap.putAll(current().get().contextMap);
+            if (getContext().isPresent()) {
+                renderableMap.putAll(getContext().get().contextMap);
             }
             map.forEach((key, value) -> {
                 renderableMap.put(key, value instanceof Renderable ? (Renderable) value : new ObjectRenderable(value));
@@ -351,14 +394,6 @@ public class ScopedContext {
         }
     }
 
-    /**
-     * Returns an Optional holding the active ScopedContext.Instance
-     * @return an Optional containing the active ScopedContext, if there is one.
-     */
-    private static Optional<Instance> current() {
-        return ScopedContextDataProvider.getContext();
-    }
-
     public static class Instance {
 
         private final Instance parent;
@@ -500,11 +535,11 @@ public class ScopedContext {
             if (contextStack != null) {
                 ThreadContext.setStack(contextStack);
             }
-            ScopedContextDataProvider.addScopedContext(scopedContext);
+            addScopedContext(scopedContext);
             try {
                 op.run();
             } finally {
-                ScopedContextDataProvider.removeScopedContext();
+                removeScopedContext();
                 ThreadContext.clearAll();
             }
         }
@@ -551,11 +586,11 @@ public class ScopedContext {
             if (contextStack != null) {
                 ThreadContext.setStack(contextStack);
             }
-            ScopedContextDataProvider.addScopedContext(scopedContext);
+            addScopedContext(scopedContext);
             try {
                 return op.call();
             } finally {
-                ScopedContextDataProvider.removeScopedContext();
+                removeScopedContext();
                 ThreadContext.clearAll();
             }
         }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java
index d914f1c4c9..f5529f4258 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java
@@ -23,9 +23,10 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ScopedContext;
+import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
@@ -295,8 +296,8 @@ public class SimpleLogger extends AbstractLogger {
         }
         sb.append(msg.getFormattedMessage());
         if (showContextMap) {
-            final Map<String, String> mdc = new HashMap<>(ContextData.size());
-            ContextData.addAll(mdc);
+            final Map<String, String> mdc = new HashMap<>(ThreadContext.getImmutableContext());
+            ScopedContext.getContextMap().forEach((key, value) -> mdc.put(key, value.render()));
             if (!mdc.isEmpty()) {
                 sb.append(SPACE);
                 sb.append(mdc.toString());
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ContextDataProvider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ContextDataProvider.java
deleted file mode 100644
index d003e9c74f..0000000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ContextDataProvider.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.spi;
-
-import java.util.Map;
-import org.apache.logging.log4j.util.StringMap;
-
-/**
- * Source of context data to be added to each log event.
- */
-public interface ContextDataProvider {
-
-    /**
-     * Returns the key for a value from the context data.
-     * @param key the key to locate.
-     * @return the value or null if it is not found.
-     */
-    default String get(String key) {
-        return null;
-    }
-
-    /**
-     * Returns a Map containing context data to be injected into the event or null if no context data is to be added.
-     * <p>
-     *     Thread-safety note: The returned object can safely be passed off to another thread: future changes in the
-     *     underlying context data will not be reflected in the returned object.
-     * </p>
-     * @return A Map containing the context data or null.
-     */
-    Map<String, String> supplyContextData();
-
-    /**
-     * Returns the number of items in this context.
-     * @return the number of items in the context.
-     */
-    default int size() {
-        Map<String, String> contextMap = supplyContextData();
-        return contextMap != null ? contextMap.size() : 0;
-    }
-
-    /**
-     * Add all the keys in the current context to the provided Map.
-     * @param map the StringMap to add the keys and values to.
-     */
-    default void addAll(Map<String, String> map) {
-        Map<String, String> contextMap = supplyContextData();
-        if (contextMap != null) {
-            map.putAll(contextMap);
-        }
-    }
-
-    /**
-     * Add all the keys in the current context to the provided StringMap.
-     * @param map the StringMap to add the keys and values to.
-     */
-    default void addAll(StringMap map) {
-        Map<String, String> contextMap = supplyContextData();
-        if (contextMap != null) {
-            contextMap.forEach(map::putValue);
-        }
-    }
-}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ScopedContextDataProvider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ScopedContextDataProvider.java
deleted file mode 100644
index f2a14c19d0..0000000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ScopedContextDataProvider.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.spi;
-
-import aQute.bnd.annotation.Resolution;
-import aQute.bnd.annotation.spi.ServiceProvider;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import org.apache.logging.log4j.ScopedContext;
-
-/**
- * ContextDataProvider for {@code Map<String, String>} data.
- * @since 2.24.0
- */
-@ServiceProvider(value = ContextDataProvider.class, resolution = Resolution.OPTIONAL)
-public class ScopedContextDataProvider implements ContextDataProvider {
-
-    private static final ThreadLocal<Deque<ScopedContext.Instance>> scopedContext = new ThreadLocal<>();
-
-    /**
-     * Returns an immutable Map containing all the key/value pairs as Renderable objects.
-     * @return An immutable copy of the Map at the current scope.
-     */
-    public static Optional<ScopedContext.Instance> getContext() {
-        Deque<ScopedContext.Instance> stack = scopedContext.get();
-        if (stack != null) {
-            return Optional.of(stack.getFirst());
-        }
-        return Optional.empty();
-    }
-
-    /**
-     * Add the ScopeContext.
-     * @param context The ScopeContext.
-     */
-    public static void addScopedContext(ScopedContext.Instance context) {
-        Deque<ScopedContext.Instance> stack = scopedContext.get();
-        if (stack == null) {
-            stack = new ArrayDeque<>();
-            scopedContext.set(stack);
-        }
-        stack.addFirst(context);
-    }
-
-    /**
-     * Remove the top ScopeContext.
-     */
-    public static void removeScopedContext() {
-        Deque<ScopedContext.Instance> stack = scopedContext.get();
-        if (stack != null) {
-            if (!stack.isEmpty()) {
-                stack.removeFirst();
-            }
-            if (stack.isEmpty()) {
-                scopedContext.remove();
-            }
-        }
-    }
-
-    @Override
-    public String get(String key) {
-        return ScopedContext.getString(key);
-    }
-
-    @Override
-    public Map<String, String> supplyContextData() {
-        Map<String, ScopedContext.Renderable> contextMap = ScopedContext.getContextMap();
-        if (!contextMap.isEmpty()) {
-            Map<String, String> map = new HashMap<>();
-            contextMap.forEach((key, value) -> map.put(key, value.render()));
-            return map;
-        } else {
-            return Collections.emptyMap();
-        }
-    }
-
-    @Override
-    public int size() {
-        return ScopedContext.size();
-    }
-
-    @Override
-    public void addAll(Map<String, String> map) {
-        ScopedContext.addAll(map);
-    }
-}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
index 5bb479f66c..f8b5b11402 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
@@ -19,7 +19,6 @@ package org.apache.logging.log4j.core.async;
 import com.lmax.disruptor.EventTranslatorVararg;
 import com.lmax.disruptor.dsl.Disruptor;
 import java.util.List;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
@@ -31,6 +30,7 @@ import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
 import org.apache.logging.log4j.core.util.Clock;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
index c965ce974d..ef79ca5b3e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
@@ -17,11 +17,11 @@
 package org.apache.logging.log4j.core.async;
 
 import com.lmax.disruptor.EventTranslator;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
 import org.apache.logging.log4j.core.ContextDataInjector;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
 import org.apache.logging.log4j.core.util.Clock;
 import org.apache.logging.log4j.core.util.NanoClock;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
index d2de85fe4d..b1f3c8f0d2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
@@ -19,7 +19,6 @@ package org.apache.logging.log4j.core.filter;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
@@ -32,11 +31,12 @@ import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
+import org.apache.logging.log4j.core.util.ContextDataProvider;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.spi.ContextDataProvider;
 import org.apache.logging.log4j.util.PerformanceSensitive;
 import org.apache.logging.log4j.util.StringMap;
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
index 7b27f88450..5116876555 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
@@ -21,7 +21,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.core.Filter;
@@ -33,6 +32,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginAliases;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ContextData.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextData.java
similarity index 96%
rename from log4j-api/src/main/java/org/apache/logging/log4j/ContextData.java
rename to log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextData.java
index 1b9445dcd8..df951a2e9f 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ContextData.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextData.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j;
+package org.apache.logging.log4j.core.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -24,7 +24,8 @@ import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.logging.log4j.spi.ContextDataProvider;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.ContextDataProvider;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.ServiceLoaderUtil;
 import org.apache.logging.log4j.util.StringMap;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index bc02b085bb..aff4d5893c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -24,7 +24,6 @@ import java.rmi.MarshalledObject;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
index 5a916d4003..5b41469aac 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@ -17,7 +17,6 @@
 package org.apache.logging.log4j.core.impl;
 
 import java.util.List;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextDataProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ScopedContextDataProvider.java
similarity index 60%
rename from log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextDataProvider.java
rename to log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ScopedContextDataProvider.java
index d6e28f00d8..805c0979e7 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextDataProvider.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ScopedContextDataProvider.java
@@ -14,36 +14,47 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.spi;
+package org.apache.logging.log4j.core.impl;
 
 import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceProvider;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
-import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.ScopedContext;
+import org.apache.logging.log4j.core.util.ContextDataProvider;
 
 /**
- * ContextDataProvider for ThreadContext data.
+ * ContextDataProvider for {@code Map<String, String>} data.
+ * @since 2.24.0
  */
 @ServiceProvider(value = ContextDataProvider.class, resolution = Resolution.OPTIONAL)
-public class ThreadContextDataProvider implements ContextDataProvider {
+public class ScopedContextDataProvider implements ContextDataProvider {
 
     @Override
     public String get(String key) {
-        return ThreadContext.get(key);
+        return ScopedContext.getString(key);
     }
 
     @Override
     public Map<String, String> supplyContextData() {
-        return ThreadContext.getImmutableContext();
+        Map<String, ScopedContext.Renderable> contextMap = ScopedContext.getContextMap();
+        if (!contextMap.isEmpty()) {
+            Map<String, String> map = new HashMap<>();
+            contextMap.forEach((key, value) -> map.put(key, value.render()));
+            return map;
+        } else {
+            return Collections.emptyMap();
+        }
     }
 
     @Override
     public int size() {
-        return ThreadContext.getContext().size();
+        return ScopedContext.size();
     }
 
     @Override
     public void addAll(Map<String, String> map) {
-        map.putAll(ThreadContext.getContext());
+        ScopedContext.addAll(map);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index 0362984c5b..06b9bcd084 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -21,7 +21,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextDataInjector;
@@ -236,9 +235,9 @@ public class ThreadContextDataInjector {
 
     private static class ProviderIterator implements Iterator<ContextDataProvider> {
 
-        private final Iterator<org.apache.logging.log4j.spi.ContextDataProvider> iter;
+        private final Iterator<ContextDataProvider> iter;
 
-        public ProviderIterator(Iterator<org.apache.logging.log4j.spi.ContextDataProvider> iter) {
+        public ProviderIterator(Iterator<ContextDataProvider> iter) {
             this.iter = iter;
         }
 
@@ -249,7 +248,7 @@ public class ThreadContextDataInjector {
 
         @Override
         public ContextDataProvider next() {
-            org.apache.logging.log4j.spi.ContextDataProvider next = iter.next();
+            ContextDataProvider next = iter.next();
             if (next instanceof ContextDataProvider) {
                 return (ContextDataProvider) next;
             } else if (next != null) {
@@ -261,9 +260,9 @@ public class ThreadContextDataInjector {
 
     private static class ProviderWrapper implements ContextDataProvider {
 
-        private final org.apache.logging.log4j.spi.ContextDataProvider provider;
+        private final ContextDataProvider provider;
 
-        public ProviderWrapper(org.apache.logging.log4j.spi.ContextDataProvider provider) {
+        public ProviderWrapper(ContextDataProvider provider) {
             this.provider = provider;
         }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.java
index a20216c755..949f8868a4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.java
@@ -29,6 +29,11 @@ import org.apache.logging.log4j.util.StringMap;
 @ServiceProvider(value = ContextDataProvider.class, resolution = Resolution.OPTIONAL)
 public class ThreadContextDataProvider implements ContextDataProvider {
 
+    @Override
+    public String get(String key) {
+        return ThreadContext.get(key);
+    }
+
     @Override
     public Map<String, String> supplyContextData() {
         return ThreadContext.getImmutableContext();
@@ -38,4 +43,14 @@ public class ThreadContextDataProvider implements ContextDataProvider {
     public StringMap supplyStringMap() {
         return ThreadContext.getThreadContextMap().getReadOnlyContextData();
     }
+
+    @Override
+    public int size() {
+        return ThreadContext.getContext().size();
+    }
+
+    @Override
+    public void addAll(Map<String, String> map) {
+        map.putAll(ThreadContext.getContext());
+    }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
index b24f1203a8..9b841bb396 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
@@ -16,12 +16,12 @@
  */
 package org.apache.logging.log4j.core.lookup;
 
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.ScopedContext;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextDataInjector;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
 
 /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java
index 17bde215ff..5f6f1da67c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java
@@ -18,14 +18,14 @@ package org.apache.logging.log4j.core.osgi;
 
 import java.util.Collection;
 import java.util.concurrent.atomic.AtomicReference;
-import org.apache.logging.log4j.ContextData;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;
+import org.apache.logging.log4j.core.impl.ContextData;
 import org.apache.logging.log4j.core.impl.Log4jProvider;
+import org.apache.logging.log4j.core.impl.ThreadContextDataProvider;
 import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.spi.ContextDataProvider;
-import org.apache.logging.log4j.spi.ThreadContextDataProvider;
+import org.apache.logging.log4j.core.util.ContextDataProvider;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.ProviderActivator;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
index 086ac93981..6eeeeef9b5 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
@@ -22,11 +22,26 @@ import org.apache.logging.log4j.util.StringMap;
 
 /**
  * Source of context data to be added to each log event.
- * @deprecated Use ContextDataProvider from Log4j API from 2.24.0.
  */
-@Deprecated
-public interface ContextDataProvider extends org.apache.logging.log4j.spi.ContextDataProvider {
+public interface ContextDataProvider {
 
+    /**
+     * Returns the key for a value from the context data.
+     * @param key the key to locate.
+     * @return the value or null if it is not found.
+     */
+    default String get(String key) {
+        return null;
+    }
+
+    /**
+     * Returns a Map containing context data to be injected into the event or null if no context data is to be added.
+     * <p>
+     *     Thread-safety note: The returned object can safely be passed off to another thread: future changes in the
+     *     underlying context data will not be reflected in the returned object.
+     * </p>
+     * @return A Map containing the context data or null.
+     */
     Map<String, String> supplyContextData();
 
     /**
@@ -42,4 +57,35 @@ public interface ContextDataProvider extends org.apache.logging.log4j.spi.Contex
     default StringMap supplyStringMap() {
         return new JdkMapAdapterStringMap(supplyContextData(), true);
     }
+
+    /**
+     * Returns the number of items in this context.
+     * @return the number of items in the context.
+     */
+    default int size() {
+        Map<String, String> contextMap = supplyContextData();
+        return contextMap != null ? contextMap.size() : 0;
+    }
+
+    /**
+     * Add all the keys in the current context to the provided Map.
+     * @param map the StringMap to add the keys and values to.
+     */
+    default void addAll(Map<String, String> map) {
+        Map<String, String> contextMap = supplyContextData();
+        if (contextMap != null) {
+            map.putAll(contextMap);
+        }
+    }
+
+    /**
+     * Add all the keys in the current context to the provided StringMap.
+     * @param map the StringMap to add the keys and values to.
+     */
+    default void addAll(StringMap map) {
+        Map<String, String> contextMap = supplyContextData();
+        if (contextMap != null) {
+            contextMap.forEach(map::putValue);
+        }
+    }
 }