Fix logging hierarchy configs

Today when setting the logging level via the command-line or an API
call, the expectation is that the logging level should trickle down the
hiearchy to descendant loggers. However, this is not necessarily the
case. For example, if loggers x and x.y are already configured then
setting the logging level on x will not descend to x.y. This is because
the logging config for x.y has already been forked from the logging
config for x. Therefore, we must explicitly descend the hierarchy when
setting the logging level and that is what this commit does.

Relates #20463
This commit is contained in:
Jason Tedor 2016-09-13 22:46:14 -04:00 committed by GitHub
parent 4704efaef4
commit 0eff7daf5b
4 changed files with 58 additions and 10 deletions

View File

@ -30,7 +30,6 @@ import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
import org.apache.logging.log4j.core.config.properties.PropertiesConfiguration;
import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
@ -44,7 +43,6 @@ import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@ -81,13 +79,14 @@ public class LogConfigurator {
}
if (ESLoggerFactory.LOG_DEFAULT_LEVEL_SETTING.exists(settings)) {
Loggers.setLevel(ESLoggerFactory.getRootLogger(), ESLoggerFactory.LOG_DEFAULT_LEVEL_SETTING.get(settings));
final Level level = ESLoggerFactory.LOG_DEFAULT_LEVEL_SETTING.get(settings);
Loggers.setLevel(ESLoggerFactory.getRootLogger(), level);
}
final Map<String, String> levels = settings.filter(ESLoggerFactory.LOG_LEVEL_SETTING::match).getAsMap();
for (String key : levels.keySet()) {
final Level level = ESLoggerFactory.LOG_LEVEL_SETTING.getConcreteSetting(key).get(settings);
Loggers.setLevel(Loggers.getLogger(key.substring("logger.".length())), level);
Loggers.setLevel(ESLoggerFactory.getLogger(key.substring("logger.".length())), level);
}
}

View File

@ -35,10 +35,12 @@ import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
import static javax.security.auth.login.Configuration.getConfiguration;
import static org.elasticsearch.common.util.CollectionUtils.asArrayList;
/**
@ -149,15 +151,23 @@ public class Loggers {
}
public static void setLevel(Logger logger, Level level) {
if (!"".equals(logger.getName())) {
if (!LogManager.ROOT_LOGGER_NAME.equals(logger.getName())) {
Configurator.setLevel(logger.getName(), level);
} else {
LoggerContext ctx = LoggerContext.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
final LoggerContext ctx = LoggerContext.getContext(false);
final Configuration config = ctx.getConfiguration();
final LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
loggerConfig.setLevel(level);
ctx.updateLoggers();
}
// we have to descend the hierarchy
final LoggerContext ctx = LoggerContext.getContext(false);
for (final LoggerConfig loggerConfig : ctx.getConfiguration().getLoggers().values()) {
if (LogManager.ROOT_LOGGER_NAME.equals(logger.getName()) || loggerConfig.getName().startsWith(logger.getName() + ".")) {
Configurator.setLevel(loggerConfig.getName(), level);
}
}
}
private static String buildClassLoggerName(Class<?> clazz) {

View File

@ -96,7 +96,7 @@ public class EvilLoggerConfigurationTests extends ESTestCase {
final Environment environment = new Environment(settings);
LogConfigurator.configure(environment, true);
final String loggerName = Loggers.commonPrefix + "test";
final String loggerName = "test";
final Logger logger = ESLoggerFactory.getLogger(loggerName);
assertThat(logger.getLevel().toString(), equalTo(level));
}
@ -113,9 +113,28 @@ public class EvilLoggerConfigurationTests extends ESTestCase {
LogConfigurator.configure(environment, true);
// args should overwrite whatever is in the config
final String loggerName = Loggers.commonPrefix + "test_resolve_order";
final String loggerName = "test_resolve_order";
final Logger logger = ESLoggerFactory.getLogger(loggerName);
assertTrue(logger.isTraceEnabled());
}
public void testHierarchy() throws Exception {
final Path configDir = getDataPath("hierarchy");
final Settings settings = Settings.builder()
.put(Environment.PATH_CONF_SETTING.getKey(), configDir.toAbsolutePath())
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString())
.build();
final Environment environment = new Environment(settings);
LogConfigurator.configure(environment, true);
assertThat(ESLoggerFactory.getLogger("x").getLevel(), equalTo(Level.TRACE));
assertThat(ESLoggerFactory.getLogger("x.y").getLevel(), equalTo(Level.DEBUG));
final Level level = randomFrom(Level.TRACE, Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR);
Loggers.setLevel(ESLoggerFactory.getLogger("x"), level);
assertThat(ESLoggerFactory.getLogger("x").getLevel(), equalTo(level));
assertThat(ESLoggerFactory.getLogger("x.y").getLevel(), equalTo(level));
}
}

View File

@ -0,0 +1,20 @@
status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
rootLogger.appenderRef.file.ref = file
logger.x.name = x
logger.x.level = trace
logger.x.appenderRef.console.ref = console
logger.x.additivity = false
logger.x_y.name = x.y
logger.x_y.level = debug
logger.x_y.appenderRef.console.ref = console
logger.x_y.additivity = false