Improve Log4J log level reset support
Update `Log4J2LoggingSystem` so that call to `setLevel` with a `null` level with remove the logger if it was previously configured by a `LoggingSystem` call. To track which loggers have been configured by us, and which have been configure directly by the user, a custom `LoggerConfig` subclass is used. We'll only remove `LevelSetLoggerConfig` classes, for any others we'll call `setLevel(null)` on the config. Prior to this commit, it was impossible to set then reset a logger level using the actuator endpoint. This is because Log4J doesn't provide a way to get the actual configured level. If the `setLevel(null)` has been applied, then `getLevel()` will return the value of the parent logger or a default value of `ERROR`. Fixes gh-24298
This commit is contained in:
@@ -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 class Log4J2LoggingSystem extends Slf4JLoggingSystem {
|
||||
|
||||
@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 class Log4J2LoggingSystem extends Slf4JLoggingSystem {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.EnumSet;
|
||||
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.LogManager;
|
||||
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 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
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 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
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('.', '/');
|
||||
|
||||
Reference in New Issue
Block a user