Repository: logging-log4j2 Updated Branches: refs/heads/LOG4J2-1161 990a97c0b -> d3a064150
LOG4J2-323, 493, 1159 factor out AsyncLogger.Info into top-level class Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/bf3ba25d Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/bf3ba25d Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/bf3ba25d Branch: refs/heads/LOG4J2-1161 Commit: bf3ba25dfe9e4d8a831bea783bed3a6e65b4593b Parents: 6d62c74 Author: rpopma <rpo...@apache.org> Authored: Wed Oct 21 02:04:10 2015 +0900 Committer: rpopma <rpo...@apache.org> Committed: Wed Oct 21 02:04:10 2015 +0900 ---------------------------------------------------------------------- .../logging/log4j/core/async/AsyncLogger.java | 89 --------------- .../log4j/core/async/AsyncLoggerHelper.java | 5 +- .../apache/logging/log4j/core/async/Info.java | 109 +++++++++++++++++++ .../AsyncLoggerThreadNameStrategyTest.java | 4 +- 4 files changed, 114 insertions(+), 93 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/bf3ba25d/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java ---------------------------------------------------------------------- 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 c2214f8..72d81d3 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 @@ -18,7 +18,6 @@ package org.apache.logging.log4j.core.async; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ExecutorService; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -37,7 +36,6 @@ import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.TimestampMessage; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; import com.lmax.disruptor.dsl.Disruptor; @@ -62,98 +60,12 @@ import com.lmax.disruptor.dsl.Disruptor; */ public class AsyncLogger extends Logger { - /** - * Strategy for deciding whether thread name should be cached or not. - */ - static enum ThreadNameStrategy { // LOG4J2-467 - CACHED { - @Override - public String getThreadName(final Info info) { - return info.cachedThreadName; - } - }, - UNCACHED { - @Override - public String getThreadName(final Info info) { - return Thread.currentThread().getName(); - } - }; - abstract String getThreadName(Info info); - - static ThreadNameStrategy create() { - final String name = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ThreadNameStrategy", - CACHED.name()); - try { - final ThreadNameStrategy result = ThreadNameStrategy.valueOf(name); - LOGGER.debug("AsyncLogger.ThreadNameStrategy={}", result); - return result; - } catch (final Exception ex) { - LOGGER.debug("Using AsyncLogger.ThreadNameStrategy.CACHED: '{}' not valid: {}", name, ex.toString()); - return CACHED; - } - } - } - - /** - * Tuple with the event translator and thread name for a thread. - */ - static class Info { - private final RingBufferLogEventTranslator translator; - private final String cachedThreadName; - private final boolean isAppenderThread; - - public Info(final RingBufferLogEventTranslator translator, final String threadName, final boolean appenderThread) { - this.translator = translator; - this.cachedThreadName = threadName; - this.isAppenderThread = appenderThread; - } - - /** - * Initialize an {@code Info} object that is threadlocal to the consumer/appender thread. This Info object - * uniquely has attribute {@code isAppenderThread} set to {@code true}. All other Info objects will have this - * attribute set to {@code false}. This allows us to detect Logger.log() calls initiated from the appender - * thread, which may cause deadlock when the RingBuffer is full. (LOG4J2-471) - * - * @param executor runs the appender thread - */ - public static void initExecutorThreadInstance(final ExecutorService executor) { - executor.submit(new Runnable() { - @Override - public void run() { - final boolean isAppenderThread = true; - final Info info = new Info(new RingBufferLogEventTranslator(), // - Thread.currentThread().getName(), isAppenderThread); - THREADLOCAL.set(info); - } - }); - } - - private static Info get() { - Info result = THREADLOCAL.get(); - if (result == null) { - // by default, set isAppenderThread to false - result = new Info(new RingBufferLogEventTranslator(), Thread.currentThread().getName(), false); - THREADLOCAL.set(result); - } - return result; - } - - // LOG4J2-467 - private String threadName() { - return THREAD_NAME_STRATEGY.getThreadName(this); - } - } - private static final long serialVersionUID = 1L; private static final StatusLogger LOGGER = StatusLogger.getLogger(); - private static final ThreadNameStrategy THREAD_NAME_STRATEGY = ThreadNameStrategy.create(); - private static final ThreadLocal<Info> THREADLOCAL = new ThreadLocal<Info>(); - private static final Clock CLOCK = ClockFactory.getClock(); private static volatile NanoClock nanoClock = new DummyNanoClock(); - /** * Constructs an {@code AsyncLogger} with the specified context, name and message factory. * @@ -163,7 +75,6 @@ public class AsyncLogger extends Logger { */ public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory) { super(context, name, messageFactory); - LOGGER.info("Created AsyncLogger " + name); } @Override http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/bf3ba25d/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java index 65f76e0..43dacc1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerHelper.java @@ -20,7 +20,6 @@ package org.apache.logging.log4j.core.async; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.apache.logging.log4j.core.async.AsyncLogger.Info; import org.apache.logging.log4j.core.jmx.RingBufferAdmin; import org.apache.logging.log4j.core.util.Integers; import org.apache.logging.log4j.core.util.Loader; @@ -185,7 +184,7 @@ public class AsyncLoggerHelper { count = 0; // ref count must not be negative or #claim() will not work correctly return; // disruptor was already shut down by another thread } - LOGGER.trace("AsyncLoggerHelper: shutting down disruptor: ref count is {}.", count); + LOGGER.debug("AsyncLoggerHelper: shutting down disruptor: ref count is {}.", count); // Must guarantee that publishing to the RingBuffer has stopped // before we call disruptor.shutdown() @@ -201,6 +200,8 @@ public class AsyncLoggerHelper { } } temp.shutdown(); // busy-spins until all events currently in the disruptor have been processed + + LOGGER.trace("AsyncLoggerHelper: shutting down disruptor executor."); executor.shutdown(); // finally, kill the processor thread executor = null; // Info.THREADLOCAL.remove(); // LOG4J2-323 http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/bf3ba25d/log4j-core/src/main/java/org/apache/logging/log4j/core/async/Info.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/Info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/Info.java new file mode 100644 index 0000000..d27cb6d --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/Info.java @@ -0,0 +1,109 @@ +/* + * 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 java.util.concurrent.ExecutorService; + +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.PropertiesUtil; + +/** + * Tuple with the event translator and thread name for a thread. + */ +class Info { + /** + * Strategy for deciding whether thread name should be cached or not. + */ + static enum ThreadNameStrategy { // LOG4J2-467 + CACHED { + @Override + public String getThreadName(final Info info) { + return info.cachedThreadName; + } + }, + UNCACHED { + @Override + public String getThreadName(final Info info) { + return Thread.currentThread().getName(); + } + }; + abstract String getThreadName(Info info); + + static Info.ThreadNameStrategy create() { + final String name = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ThreadNameStrategy", + CACHED.name()); + try { + final Info.ThreadNameStrategy result = ThreadNameStrategy.valueOf(name); + LOGGER.debug("AsyncLogger.ThreadNameStrategy={}", result); + return result; + } catch (final Exception ex) { + LOGGER.debug("Using AsyncLogger.ThreadNameStrategy.CACHED: '{}' not valid: {}", name, ex.toString()); + return CACHED; + } + } + } + + private static final StatusLogger LOGGER = StatusLogger.getLogger(); + private static final Info.ThreadNameStrategy THREAD_NAME_STRATEGY = ThreadNameStrategy.create(); + private static final ThreadLocal<Info> THREADLOCAL = new ThreadLocal<Info>(); + + final RingBufferLogEventTranslator translator; + private final String cachedThreadName; + final boolean isAppenderThread; + + public Info(final RingBufferLogEventTranslator translator, final String threadName, final boolean appenderThread) { + this.translator = translator; + this.cachedThreadName = threadName; + this.isAppenderThread = appenderThread; + } + + /** + * Initialize an {@code Info} object that is threadlocal to the consumer/appender thread. This Info object + * uniquely has attribute {@code isAppenderThread} set to {@code true}. All other Info objects will have this + * attribute set to {@code false}. This allows us to detect Logger.log() calls initiated from the appender + * thread, which may cause deadlock when the RingBuffer is full. (LOG4J2-471) + * + * @param executor runs the appender thread + */ + public static void initExecutorThreadInstance(final ExecutorService executor) { + executor.submit(new Runnable() { + @Override + public void run() { + final boolean isAppenderThread = true; + final Info info = new Info(new RingBufferLogEventTranslator(), // + Thread.currentThread().getName(), isAppenderThread); + THREADLOCAL.set(info); + } + }); + } + + static Info get() { + Info result = THREADLOCAL.get(); + if (result == null) { + // by default, set isAppenderThread to false + result = new Info(new RingBufferLogEventTranslator(), Thread.currentThread().getName(), false); + THREADLOCAL.set(result); + } + return result; + } + + // LOG4J2-467 + String threadName() { + return THREAD_NAME_STRATEGY.getThreadName(this); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/bf3ba25d/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java index f545fc2..4c96f87 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java @@ -44,7 +44,7 @@ public class AsyncLoggerThreadNameStrategyTest { @Test public void testUncachedThreadNameStrategyReturnsCurrentThreadName() throws Exception { - final AsyncLogger.Info info = new AsyncLogger.Info(null, "original", false); + final Info info = new Info(null, "original", false); final String name1 = "MODIFIED-THREADNAME1"; Thread.currentThread().setName(name1); assertEquals(name1, AsyncLogger.ThreadNameStrategy.UNCACHED.getThreadName(info)); @@ -58,7 +58,7 @@ public class AsyncLoggerThreadNameStrategyTest { public void testCachedThreadNameStrategyReturnsCachedThreadName() throws Exception { final String original = "Original-ThreadName"; Thread.currentThread().setName(original); - final AsyncLogger.Info info = new AsyncLogger.Info(null, original, false); + final Info info = new Info(null, original, false); assertEquals(original, AsyncLogger.ThreadNameStrategy.CACHED.getThreadName(info)); final String name2 = "OTHER-THREADNAME2";