Skip to content

Commit

Permalink
Disable Log4j2's shutdown hook by default
Browse files Browse the repository at this point in the history
Previously, Log4j2's own shutdown hook was only disabled when Log4j2
detected javax.servlet.Servlet on the classpath and, therefore,
determined that it was running in a web application. In an application
without Servlet on the classpath, this could lead to both Log4j2's shut
down hook and and logging system's shutdown handler both stopping
Log4j2. This could result in a failure as the second attempt at stopping
would result in reinitialization which would fail as the JVM is already
shutting down.

This commit introduces a new Log4j2 PropertySource implementation,
registered via META-INF/services, that sets the
log4j.shutdownHookEnabled property to false. This will ensure that
Log4j2's own shutdown hook is disabled by default whenever Spring Boot
is on the classpath and not just in Servlet-based web applications.

Fixes spring-projectsgh-26953
  • Loading branch information
wilkinsona committed Jun 21, 2021
1 parent 07e7398 commit 35190f0
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,12 @@ private LoggerConfiguration convertLoggerConfig(String name, LoggerConfig logger

@Override
public Runnable getShutdownHandler() {
return () -> getLoggerContext().stop();
if (getLoggerContext().getConfiguration().isShutdownHookEnabled()) {
return null;
}
return () -> {
getLoggerContext().stop();
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@
*
* <ol>
* <li>Prevent logger warnings from being printed when the application first starts.
* <li>Disable its shutdown hook
* </ol>
*
* This factory is ordered last and is triggered by a {@code log4j2.springboot} classpath
* resource (which is bundled in this jar). If the {@link Log4J2LoggingSystem} is active,
* a custom {@link DefaultConfiguration} is returned with the expectation that the system
* will later re-initialize Log4J2 with the correct configuration file.
* a {@link DefaultConfiguration} is returned with the expectation that the system will
* later re-initialize Log4J2 with the correct configuration file.
*
* @author Phillip Webb
* @since 1.5.0
Expand All @@ -57,15 +56,7 @@ public Configuration getConfiguration(LoggerContext loggerContext, Configuration
if (source == null || source == ConfigurationSource.NULL_SOURCE) {
return null;
}
return new SpringBootConfiguration();
}

private static final class SpringBootConfiguration extends DefaultConfiguration {

private SpringBootConfiguration() {
this.isShutdownHookEnabled = false;
}

return new DefaultConfiguration();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.logging.log4j2;

import java.util.Collections;
import java.util.Map;

import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.PropertySource;

/**
* Spring Boot {@link PropertySource} that disables Log4j2's shutdown hook.
*
* @author Andy Wilkinson
* @since 2.5.2
*/
public class SpringBootPropertySource implements PropertySource {

private static final String PREFIX = "log4j.";

private final Map<String, String> properties = Collections
.singletonMap(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, "false");

@Override
public void forEach(BiConsumer<String, String> action) {
this.properties.forEach((key, value) -> action.accept(key, value));
}

@Override
public CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) {
return PREFIX + Util.joinAsCamelCase(tokens);
}

@Override
public int getPriority() {
return -200;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.springframework.boot.logging.log4j2.SpringBootPropertySource
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
Expand Down Expand Up @@ -370,6 +372,13 @@ void getLoggingConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConf
.isEqualTo(new LoggerConfiguration("com.example.test", LogLevel.WARN, LogLevel.WARN));
}

@Test
void shutdownHookIsDisabled() {
assertThat(
PropertiesUtil.getProperties().getBooleanProperty(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, true))
.isFalse();
}

private String getRelativeClasspathLocation(String fileName) {
String defaultPath = ClassUtils.getPackageName(getClass());
defaultPath = defaultPath.replace('.', '/');
Expand Down

0 comments on commit 35190f0

Please sign in to comment.