I still think that we should not use non-daemon threads (except in tests and samples).
On Jan 12, 2017 11:45 PM, "Gary Gregory" <garydgreg...@gmail.com> wrote: > I still like the work I did with executor services, so I'll leave it at > that ;-) Sure it turns out there is a bug on reconfigure but it's fixable > without throwing it all out. I'm swamped at work ATM so I cannot spend time > dealing with too much FOSS this week (as was last week). Good luck :-) > > Gary > > On Thu, Jan 12, 2017 at 8:01 AM, Remko Popma <remko.po...@gmail.com> > wrote: > >> Some feedback: >> 1. Why remove Log4jThreadFactory.createThreadFactory? >> CassandraRule was using it and now needs to use the constructor. >> >> 2. The ConfigurationScheduler may create a thread pool with size zero. >> ConfigurationScheduler::incrementScheduledItems is only called if >> monitorInterval is positive, or if a plugin with the @Scheduled annotation >> is configured (not sure I'm reading that right), or if a >> CronTriggeringPolicy is configured. If none of these are true, but a >> RollingFile appender is configured, I think there will be a problem. >> >> 3. Generally, I think RollingFileManager AsyncActions (compress) should >> not be submitted to the ConfigurationScheduler: this executor will usually >> only have one thread so these actions will execute one by one sequentially. >> If many files need to be rolled over and compressed at the same time, I >> think this work should be done in parallel as much as possible.Therefore, I >> think it's better to create new (non-daemon) threads for the rollover async >> actions. >> >> 4. (Not your change, I noticed during review): ConfigurationScheduler >> catches InterruptedException but does not restore the interrupted flag. >> Should be: >> ... >> } catch (InterruptedException ie) { >> ... >> // Preserve interrupt status >> Thread.currentThread().interrupt(); >> } >> >> >> On Thu, Jan 12, 2017 at 8:36 PM, <mi...@apache.org> wrote: >> >>> Repository: logging-log4j2 >>> Updated Branches: >>> refs/heads/LOG4J2-1748and1780-remove-ExecutorService-from-LoggerContext >>> [created] 162a5e33a >>> >>> >>> LOG4J2-1748 and LOG4J2-1780 Remove ExecutorServices from LoggerContext >>> >>> >>> Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo >>> Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit >>> /162a5e33 >>> Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/1 >>> 62a5e33 >>> Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/1 >>> 62a5e33 >>> >>> Branch: refs/heads/LOG4J2-1748and1780-remove-ExecutorService-from-Lo >>> ggerContext >>> Commit: 162a5e33ace3f1b4adf0726502083d0efb1e799a >>> Parents: a6f9d12 >>> Author: Mikael Ståldal <mikael.stal...@magine.com> >>> Authored: Thu Jan 12 12:14:18 2017 +0100 >>> Committer: Mikael Ståldal <mikael.stal...@magine.com> >>> Committed: Thu Jan 12 12:32:00 2017 +0100 >>> >>> ---------------------------------------------------------------------- >>> .../logging/log4j/core/LoggerContext.java | 97 >>> +------------------- >>> .../core/appender/mom/kafka/KafkaManager.java | 11 ++- >>> .../appender/rolling/RollingFileManager.java | 2 +- >>> .../core/config/AbstractConfiguration.java | 4 +- >>> .../core/config/ConfigurationScheduler.java | 51 +++++++--- >>> .../core/config/ConfiguratonFileWatcher.java | 7 +- >>> .../logging/log4j/core/config/Configurator.java | 4 +- >>> .../log4j/core/util/Log4jThreadFactory.java | 11 --- >>> .../nosql/appender/cassandra/CassandraRule.java | 2 +- >>> src/site/xdoc/manual/configuration.xml.vm | 4 +- >>> 10 files changed, 59 insertions(+), 134 deletions(-) >>> ---------------------------------------------------------------------- >>> >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/LoggerContext.java >>> ---------------------------------------------------------------------- >>> 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/Log >>> gerContext.java >>> index 2322376..9797cc6 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Log >>> gerContext.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Log >>> gerContext.java >>> @@ -26,13 +26,6 @@ import java.util.Collection; >>> import java.util.Objects; >>> import java.util.concurrent.ConcurrentMap; >>> import java.util.concurrent.CopyOnWriteArrayList; >>> -import java.util.concurrent.ExecutorService; >>> -import java.util.concurrent.Executors; >>> -import java.util.concurrent.Future; >>> -import java.util.concurrent.RejectedExecutionException; >>> -import java.util.concurrent.SynchronousQueue; >>> -import java.util.concurrent.ThreadFactory; >>> -import java.util.concurrent.ThreadPoolExecutor; >>> import java.util.concurrent.TimeUnit; >>> import java.util.concurrent.locks.Lock; >>> import java.util.concurrent.locks.ReentrantLock; >>> @@ -49,7 +42,6 @@ import org.apache.logging.log4j.core. >>> impl.Log4jLogEvent; >>> import org.apache.logging.log4j.core.jmx.Server; >>> import org.apache.logging.log4j.core.util.Cancellable; >>> import org.apache.logging.log4j.core.util.ExecutorServices; >>> -import org.apache.logging.log4j.core.util.Log4jThreadFactory; >>> import org.apache.logging.log4j.core.util.NetUtils; >>> import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; >>> import org.apache.logging.log4j.message.MessageFactory; >>> @@ -92,8 +84,6 @@ public class LoggerContext extends AbstractLifeCycle >>> * reference is updated. >>> */ >>> private volatile Configuration configuration = new >>> DefaultConfiguration(); >>> - private ExecutorService executorService; >>> - private ExecutorService executorServiceDeamons; >>> private Object externalContext; >>> private String contextName; >>> private volatile URI configLocation; >>> @@ -326,8 +316,8 @@ public class LoggerContext extends AbstractLifeCycle >>> * Log4j can start threads to perform certain actions like file >>> rollovers, calling this method with a positive timeout will >>> * block until the rollover thread is done. >>> * >>> - * @param timeout the maximum time to wait, or 0 which mean that >>> each apppender uses its default timeout, and don't wait for background >>> - tasks >>> + * @param timeout the maximum time to wait, or 0 which mean that >>> each apppender uses its default timeout, and wait for >>> + * background tasks for one second >>> * @param timeUnit >>> * the time unit of the timeout argument >>> * @return {@code true} if the logger context terminated and {@code >>> false} if the timeout elapsed before >>> @@ -338,8 +328,6 @@ public class LoggerContext extends AbstractLifeCycle >>> public boolean stop(final long timeout, final TimeUnit timeUnit) { >>> LOGGER.debug("Stopping LoggerContext[name={}, {}]...", >>> getName(), this); >>> configLock.lock(); >>> - final boolean shutdownEs; >>> - final boolean shutdownEsd; >>> try { >>> if (this.isStopped()) { >>> return true; >>> @@ -366,16 +354,12 @@ public class LoggerContext extends >>> AbstractLifeCycle >>> } >>> externalContext = null; >>> LogManager.getFactory().removeContext(this); >>> - final String source = "LoggerContext \'" + getName() + "\'"; >>> - shutdownEs = ExecutorServices.shutdown(executorService, >>> timeout, timeUnit, source); >>> - // Do not wait for daemon threads >>> - shutdownEsd = ExecutorServices.shutdown(executorServiceDeamons, >>> 0, timeUnit, source); >>> } finally { >>> configLock.unlock(); >>> this.setStopped(); >>> } >>> LOGGER.debug("Stopped LoggerContext[name={}, {}]...", >>> getName(), this); >>> - return shutdownEs && shutdownEsd; >>> + return true; >>> } >>> >>> /** >>> @@ -548,9 +532,6 @@ public class LoggerContext extends AbstractLifeCycle >>> try { >>> final Configuration prev = this.configuration; >>> config.addListener(this); >>> - executorService = createNonDaemonThreadPool(Log4 >>> jThreadFactory.createThreadFactory(contextName)); >>> - // Daemon threads do not prevent the application from >>> shutting down so the default keep-alive time is fine. >>> - executorServiceDeamons = Executors.newCachedThreadPool( >>> Log4jThreadFactory.createDaemonThreadFactory(contextName)); >>> >>> final ConcurrentMap<String, String> map = >>> config.getComponent(Configuration.CONTEXT_PROPERTIES); >>> >>> @@ -586,30 +567,6 @@ public class LoggerContext extends AbstractLifeCycle >>> } >>> } >>> >>> - /** >>> - * Returns an {@code ExecutorService} whose keep-alive time is one >>> second by default, unless another >>> - * value is specified for system property {@code >>> log4j.nondaemon.threads.keepAliveSeconds}. >>> - * <p> >>> - * LOG4J2-1748: ThreadPool for non-daemon threads should use a >>> short keep-alive time to prevent >>> - * applications from being able to shut down promptly after a >>> rollover. >>> - * </p> >>> - * >>> - * @param threadFactory thread factory to use >>> - * @return a new cached thread pool >>> - */ >>> - private ExecutorService createNonDaemonThreadPool(final >>> ThreadFactory threadFactory) { >>> - final String PROP = "log4j.nondaemon.threads.keepAliveSeconds"; >>> - final int keepAliveTimeSeconds = >>> PropertiesUtil.getProperties().getIntegerProperty(PROP, >>> 1); >>> - return createThreadPool(threadFactory, keepAliveTimeSeconds); >>> - } >>> - >>> - private ExecutorService createThreadPool(final ThreadFactory >>> threadFactory, final int keepAliveTimeSeconds) { >>> - return new ThreadPoolExecutor(0, Integer.MAX_VALUE, >>> - keepAliveTimeSeconds, TimeUnit.SECONDS, >>> - new SynchronousQueue<Runnable>(), >>> - threadFactory); >>> - } >>> - >>> private void firePropertyChangeEvent(final PropertyChangeEvent >>> event) { >>> for (final PropertyChangeListener listener : >>> propertyChangeListeners) { >>> listener.propertyChange(event); >>> @@ -719,52 +676,4 @@ public class LoggerContext extends AbstractLifeCycle >>> return new Logger(ctx, name, messageFactory); >>> } >>> >>> - /** >>> - * Gets the executor service to submit normal tasks. >>> - * >>> - * @return the ExecutorService to submit normal tasks. >>> - */ >>> - public ExecutorService getExecutorService() { >>> - return executorService; >>> - } >>> - >>> - /** >>> - * Gets the executor service to submit daemon tasks. >>> - * >>> - * @return the ExecutorService to submit normal daemon tasks. >>> - */ >>> - public ExecutorService getExecutorServiceDeamons() { >>> - return executorServiceDeamons; >>> - } >>> - >>> - /** >>> - * Submits a Runnable task for normal execution and returns a >>> Future representing that task. The Future's >>> - * {@code get} method will return {@code null} upon >>> <em>successful</em> completion. >>> - * >>> - * @param task the task to submit >>> - * @return a Future representing pending completion of the task >>> - * @throws RejectedExecutionException if the task cannot be >>> - * scheduled for execution >>> - * @throws NullPointerException if the task is null >>> - */ >>> - public Future<?> submit(final Runnable task) { >>> - return executorService.submit(task); >>> - } >>> - >>> - /** >>> - * Submits a Runnable task for daemon execution and returns a >>> Future representing that task. The Future's >>> - * {@code get} method will return {@code null} upon >>> <em>successful</em> completion. >>> - * >>> - * @param task >>> - * the task to submit >>> - * @return a Future representing pending completion of the task >>> - * @throws RejectedExecutionException >>> - * if the task cannot be scheduled for execution >>> - * @throws NullPointerException >>> - * if the task is null >>> - */ >>> - public Future<?> submitDaemon(final Runnable task) { >>> - return executorServiceDeamons.submit(task); >>> - } >>> - >>> } >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/appender/mom/kafka/KafkaManager.java >>> ---------------------------------------------------------------------- >>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/mom/kafka/KafkaManager.java b/log4j-core/src/main/java/org >>> /apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java >>> index 616191c..b293f2a 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/mom/kafka/KafkaManager.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/mom/kafka/KafkaManager.java >>> @@ -30,6 +30,7 @@ import org.apache.kafka.clients.produ >>> cer.RecordMetadata; >>> import org.apache.logging.log4j.core.LoggerContext; >>> import org.apache.logging.log4j.core.appender.AbstractManager; >>> import org.apache.logging.log4j.core.config.Property; >>> +import org.apache.logging.log4j.core.util.Log4jThread; >>> >>> public class KafkaManager extends AbstractManager { >>> >>> @@ -73,17 +74,19 @@ public class KafkaManager extends AbstractManager { >>> private void closeProducer(final long timeout, final TimeUnit >>> timeUnit) { >>> if (producer != null) { >>> // This thread is a workaround for this Kafka issue: >>> https://issues.apache.org/jira/browse/KAFKA-1660 >>> - final Runnable task = new Runnable() { >>> + final Thread closeThread = new Log4jThread(new Runnable() { >>> @Override >>> public void run() { >>> if (producer != null) { >>> producer.close(); >>> } >>> } >>> - }; >>> + }, "KafkaManager-CloseThread"); >>> + closeThread.setDaemon(true); // avoid blocking JVM shutdown >>> + closeThread.start(); >>> try { >>> - getLoggerContext().submitDaemon(task).get(timeout, >>> timeUnit); >>> - } catch (InterruptedException | ExecutionException | >>> TimeoutException e) { >>> + closeThread.join(timeUnit.toMillis(timeout)); >>> + } catch (final InterruptedException ignore) { >>> // ignore >>> } >>> } >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/appender/rolling/RollingFileManager.java >>> ---------------------------------------------------------------------- >>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/rolling/RollingFileManager.java b/log4j-core/src/main/java/org >>> /apache/logging/log4j/core/appender/rolling/RollingFileManager.java >>> index 10cb79e..e9c7790 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/rolling/RollingFileManager.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/rolling/RollingFileManager.java >>> @@ -296,7 +296,7 @@ public class RollingFileManager extends FileManager { >>> >>> if (success && descriptor.getAsynchronous() != null) { >>> LOGGER.debug("RollingFileManager executing async >>> {}", descriptor.getAsynchronous()); >>> - future = LoggerContext.getContext(false).submit(new >>> AsyncAction(descriptor.getAsynchronous(), this)); >>> + future = LoggerContext.getContext(false >>> ).getConfiguration().getScheduler().submit(new >>> AsyncAction(descriptor.getAsynchronous(), this)); >>> } >>> return true; >>> } >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/config/AbstractConfiguration.java >>> ---------------------------------------------------------------------- >>> diff --git >>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java >>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/AbstractConfiguration.java >>> index 3a6a58e..e5e149e 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/AbstractConfiguration.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/AbstractConfiguration.java >>> @@ -373,9 +373,9 @@ public abstract class AbstractConfiguration extends >>> AbstractFilterable implement >>> root.clearAppenders(); >>> >>> if (watchManager.isStarted()) { >>> - watchManager.stop(); >>> + watchManager.stop(timeout, timeUnit); >>> } >>> - configurationScheduler.stop(); >>> + configurationScheduler.stop(timeout, timeUnit); >>> >>> if (advertiser != null && advertisement != null) { >>> advertiser.unadvertise(advertisement); >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/config/ConfigurationScheduler.java >>> ---------------------------------------------------------------------- >>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfigurationScheduler.java b/log4j-core/src/main/java/org >>> /apache/logging/log4j/core/config/ConfigurationScheduler.java >>> index 6c639f2..4af83a5 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfigurationScheduler.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfigurationScheduler.java >>> @@ -17,9 +17,9 @@ >>> package org.apache.logging.log4j.core.config; >>> >>> import java.util.Date; >>> -import java.util.List; >>> import java.util.Queue; >>> import java.util.concurrent.Callable; >>> +import java.util.concurrent.Future; >>> import java.util.concurrent.ScheduledExecutorService; >>> import java.util.concurrent.ScheduledFuture; >>> import java.util.concurrent.ScheduledThreadPoolExecutor; >>> @@ -39,6 +39,7 @@ public class ConfigurationScheduler extends >>> AbstractLifeCycle { >>> private static final Logger LOGGER = StatusLogger.getLogger(); >>> private static final String SIMPLE_NAME = "Log4j2 " + >>> ConfigurationScheduler.class.getSimpleName(); >>> private static final int MAX_SCHEDULED_ITEMS = 5; >>> + private static final long DEFAULT_SHUTDOWN_TIMEOUT_MILLIS = 1000; >>> private ScheduledExecutorService executorService; >>> >>> private int scheduledItems = 0; >>> @@ -52,14 +53,17 @@ public class ConfigurationScheduler extends >>> AbstractLifeCycle { >>> public boolean stop(final long timeout, final TimeUnit timeUnit) { >>> setStopping(); >>> if (isExecutorServiceSet()) { >>> + long timeoutToUse = timeout > 0 ? timeout : >>> DEFAULT_SHUTDOWN_TIMEOUT_MILLIS; >>> + TimeUnit timeUnitToUse = timeout > 0 ? timeUnit : >>> TimeUnit.MILLISECONDS; >>> + >>> LOGGER.debug("{} shutting down threads in {}", SIMPLE_NAME, >>> getExecutorService()); >>> executorService.shutdown(); >>> try { >>> - executorService.awaitTermination(timeout, timeUnit); >>> + executorService.awaitTermination(timeoutToUse, >>> timeUnitToUse); >>> } catch (InterruptedException ie) { >>> executorService.shutdownNow(); >>> try { >>> - executorService.awaitTermination(timeout, >>> timeUnit); >>> + executorService.awaitTermination(timeoutToUse, >>> timeUnitToUse); >>> } catch (InterruptedException inner) { >>> LOGGER.warn("ConfigurationScheduler stopped but >>> some scheduled services may not have completed."); >>> } >>> @@ -95,6 +99,28 @@ public class ConfigurationScheduler extends >>> AbstractLifeCycle { >>> } >>> >>> /** >>> + * Creates and executes a Future that becomes enabled immediately. >>> + * @param <V> The result type returned by this Future >>> + * @param callable the function to execute. >>> + * @return a Future that can be used to extract result or cancel. >>> + * >>> + */ >>> + public <V> Future<V> submit(final Callable<V> callable) { >>> + return getExecutorService().submit(callable); >>> + } >>> + >>> + /** >>> + * Creates and executes a Future that becomes enabled immediately. >>> + * @param runnable the function to execute. >>> + * @return a Future representing pending completion of the task and >>> whose get() method will return null >>> + * upon completion. >>> + */ >>> + public Future<?> submit(final Runnable runnable) { >>> + return getExecutorService().submit(runnable); >>> + } >>> + >>> + >>> + /** >>> * Creates and executes a ScheduledFuture that becomes enabled >>> after the given delay. >>> * @param <V> The result type returned by this Future >>> * @param callable the function to execute. >>> @@ -183,18 +209,13 @@ public class ConfigurationScheduler extends >>> AbstractLifeCycle { >>> >>> private ScheduledExecutorService getExecutorService() { >>> if (executorService == null) { >>> - if (scheduledItems > 0) { >>> - LOGGER.debug("{} starting {} threads", SIMPLE_NAME, >>> scheduledItems); >>> - scheduledItems = Math.min(scheduledItems, >>> MAX_SCHEDULED_ITEMS); >>> - ScheduledThreadPoolExecutor executor = new >>> ScheduledThreadPoolExecutor(scheduledItems, >>> - Log4jThreadFactory.createDaemo >>> nThreadFactory("Scheduled")); >>> - executor.setContinueExistingPe >>> riodicTasksAfterShutdownPolicy(false); >>> - executor.setExecuteExistingDel >>> ayedTasksAfterShutdownPolicy(false); >>> - this.executorService = executor; >>> - >>> - } else { >>> - LOGGER.debug("{}: No scheduled items", SIMPLE_NAME); >>> - } >>> + LOGGER.debug("{} starting {} threads", SIMPLE_NAME, >>> scheduledItems); >>> + scheduledItems = Math.min(scheduledItems, >>> MAX_SCHEDULED_ITEMS); >>> + ScheduledThreadPoolExecutor executor = new >>> ScheduledThreadPoolExecutor(scheduledItems + 1, >>> + Log4jThreadFactory.createDaemo >>> nThreadFactory("Scheduled")); >>> + executor.setContinueExistingPe >>> riodicTasksAfterShutdownPolicy(false); >>> + executor.setExecuteExistingDel >>> ayedTasksAfterShutdownPolicy(false); >>> + this.executorService = executor; >>> } >>> return executorService; >>> } >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/config/ConfiguratonFileWatcher.java >>> ---------------------------------------------------------------------- >>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfiguratonFileWatcher.java b/log4j-core/src/main/java/org >>> /apache/logging/log4j/core/config/ConfiguratonFileWatcher.java >>> index b32f9d0..38491f2 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfiguratonFileWatcher.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/ConfiguratonFileWatcher.java >>> @@ -19,8 +19,8 @@ package org.apache.logging.log4j.core.config; >>> import java.io.File; >>> import java.util.List; >>> >>> -import org.apache.logging.log4j.core.LoggerContext; >>> import org.apache.logging.log4j.core.util.FileWatcher; >>> +import org.apache.logging.log4j.core.util.Log4jThreadFactory; >>> >>> /** >>> * Watcher for configuration files. Causes a reconfiguration when a >>> file changes. >>> @@ -29,10 +29,12 @@ public class ConfiguratonFileWatcher implements >>> FileWatcher { >>> >>> private final Reconfigurable reconfigurable; >>> private final List<ConfigurationListener> configurationListeners; >>> + private final Log4jThreadFactory threadFactory; >>> >>> public ConfiguratonFileWatcher(final Reconfigurable reconfigurable, >>> final List<ConfigurationListener> configurationListeners) { >>> this.reconfigurable = reconfigurable; >>> this.configurationListeners = configurationListeners; >>> + this.threadFactory = Log4jThreadFactory.createDaemo >>> nThreadFactory("ConfiguratonFileWatcher"); >>> } >>> >>> public List<ConfigurationListener> getListeners() { >>> @@ -43,7 +45,8 @@ public class ConfiguratonFileWatcher implements >>> FileWatcher { >>> @Override >>> public void fileModified(final File file) { >>> for (final ConfigurationListener configurationListener : >>> configurationListeners) { >>> - LoggerContext.getContext(false).submitDaemon(new >>> ReconfigurationRunnable(configurationListener, reconfigurable)); >>> + final Thread thread = threadFactory.newThread(new >>> ReconfigurationRunnable(configurationListener, reconfigurable)); >>> + thread.start(); >>> } >>> } >>> >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/config/Configurator.java >>> ---------------------------------------------------------------------- >>> diff --git >>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java >>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/Configurator.java >>> index 28dd85f..63d8a81 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/Configurator.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con >>> fig/Configurator.java >>> @@ -331,8 +331,8 @@ public final class Configurator { >>> /** >>> * Shuts down the given logger context. This request does not wait >>> for Log4j tasks to complete. >>> * <p> >>> - * Log4j starts threads to perform certain actions like file >>> rollovers; calling this method will not wait until the >>> - * rollover thread is done. When this method returns, these tasks' >>> status are undefined, the tasks may be done or >>> + * Log4j starts threads to perform certain actions like file >>> rollovers; calling this method will wait up to one second >>> + * until the rollover thread is done. When this method returns, >>> these tasks' status are undefined, the tasks may be done or >>> * not. >>> * </p> >>> * >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-core/src/main/java/org/apache/logging/log4j/co >>> re/util/Log4jThreadFactory.java >>> ---------------------------------------------------------------------- >>> diff --git >>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Log4jThreadFactory.java >>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/uti >>> l/Log4jThreadFactory.java >>> index 3715243..2318feb 100644 >>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/uti >>> l/Log4jThreadFactory.java >>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/uti >>> l/Log4jThreadFactory.java >>> @@ -40,17 +40,6 @@ public class Log4jThreadFactory implements >>> ThreadFactory { >>> return new Log4jThreadFactory(threadFactoryName, true, >>> Thread.NORM_PRIORITY); >>> } >>> >>> - /** >>> - * Creates a new thread factory. >>> - * >>> - * @param threadFactoryName >>> - * The thread factory name. >>> - * @return a new daemon thread factory. >>> - */ >>> - public static Log4jThreadFactory createThreadFactory(final String >>> threadFactoryName) { >>> - return new Log4jThreadFactory(threadFactoryName, false, >>> Thread.NORM_PRIORITY); >>> - } >>> - >>> private static final AtomicInteger FACTORY_NUMBER = new >>> AtomicInteger(1); >>> private static final AtomicInteger THREAD_NUMBER = new >>> AtomicInteger(1); >>> private final boolean daemon; >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/log4j-nosql/src/test/java/org/apache/logging/log4j/n >>> osql/appender/cassandra/CassandraRule.java >>> ---------------------------------------------------------------------- >>> diff --git a/log4j-nosql/src/test/java/org/apache/logging/log4j/nosql/a >>> ppender/cassandra/CassandraRule.java b/log4j-nosql/src/test/java/or >>> g/apache/logging/log4j/nosql/appender/cassandra/CassandraRule.java >>> index bec97ea..900f794 100644 >>> --- a/log4j-nosql/src/test/java/org/apache/logging/log4j/nosql/a >>> ppender/cassandra/CassandraRule.java >>> +++ b/log4j-nosql/src/test/java/org/apache/logging/log4j/nosql/a >>> ppender/cassandra/CassandraRule.java >>> @@ -37,7 +37,7 @@ import org.junit.rules.ExternalResource; >>> */ >>> public class CassandraRule extends ExternalResource { >>> >>> - private static final ThreadFactory THREAD_FACTORY = >>> Log4jThreadFactory.createThreadFactory("Cassandra"); >>> + private static final ThreadFactory THREAD_FACTORY = new >>> Log4jThreadFactory("Cassandra", false, Thread.NORM_PRIORITY); >>> >>> private final CountDownLatch latch = new CountDownLatch(1); >>> private final Cancellable embeddedCassandra = new >>> EmbeddedCassandra(latch); >>> >>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1 >>> 62a5e33/src/site/xdoc/manual/configuration.xml.vm >>> ---------------------------------------------------------------------- >>> diff --git a/src/site/xdoc/manual/configuration.xml.vm >>> b/src/site/xdoc/manual/configuration.xml.vm >>> index ec73bac..3075839 100644 >>> --- a/src/site/xdoc/manual/configuration.xml.vm >>> +++ b/src/site/xdoc/manual/configuration.xml.vm >>> @@ -410,8 +410,8 @@ public class Bar { >>> <tr> >>> <td>shutdownTimeout</td> >>> <td>Specifies how many milliseconds appenders and >>> background tasks will get to shutdown when the JVM shuts >>> - down. Default is zero which mean that each appender >>> uses its default timeout, and don't wait for background >>> - tasks. Not all appenders will honor this, it is a hint >>> and not an absolute guarantee that the shutdown >>> + down. Default is zero which mean that each appender >>> uses its default timeout, and wait for background >>> + tasks for one second. Not all appenders will honor >>> this, it is a hint and not an absolute guarantee that the shutdown >>> procedure will not take longer. Setting this too low >>> increase the risk of losing outstanding log events >>> not yet written to the final destination. See <a >>> class="javadoc" >>> href="../log4j-core/target/sit >>> e/apidocs/org/apache/logging/log4j/core/LoggerContext.html#stop(long, >>> java.util.concurrent.TimeUnit)">LoggerContext.stop(long, >>> java.util.concurrent.TimeUnit)</a>. >>> >>> >> > > > -- > E-Mail: garydgreg...@gmail.com | ggreg...@apache.org > Java Persistence with Hibernate, Second Edition > <https://www.amazon.com/gp/product/1617290459/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1617290459&linkCode=as2&tag=garygregory-20&linkId=cadb800f39946ec62ea2b1af9fe6a2b8> > > <http:////ir-na.amazon-adsystem.com/e/ir?t=garygregory-20&l=am2&o=1&a=1617290459> > JUnit in Action, Second Edition > <https://www.amazon.com/gp/product/1935182021/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1935182021&linkCode=as2&tag=garygregory-20&linkId=31ecd1f6b6d1eaf8886ac902a24de418%22> > > <http:////ir-na.amazon-adsystem.com/e/ir?t=garygregory-20&l=am2&o=1&a=1935182021> > Spring Batch in Action > <https://www.amazon.com/gp/product/1935182951/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1935182951&linkCode=%7B%7BlinkCode%7D%7D&tag=garygregory-20&linkId=%7B%7Blink_id%7D%7D%22%3ESpring+Batch+in+Action> > <http:////ir-na.amazon-adsystem.com/e/ir?t=garygregory-20&l=am2&o=1&a=1935182951> > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory >