From cf940fd3743803a1a95ff41e4981482dda05fb1f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 21 Jun 2021 19:58:02 +0100 Subject: [PATCH] Disable Log4j2's shutdown hook by default 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 gh-26953 --- .../SpringBootConfigurationFactory.java | 15 ++---- .../log4j2/SpringBootPropertySource.java | 54 +++++++++++++++++++ ...g.apache.logging.log4j.util.PropertySource | 1 + .../log4j2/Log4J2LoggingSystemTests.java | 9 ++++ .../SpringBootConfigurationFactoryTests.java | 42 --------------- 5 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootPropertySource.java create mode 100644 spring-boot-project/spring-boot/src/main/resources/META-INF/services/org.apache.logging.log4j.util.PropertySource delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactoryTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactory.java index 9cc3cd2cf5..6460ba1c12 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactory.java @@ -30,13 +30,12 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; * *
    *
  1. Prevent logger warnings from being printed when the application first starts. - *
  2. Disable its shutdown hook *
* * 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 @@ -57,15 +56,7 @@ public class SpringBootConfigurationFactory extends ConfigurationFactory { 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(); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootPropertySource.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootPropertySource.java new file mode 100644 index 0000000000..29c5cc2ec0 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootPropertySource.java @@ -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 properties = Collections + .singletonMap(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, "false"); + + @Override + public void forEach(BiConsumer action) { + this.properties.forEach((key, value) -> action.accept(key, value)); + } + + @Override + public CharSequence getNormalForm(Iterable tokens) { + return PREFIX + Util.joinAsCamelCase(tokens); + } + + @Override + public int getPriority() { + return -200; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/services/org.apache.logging.log4j.util.PropertySource b/spring-boot-project/spring-boot/src/main/resources/META-INF/services/org.apache.logging.log4j.util.PropertySource new file mode 100644 index 0000000000..b990694a78 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/services/org.apache.logging.log4j.util.PropertySource @@ -0,0 +1 @@ +org.springframework.boot.logging.log4j2.SpringBootPropertySource \ No newline at end of file diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index 3a58f22c51..2a96b0781f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -35,6 +35,8 @@ import org.apache.logging.log4j.core.LoggerContext; 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; @@ -370,6 +372,13 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { .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('.', '/'); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactoryTests.java deleted file mode 100644 index 3b5e650b56..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactoryTests.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2019 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.io.ByteArrayInputStream; -import java.io.IOException; - -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.ConfigurationSource; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link SpringBootConfigurationFactory}. - * - * @author Andy Wilkinson - */ -class SpringBootConfigurationFactoryTests { - - @Test - void producesConfigurationWithShutdownHookDisabled() throws IOException { - ConfigurationSource source = new ConfigurationSource(new ByteArrayInputStream(new byte[0])); - assertThat(new SpringBootConfigurationFactory().getConfiguration(new LoggerContext(""), source) - .isShutdownHookEnabled()).isFalse(); - } - -}