in log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java [366:467]
public boolean stop(final long timeout, final TimeUnit timeUnit) {
LOGGER.info("Stopping configuration {}...", this);
this.setStopping();
super.stop(timeout, timeUnit, false);
// Stop the components that are closest to the application first:
// 1. Notify all LoggerConfigs' ReliabilityStrategy that the configuration will be stopped.
// 2. Stop the LoggerConfig objects (this may stop nested Filters)
// 3. Stop the AsyncLoggerConfigDelegate. This shuts down the AsyncLoggerConfig Disruptor
// and waits until all events in the RingBuffer have been processed.
// 4. Stop all AsyncAppenders. This shuts down the associated thread and
// waits until all events in the queue have been processed. (With optional timeout.)
// 5. Notify all LoggerConfigs' ReliabilityStrategy that appenders will be stopped.
// This guarantees that any event received by a LoggerConfig before reconfiguration
// are passed on to the Appenders before the Appenders are stopped.
// 6. Stop the remaining running Appenders. (It should now be safe to do so.)
// 7. Notify all LoggerConfigs that their Appenders can be cleaned up.
for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
loggerConfig.getReliabilityStrategy().beforeStopConfiguration(this);
}
root.getReliabilityStrategy().beforeStopConfiguration(this);
final String cls = getClass().getSimpleName();
LOGGER.trace(
"{} notified {} ReliabilityStrategies that config will be stopped.", cls, loggerConfigs.size() + 1);
if (!loggerConfigs.isEmpty()) {
LOGGER.trace("{} stopping {} LoggerConfigs.", cls, loggerConfigs.size());
for (final LoggerConfig logger : loggerConfigs.values()) {
logger.stop(timeout, timeUnit);
}
}
LOGGER.trace("{} stopping root LoggerConfig.", cls);
if (!root.isStopped()) {
root.stop(timeout, timeUnit);
}
if (hasAsyncLoggers()) {
LOGGER.trace("{} stopping AsyncLoggerConfigDisruptor.", cls);
asyncLoggerConfigDisruptor.stop(timeout, timeUnit);
}
LOGGER.trace("{} notifying ReliabilityStrategies that appenders will be stopped.", cls);
for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
loggerConfig.getReliabilityStrategy().beforeStopAppenders();
}
root.getReliabilityStrategy().beforeStopAppenders();
// Stop the appenders in reverse order in case they still have activity.
final Appender[] array = appenders.values().toArray(Appender.EMPTY_ARRAY);
final List<Appender> async = getAsyncAppenders(array);
if (!async.isEmpty()) {
// LOG4J2-511, LOG4J2-392 stop AsyncAppenders first
LOGGER.trace("{} stopping {} AsyncAppenders.", cls, async.size());
for (final Appender appender : async) {
if (appender instanceof LifeCycle2) {
((LifeCycle2) appender).stop(timeout, timeUnit);
} else {
appender.stop();
}
}
}
LOGGER.trace("{} stopping remaining Appenders.", cls);
int appenderCount = 0;
for (int i = array.length - 1; i >= 0; --i) {
if (array[i].isStarted()) { // then stop remaining Appenders
if (array[i] instanceof LifeCycle2) {
((LifeCycle2) array[i]).stop(timeout, timeUnit);
} else {
array[i].stop();
}
appenderCount++;
}
}
LOGGER.trace("{} stopped {} remaining Appenders.", cls, appenderCount);
LOGGER.trace("{} cleaning Appenders from {} LoggerConfigs.", cls, loggerConfigs.size() + 1);
for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
// LOG4J2-520, LOG4J2-392:
// Important: do not clear appenders until after all AsyncLoggerConfigs
// have been stopped! Stopping the last AsyncLoggerConfig will
// shut down the disruptor and wait for all enqueued events to be processed.
// Only *after this* the appenders can be cleared or events will be lost.
loggerConfig.clearAppenders();
}
root.clearAppenders();
if (watchManager.isStarted()) {
watchManager.stop(timeout, timeUnit);
}
configurationScheduler.stop(timeout, timeUnit);
if (advertiser != null && advertisement != null) {
advertiser.unadvertise(advertisement);
}
setStopped();
LOGGER.info("Configuration {} stopped.", this);
return true;
}