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 2021/03/28 23:10:24 UTC

[logging-log4j2] 05/06: LOG4J2-2940: Implement BasicAsyncLoggerContextSelector

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

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

commit f42f81c5b4644cceca7cdadf472091efc0360983
Author: Carter Kozak <ck...@apache.org>
AuthorDate: Mon Mar 22 14:52:11 2021 -0400

    LOG4J2-2940: Implement BasicAsyncLoggerContextSelector
    
    The BasicAsyncLoggerContextSelector is equivalent to the
    AsyncLoggerContextSelector without ClassLoader introspection
    and associated overhead.
---
 .../async/BasicAsyncLoggerContextSelector.java     |  84 ++++++++++++++++
 .../log4j/core/selector/CoreContextSelectors.java  |   8 +-
 .../async/BasicAsyncLoggerContextSelectorTest.java | 107 +++++++++++++++++++++
 src/changes/changes.xml                            |   5 +
 4 files changed, 203 insertions(+), 1 deletion(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java
new file mode 100644
index 0000000..90ce160
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.async;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.ContextAnchor;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Returns either this Thread's context or the default {@link AsyncLoggerContext}.
+ * Single-application instances should prefer this implementation over the {@link AsyncLoggerContextSelector}
+ * due the the reduced overhead avoiding classloader lookups.
+ */
+public class BasicAsyncLoggerContextSelector implements ContextSelector {
+
+    private static final AsyncLoggerContext CONTEXT = new AsyncLoggerContext("AsyncDefault");
+
+    @Override
+    public void shutdown(String fqcn, ClassLoader loader, boolean currentContext, boolean allContexts) {
+        LoggerContext ctx = getContext(fqcn, loader, currentContext);
+        if (ctx != null && ctx.isStarted()) {
+            ctx.stop(DEFAULT_STOP_TIMEOUT, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    @Override
+    public boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
+        LoggerContext ctx = getContext(fqcn, loader, currentContext);
+        return ctx != null && ctx.isStarted();
+    }
+
+    @Override
+    public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
+        final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
+        return ctx != null ? ctx : CONTEXT;
+    }
+
+
+    @Override
+    public LoggerContext getContext(
+            final String fqcn,
+            final ClassLoader loader,
+            final boolean currentContext,
+            final URI configLocation) {
+        final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
+        return ctx != null ? ctx : CONTEXT;
+    }
+
+    @Override
+    public void removeContext(final LoggerContext context) {
+        // does not remove anything
+    }
+
+    @Override
+    public boolean isClassLoaderDependent() {
+        return false;
+    }
+
+    @Override
+    public List<LoggerContext> getLoggerContexts() {
+        return Collections.singletonList(CONTEXT);
+    }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
index 1077e5a..2ee6b0d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
@@ -17,9 +17,15 @@
 package org.apache.logging.log4j.core.selector;
 
 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
+import org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector;
 
 public class CoreContextSelectors {
 
-    public static final Class<?>[] CLASSES = new Class<?>[] { ClassLoaderContextSelector.class, BasicContextSelector.class, AsyncLoggerContextSelector.class };
+    public static final Class<?>[] CLASSES = new Class<?>[] {
+            ClassLoaderContextSelector.class,
+            BasicContextSelector.class,
+            AsyncLoggerContextSelector.class,
+            BasicAsyncLoggerContextSelector.class
+    };
 
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java
new file mode 100644
index 0000000..823cc3f
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.async;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.categories.AsyncLoggers;
+import org.apache.logging.log4j.core.LifeCycle;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.util.Constants;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@Category(AsyncLoggers.class)
+public class BasicAsyncLoggerContextSelectorTest {
+
+    private static final String FQCN = BasicAsyncLoggerContextSelectorTest.class.getName();
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
+                BasicAsyncLoggerContextSelector.class.getName());
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
+    }
+
+    @Test
+    public void testContextReturnsAsyncLoggerContext() {
+        final BasicAsyncLoggerContextSelector selector = new BasicAsyncLoggerContextSelector();
+        final LoggerContext context = selector.getContext(FQCN, null, false);
+
+        assertTrue(context instanceof AsyncLoggerContext);
+    }
+
+    @Test
+    public void testContext2ReturnsAsyncLoggerContext() {
+        final BasicAsyncLoggerContextSelector selector = new BasicAsyncLoggerContextSelector();
+        final LoggerContext context = selector.getContext(FQCN, null, false, null);
+
+        assertTrue(context instanceof AsyncLoggerContext);
+    }
+
+    @Test
+    public void testLoggerContextsReturnsAsyncLoggerContext() {
+        final BasicAsyncLoggerContextSelector selector = new BasicAsyncLoggerContextSelector();
+
+        List<LoggerContext> list = selector.getLoggerContexts();
+        assertEquals(1, list.size());
+        assertTrue(list.get(0) instanceof AsyncLoggerContext);
+
+        selector.getContext(FQCN, null, false);
+
+        list = selector.getLoggerContexts();
+        assertEquals(1, list.size());
+        assertTrue(list.get(0) instanceof AsyncLoggerContext);
+    }
+
+    @Test
+    public void testContextNameIsAsyncDefault() {
+        final BasicAsyncLoggerContextSelector selector = new BasicAsyncLoggerContextSelector();
+        final LoggerContext context = selector.getContext(FQCN, null, false);
+        assertEquals("AsyncDefault" , context.getName());
+    }
+
+    @Test
+    public void testDependentOnClassLoader() {
+        final BasicAsyncLoggerContextSelector selector = new BasicAsyncLoggerContextSelector();
+        assertFalse(selector.isClassLoaderDependent());
+    }
+
+    @Test
+    public void testFactoryIsNotDependentOnClassLoader() {
+        assertFalse(LogManager.getFactory().isClassLoaderDependent());
+    }
+
+    @Test
+    public void testLogManagerShutdown() {
+        LoggerContext context = (LoggerContext) LogManager.getContext();
+        assertEquals(LifeCycle.State.STARTED, context.getState());
+        LogManager.shutdown();
+        assertEquals(LifeCycle.State.STOPPED, context.getState());
+    }
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3d8c3d8..3644802 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -186,6 +186,11 @@
         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="update">
         Allow a PatternSelector to be specified on GelfLayout.
       </action>