diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index ed5e29cc384c..f7ebcac001c3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * 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. @@ -214,16 +214,37 @@ public Set getSupportedLogLevels() { @Override public void setLogLevel(String loggerName, LogLevel logLevel) { - Level level = LEVELS.convertSystemToNative(logLevel); + setLogLevel(loggerName, LEVELS.convertSystemToNative(logLevel)); + } + + private void setLogLevel(String loggerName, Level level) { LoggerConfig logger = getLogger(loggerName); + if (level == null) { + clearLogLevel(loggerName, logger); + } + else { + setLogLevel(loggerName, logger, level); + } + getLoggerContext().updateLoggers(); + } + + private void clearLogLevel(String loggerName, LoggerConfig logger) { + if (logger instanceof LevelSetLoggerConfig) { + getLoggerContext().getConfiguration().removeLogger(loggerName); + } + else { + logger.setLevel(null); + } + } + + private void setLogLevel(String loggerName, LoggerConfig logger, Level level) { if (logger == null) { - logger = new LoggerConfig(loggerName, level, true); - getLoggerContext().getConfiguration().addLogger(loggerName, logger); + getLoggerContext().getConfiguration().addLogger(loggerName, + new LevelSetLoggerConfig(loggerName, level, true)); } else { logger.setLevel(level); } - getLoggerContext().updateLoggers(); } @Override @@ -348,4 +369,15 @@ public LoggingSystem getLoggingSystem(ClassLoader classLoader) { } + /** + * {@link LoggerConfig} used when the user has set a specific {@link Level}. + */ + private static class LevelSetLoggerConfig extends LoggerConfig { + + LevelSetLoggerConfig(String name, Level level, boolean additive) { + super(name, level, additive); + } + + } + } 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 4ccc6bb31a72..3a58f22c5163 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * 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. @@ -25,7 +25,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.logging.Level; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.logging.Log; @@ -34,6 +33,7 @@ import org.apache.logging.log4j.Logger; 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.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -241,7 +241,7 @@ void loggingThatUsesJulIsCaptured(CapturedOutput output) { this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(null, null, null); java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(getClass().getName()); - julLogger.setLevel(Level.INFO); + julLogger.setLevel(java.util.logging.Level.INFO); julLogger.severe("Hello world"); assertThat(output).contains("Hello world"); } @@ -338,6 +338,38 @@ void initializationIsOnlyPerformedOnceUntilCleanedUp() { verify(listener, times(4)).propertyChange(any(PropertyChangeEvent.class)); } + @Test + void getLoggingConfigurationWithResetLevelReturnsNull() { + this.loggingSystem.beforeInitialize(); + this.loggingSystem.initialize(null, null, null); + this.loggingSystem.setLogLevel("com.example", LogLevel.WARN); + this.loggingSystem.setLogLevel("com.example.test", LogLevel.DEBUG); + LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration("com.example.test"); + assertThat(configuration) + .isEqualTo(new LoggerConfiguration("com.example.test", LogLevel.DEBUG, LogLevel.DEBUG)); + this.loggingSystem.setLogLevel("com.example.test", null); + LoggerConfiguration updatedConfiguration = this.loggingSystem.getLoggerConfiguration("com.example.test"); + assertThat(updatedConfiguration).isNull(); + } + + @Test + void getLoggingConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConfiguredLevel() { + LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + this.loggingSystem.beforeInitialize(); + this.loggingSystem.initialize(null, null, null); + loggerContext.getConfiguration().addLogger("com.example.test", + new LoggerConfig("com.example.test", org.apache.logging.log4j.Level.INFO, false)); + this.loggingSystem.setLogLevel("com.example", LogLevel.WARN); + this.loggingSystem.setLogLevel("com.example.test", LogLevel.DEBUG); + LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration("com.example.test"); + assertThat(configuration) + .isEqualTo(new LoggerConfiguration("com.example.test", LogLevel.DEBUG, LogLevel.DEBUG)); + this.loggingSystem.setLogLevel("com.example.test", null); + LoggerConfiguration updatedConfiguration = this.loggingSystem.getLoggerConfiguration("com.example.test"); + assertThat(updatedConfiguration) + .isEqualTo(new LoggerConfiguration("com.example.test", LogLevel.WARN, LogLevel.WARN)); + } + private String getRelativeClasspathLocation(String fileName) { String defaultPath = ClassUtils.getPackageName(getClass()); defaultPath = defaultPath.replace('.', '/');