LOG4J2-323 preparations toward having one AsyncLoggerConfigHelper per Configuration, shared by all AsyncLoggerConfig objects
- extract interface AsyncLoggerConfigDelegate from AsyncLoggerConfigHelper - removed AsyncLoggerConfig field from Helper, since a single helper will be servicing all AsyncLoggerConfigs in the same configuration Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/9c3af711 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/9c3af711 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/9c3af711 Branch: refs/heads/LOG4J2-1161 Commit: 9c3af711478e459ac0423f2eca83bd86481db93e Parents: 86e0a0a Author: rpopma <rpo...@apache.org> Authored: Fri Oct 23 09:47:24 2015 +0900 Committer: rpopma <rpo...@apache.org> Committed: Fri Oct 23 09:47:24 2015 +0900 ---------------------------------------------------------------------- .../log4j/core/async/AsyncLoggerConfig.java | 25 ++-------- .../core/async/AsyncLoggerConfigDelegate.java | 52 ++++++++++++++++++++ .../core/async/AsyncLoggerConfigHelper.java | 39 +++++---------- 3 files changed, 68 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9c3af711/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java index 186575d..7be1e8f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java @@ -70,26 +70,7 @@ public class AsyncLoggerConfig extends LoggerConfig { private static final long serialVersionUID = 1L; - private AsyncLoggerConfigHelper helper; - - /** - * Default constructor. - */ - public AsyncLoggerConfig() { - super(); - } - - /** - * Constructor that sets the name, level and additive values. - * - * @param name The Logger name. - * @param level The Level. - * @param additive true if the Logger is additive, false otherwise. - */ - public AsyncLoggerConfig(final String name, final Level level, - final boolean additive) { - super(name, level, additive); - } + private AsyncLoggerConfigDelegate helper; protected AsyncLoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter, @@ -111,7 +92,7 @@ public class AsyncLoggerConfig extends LoggerConfig { event.getThreadName(); // pass on the event to a separate thread - if (!helper.callAppendersFromAnotherThread(event)) { + if (!helper.tryCallAppendersInBackground(event, this)) { super.callAppenders(event); } } @@ -130,7 +111,7 @@ public class AsyncLoggerConfig extends LoggerConfig { LOGGER.trace("AsyncLoggerConfig[{}] starting...", displayName()); this.setStarting(); if (helper == null) { - helper = new AsyncLoggerConfigHelper(this); + helper = new AsyncLoggerConfigHelper(); } else { AsyncLoggerConfigHelper.claim(); // LOG4J2-336 } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9c3af711/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java new file mode 100644 index 0000000..229b08e --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java @@ -0,0 +1,52 @@ +/* + * 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.LogEvent; +import org.apache.logging.log4j.core.jmx.RingBufferAdmin; + +/** + * Encapsulates the mechanism used to log asynchronously. There is one delegate per configuration, which is shared by + * all AsyncLoggerConfig objects in the configuration. + */ +interface AsyncLoggerConfigDelegate { + + /** + * If possible, delegates the invocation of {@code callAppenders} to the background thread and returns {@code true}. + * If this is not possible (if it detects that delegating to the background thread would cause deadlock because the + * current call to Logger.log() originated from the background thread and the ringbuffer is full) then this method + * does nothing and returns {@code false}. It is the responsibility of the caller to process the event when this + * method returns {@code false}. + * + * @param event the event to delegate to the background thread + * @param asyncLoggerConfig the logger config to call from the background thread + * @return {@code true} if delegation was successful, {@code false} if the calling thread needs to process the event + * itself + */ + boolean tryCallAppendersInBackground(LogEvent event, AsyncLoggerConfig asyncLoggerConfig); + + /** + * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of this + * {@code AsyncLoggerConfig}. + * + * @param contextName name of the {@code LoggerContext} + * @param loggerConfigName name of the logger config + */ + RingBufferAdmin createRingBufferAdmin(String contextName, String loggerConfigName); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9c3af711/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java index 0ae2cdd..6636eba 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java @@ -53,7 +53,7 @@ import com.lmax.disruptor.dsl.ProducerType; * This class serves to make the dependency on the Disruptor optional, so that these classes are only loaded when the * {@code AsyncLoggerConfig} is actually used. */ -class AsyncLoggerConfigHelper { +class AsyncLoggerConfigHelper implements AsyncLoggerConfigDelegate { private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200; private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50; @@ -93,10 +93,7 @@ class AsyncLoggerConfigHelper { } }; - private final AsyncLoggerConfig asyncLoggerConfig; - - public AsyncLoggerConfigHelper(final AsyncLoggerConfig asyncLoggerConfig) { - this.asyncLoggerConfig = asyncLoggerConfig; + public AsyncLoggerConfigHelper() { claim(); } @@ -291,18 +288,11 @@ class AsyncLoggerConfigHelper { }); } - /** - * If possible, delegates the invocation to {@code callAppenders} to another thread and returns {@code true}. If - * this is not possible (if it detects that delegating to another thread would cause deadlock because the current - * call to Logger.log() originated from the appender thread and the ringbuffer is full) then this method does - * nothing and returns {@code false}. It is the responsibility of the caller to process the event when this method - * returns {@code false}. - * - * @param event the event to delegate to another thread - * @return {@code true} if delegation was successful, {@code false} if the calling thread needs to process the - * event itself + /* (non-Javadoc) + * @see org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate#tryCallAppendersInBackground(org.apache.logging.log4j.core.LogEvent) */ - public boolean callAppendersFromAnotherThread(final LogEvent event) { + @Override + public boolean tryCallAppendersInBackground(final LogEvent event, final AsyncLoggerConfig asyncLoggerConfig) { final Disruptor<Log4jEventWrapper> temp = disruptor; if (!hasLog4jBeenShutDown(temp)) { @@ -312,7 +302,7 @@ class AsyncLoggerConfigHelper { // bypass RingBuffer and invoke Appender directly return false; } - enqueueEvent(event); + enqueueEvent(event, asyncLoggerConfig); } return true; } @@ -328,11 +318,11 @@ class AsyncLoggerConfigHelper { return false; } - private void enqueueEvent(final LogEvent event) { + private void enqueueEvent(final LogEvent event, final AsyncLoggerConfig asyncLoggerConfig) { // LOG4J2-639: catch NPE if disruptor field was set to null after our check above try { final LogEvent logEvent = prepareEvent(event); - enqueue(logEvent); + enqueue(logEvent, asyncLoggerConfig); } catch (final NullPointerException npe) { LOGGER.fatal("Ignoring log event after log4j was shut down."); } @@ -344,7 +334,7 @@ class AsyncLoggerConfigHelper { return logEvent; } - private void enqueue(LogEvent logEvent) { + private void enqueue(final LogEvent logEvent, final AsyncLoggerConfig asyncLoggerConfig) { // Note: do NOT use the temp variable above! // That could result in adding a log event to the disruptor after it was shut down, // which could cause the publishEvent method to hang and never return. @@ -372,13 +362,10 @@ class AsyncLoggerConfigHelper { return isAppenderThread.get() == Boolean.TRUE && theDisruptor.getRingBuffer().remainingCapacity() == 0; } - /** - * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of this - * {@code AsyncLoggerConfig}. - * - * @param contextName name of the {@code LoggerContext} - * @param loggerConfigName name of the logger config + /* (non-Javadoc) + * @see org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate#createRingBufferAdmin(java.lang.String, java.lang.String) */ + @Override public RingBufferAdmin createRingBufferAdmin(final String contextName, final String loggerConfigName) { return RingBufferAdmin.forAsyncLoggerConfig(disruptor.getRingBuffer(), contextName, loggerConfigName); }