You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2020/06/29 00:40:32 UTC

[logging-log4j2] 02/03: LOG4J2-2867 - Obtain ContextDataProviders asynchronously

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

rgoers pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f5392e6b87ea4829894eb0744bf1293cbc43fd99
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sun Jun 28 15:41:27 2020 -0700

    LOG4J2-2867 - Obtain ContextDataProviders asynchronously
---
 .../apache/logging/log4j/core/LoggerContext.java   |  4 ++
 .../log4j/core/impl/ThreadContextDataInjector.java | 49 +++++++++++++++++-----
 .../org/apache/logging/log4j/core/LoggingTest.java |  4 +-
 3 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index fe1ec01..a7e5b60 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -27,6 +27,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -43,6 +44,7 @@ import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.NullConfiguration;
 import org.apache.logging.log4j.core.config.Reconfigurable;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.impl.ThreadContextDataInjector;
 import org.apache.logging.log4j.core.jmx.Server;
 import org.apache.logging.log4j.core.util.Cancellable;
 import org.apache.logging.log4j.core.util.ExecutorServices;
@@ -136,6 +138,7 @@ public class LoggerContext extends AbstractLifeCycle
             externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
         }
         this.configLocation = configLocn;
+        CompletableFuture.runAsync(ThreadContextDataInjector::initServiceProviders);
     }
 
     /**
@@ -164,6 +167,7 @@ public class LoggerContext extends AbstractLifeCycle
         } else {
             configLocation = null;
         }
+        CompletableFuture.runAsync(ThreadContextDataInjector::initServiceProviders);
     }
 
     public void addShutdownListener(LoggerContextShutdownAware listener) {
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 5ce7819..89623cd 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
@@ -23,6 +23,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
@@ -52,7 +54,7 @@ import org.apache.logging.log4j.util.StringMap;
  */
 public class ThreadContextDataInjector {
 
-    private static Logger LOGGER = StatusLogger.getLogger();
+    private static final Logger LOGGER = StatusLogger.getLogger();
 
     /**
      * ContextDataProviders loaded via OSGi.
@@ -60,6 +62,38 @@ public class ThreadContextDataInjector {
     public static Collection<ContextDataProvider> contextDataProviders =
             new ConcurrentLinkedDeque<>();
 
+    private static volatile List<ContextDataProvider> serviceProviders = null;
+    private static final Lock providerLock = new ReentrantLock();
+
+    public static void initServiceProviders() {
+        if (serviceProviders == null) {
+            providerLock.lock();
+            try {
+                if (serviceProviders == null) {
+                    serviceProviders = getServiceProviders();
+                }
+            } finally {
+                providerLock.unlock();
+            }
+        }
+    }
+
+    private static List<ContextDataProvider> getServiceProviders() {
+        List<ContextDataProvider> providers = new ArrayList<>();
+        for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
+            try {
+                for (final ContextDataProvider provider : ServiceLoader.load(ContextDataProvider.class, classLoader)) {
+                    if (providers.stream().noneMatch((p) -> p.getClass().isAssignableFrom(provider.getClass()))) {
+                        providers.add(provider);
+                    }
+                }
+            } catch (final Throwable ex) {
+                LOGGER.debug("Unable to access Context Data Providers {}", ex.getMessage());
+            }
+        }
+        return providers;
+    }
+
     /**
      * Default {@code ContextDataInjector} for the legacy {@code Map<String, String>}-based ThreadContext (which is
      * also the ThreadContext implementation used for web applications).
@@ -248,17 +282,10 @@ public class ThreadContextDataInjector {
     }
 
     private static List<ContextDataProvider> getProviders() {
+        initServiceProviders();
         final List<ContextDataProvider> providers = new ArrayList<>(contextDataProviders);
-        for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
-            try {
-                for (final ContextDataProvider provider : ServiceLoader.load(ContextDataProvider.class, classLoader)) {
-                    if (providers.stream().noneMatch((p) -> p.getClass().isAssignableFrom(provider.getClass()))) {
-                        providers.add(provider);
-                    }
-                }
-            } catch (final Throwable ex) {
-                LOGGER.debug("Unable to access Context Data Providers {}", ex.getMessage());
-            }
+        if (serviceProviders != null) {
+            providers.addAll(serviceProviders);
         }
         return providers;
     }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggingTest.java
index 4491627..6664ddf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggingTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggingTest.java
@@ -86,11 +86,11 @@ public class LoggingTest {
         logger.info("This is a test");
         System.out.println(timer.stop());
         timer = new Timer("more", 100);
-        timer.start();
+/*        timer.start();
         for (int i=0; i < 100; ++i) {
             logger.info("This is another test");
         }
-        System.out.println(timer.stop());
+        System.out.println(timer.stop());*/
     }
 }