diff --git a/src/main/java/io/github/ktestify/config/KtestifyConfig.java b/src/main/java/io/github/ktestify/config/KtestifyConfig.java index 955f89a..154f7e3 100644 --- a/src/main/java/io/github/ktestify/config/KtestifyConfig.java +++ b/src/main/java/io/github/ktestify/config/KtestifyConfig.java @@ -22,7 +22,9 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; /** * Main configuration class for ktestify framework. @@ -71,8 +73,9 @@ private KtestifyConfig(Config config) { } /** - * Applies log levels defined in {@code ktestify.logging} HOCON section via Log4j2's {@link Configurator}, - * overriding the static defaults set in {@code log4j2.properties}. + * Applies log levels defined in {@code ktestify.logging} HOCON section by modifying the Log4j2 {@link LoggerConfig} + * objects directly and calling {@code ctx.updateLoggers()}, overriding the static defaults set in + * {@code log4j2.properties}. * *
Supported keys and their environment variable overrides: * @@ -87,16 +90,21 @@ private KtestifyConfig(Config config) { private static void applyLogLevels(Config config) { Config lc = config.getConfig("ktestify.logging"); - Configurator.setLevel("io.github.ktestify", Level.toLevel(lc.getString("level"), Level.DEBUG)); - Configurator.setRootLevel(Level.toLevel(lc.getString("root-level"), Level.INFO)); - Configurator.setLevel("org.apache.kafka", Level.toLevel(lc.getString("kafka-level"), Level.WARN)); + LoggerContext ctx = LoggerContext.getContext(false); + Configuration log4jConfig = ctx.getConfiguration(); + + setLoggerLevel(log4jConfig, "io.github.ktestify", Level.toLevel(lc.getString("level"), Level.DEBUG)); + log4jConfig.getRootLogger().setLevel(Level.toLevel(lc.getString("root-level"), Level.INFO)); + setLoggerLevel(log4jConfig, "org.apache.kafka", Level.toLevel(lc.getString("kafka-level"), Level.WARN)); Level tcLevel = Level.toLevel(lc.getString("testcontainers-level"), Level.INFO); - Configurator.setLevel("org.testcontainers", tcLevel); - Configurator.setLevel("tc", tcLevel); - Configurator.setLevel("com.github.dockerjava", tcLevel); + setLoggerLevel(log4jConfig, "org.testcontainers", tcLevel); + setLoggerLevel(log4jConfig, "tc", tcLevel); + setLoggerLevel(log4jConfig, "com.github.dockerjava", tcLevel); + + setLoggerLevel(log4jConfig, "io.confluent", Level.toLevel(lc.getString("confluent-level"), Level.WARN)); - Configurator.setLevel("io.confluent", Level.toLevel(lc.getString("confluent-level"), Level.WARN)); + ctx.updateLoggers(log4jConfig); log.debug( "Log levels applied — ktestify={} root={} kafka={} confluent={}", @@ -106,6 +114,25 @@ private static void applyLogLevels(Config config) { lc.getString("confluent-level")); } + /** + * Sets the level on an existing named {@link LoggerConfig}, or creates a new one if it doesn't exist. + * + * @param log4jConfig the Log4j2 {@link Configuration} + * @param loggerName the logger name (use {@code null} for root) + * @param level the level to set + */ + private static void setLoggerLevel(Configuration log4jConfig, String loggerName, Level level) { + LoggerConfig loggerConfig = log4jConfig.getLoggerConfig(loggerName); + if (loggerConfig == null + || (!loggerName.equals(loggerConfig.getName()) + && !loggerConfig.getName().isEmpty())) { + loggerConfig = new LoggerConfig(loggerName, level, true); + log4jConfig.addLogger(loggerName, loggerConfig); + } else { + loggerConfig.setLevel(level); + } + } + /** * Applies the JVM-level truststore defined in {@code ktestify.jvm.truststore} HOCON section by setting the * corresponding {@code javax.net.ssl.*} system properties. This truststore is shared by all plugins and underlying diff --git a/src/test/java/io/github/ktestify/config/KtestifyConfigTest.java b/src/test/java/io/github/ktestify/config/KtestifyConfigTest.java index 7a58dd9..f8eb8ff 100644 --- a/src/test/java/io/github/ktestify/config/KtestifyConfigTest.java +++ b/src/test/java/io/github/ktestify/config/KtestifyConfigTest.java @@ -24,6 +24,9 @@ import java.nio.file.Path; import java.time.Duration; import java.util.Properties; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.LoggerConfig; import org.junit.jupiter.api.*; import org.junit.jupiter.api.io.TempDir; @@ -801,4 +804,94 @@ void shouldDefaultTruststoreTypeToJks() { assertEquals("JKS", System.getProperty("javax.net.ssl.trustStoreType")); } } + + // ========================================== + // LOG LEVEL TESTS + // ========================================== + + @Nested + @DisplayName("Log Levels") + class LogLevelTests { + + @AfterEach + void restoreRootLevel() { + // Restore root logger to INFO after each test + LoggerContext ctx = LoggerContext.getContext(false); + LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger(); + rootConfig.setLevel(Level.INFO); + ctx.updateLoggers(ctx.getConfiguration()); + } + + @Test + @DisplayName("Should set root logger level to DEBUG from config") + void shouldSetRootLoggerLevelToDebug() { + Config customConfig = ConfigFactory.parseString(""" + ktestify { + logging { + root-level = "DEBUG" + } + } + """); + + KtestifyConfig.load(customConfig); + + LoggerContext ctx = LoggerContext.getContext(false); + LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger(); + assertEquals(Level.DEBUG, rootConfig.getLevel()); + } + + @Test + @DisplayName("Should set root logger level to TRACE from config") + void shouldSetRootLoggerLevelToTrace() { + Config customConfig = ConfigFactory.parseString(""" + ktestify { + logging { + root-level = "TRACE" + } + } + """); + + KtestifyConfig.load(customConfig); + + LoggerContext ctx = LoggerContext.getContext(false); + LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger(); + assertEquals(Level.TRACE, rootConfig.getLevel()); + } + + @Test + @DisplayName("Should set ktestify logger level from config") + void shouldSetKtestifyLoggerLevel() { + Config customConfig = ConfigFactory.parseString(""" + ktestify { + logging { + level = "TRACE" + } + } + """); + + KtestifyConfig.load(customConfig); + + LoggerContext ctx = LoggerContext.getContext(false); + LoggerConfig ktestifyConfig = ctx.getConfiguration().getLoggerConfig("io.github.ktestify"); + assertEquals(Level.TRACE, ktestifyConfig.getLevel()); + } + + @Test + @DisplayName("Should set kafka logger level from config") + void shouldSetKafkaLoggerLevel() { + Config customConfig = ConfigFactory.parseString(""" + ktestify { + logging { + kafka-level = "DEBUG" + } + } + """); + + KtestifyConfig.load(customConfig); + + LoggerContext ctx = LoggerContext.getContext(false); + LoggerConfig kafkaConfig = ctx.getConfiguration().getLoggerConfig("org.apache.kafka"); + assertEquals(Level.DEBUG, kafkaConfig.getLevel()); + } + } }