Fixed bug in Logging.java, added unittests for Logging.java in LoggingTest.java

This commit is contained in:
lieght
2025-09-20 17:15:22 +02:00
parent e4c1d2ef13
commit 16421c7163
2 changed files with 248 additions and 9 deletions

View File

@@ -6,8 +6,18 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.LoggerConfig;
/** Options for logging. */ /**
* Utility class for configuring logging levels dynamically at runtime using Log4j 2.
* <p>
* Provides methods to enable or disable logs globally or per class, with support for
* specifying log levels either via {@link Level} enums or string names.
* </p>
*/
public final class Logging { public final class Logging {
/**
* Disables all logging globally by setting the root logger level to {@link Level#OFF}.
*/
public static void disableAllLogs() { public static void disableAllLogs() {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration(); Configuration config = ctx.getConfiguration();
@@ -16,6 +26,22 @@ public final class Logging {
ctx.updateLoggers(); ctx.updateLoggers();
} }
/**
* Enables all logging globally by setting the root logger level to {@link Level#ALL}.
*/
public static void enableAllLogs() {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig rootLoggerConfig = config.getRootLogger();
rootLoggerConfig.setLevel(Level.ALL);
ctx.updateLoggers();
}
/**
* Enables global logging at a specific level by setting the root logger.
*
* @param level the logging level to enable for all logs
*/
public static void enableAllLogs(Level level) { public static void enableAllLogs(Level level) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration(); Configuration config = ctx.getConfiguration();
@@ -24,48 +50,157 @@ public final class Logging {
ctx.updateLoggers(); ctx.updateLoggers();
} }
public static <T> void disableLogsForClass(Class<T> class_) { /**
* Verifies whether the provided string corresponds to a valid class name.
*
* @param className fully-qualified class name to check
* @return true if the class exists, false otherwise
*/
private static boolean verifyStringIsActualClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
/**
* Internal helper to disable logs for a specific class by name.
*
* @param className fully-qualified class name
*/
private static void disableLogsForClassInternal(String className) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration(); Configuration config = ctx.getConfiguration();
LoggerConfig specificConfig = new LoggerConfig(class_.getName(), Level.OFF, true); config.removeLogger(className);
config.addLogger(class_.getName(), specificConfig); LoggerConfig specificConfig = new LoggerConfig(className, Level.OFF, false);
config.addLogger(className, specificConfig);
ctx.updateLoggers(); ctx.updateLoggers();
} }
public static <T> void enableLogsForClass(Class<T> class_, Level levelToLog) { /**
* Disables logs for a specific class.
*
* @param class_ the class for which logs should be disabled
* @param <T> type of the class
*/
public static <T> void disableLogsForClass(Class<T> class_) {
disableLogsForClassInternal(class_.getName());
}
/**
* Disables logs for a class specified by fully-qualified name, if the class exists.
*
* @param className fully-qualified class name
*/
public static void disableLogsForClass(String className) {
if (verifyStringIsActualClass(className)) {
disableLogsForClassInternal(className);
}
}
/**
* Internal helper to enable logs for a specific class at a specific level.
*
* @param className fully-qualified class name
* @param level logging level to set
*/
private static void enableLogsForClassInternal(String className, Level level) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration(); Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggers().get(class_.getName()); LoggerConfig loggerConfig = config.getLoggers().get(className);
if (loggerConfig == null) { if (loggerConfig == null) {
loggerConfig = new LoggerConfig(class_.getName(), levelToLog, true); loggerConfig = new LoggerConfig(className, level, false);
config.addLogger(class_.getName(), loggerConfig); config.addLogger(className, loggerConfig);
} else { } else {
loggerConfig.setLevel(levelToLog); loggerConfig.setLevel(level);
} }
ctx.updateLoggers(); ctx.updateLoggers();
} }
/**
* Enables logging for a class at a specific level.
*
* @param class_ class to configure
* @param levelToLog the logging level to set
* @param <T> type of the class
*/
public static <T> void enableLogsForClass(Class<T> class_, Level levelToLog) {
enableLogsForClassInternal(class_.getName(), levelToLog);
}
/**
* Enables logging for a class specified by name at a specific level, if the class exists.
*
* @param className fully-qualified class name
* @param levelToLog the logging level to set
*/
public static void enableLogsForClass(String className, Level levelToLog) {
if (verifyStringIsActualClass(className)) {
enableLogsForClassInternal(className, levelToLog);
}
}
/**
* Enables logging for a class specified by name at a specific level using a string.
*
* @param className fully-qualified class name
* @param levelToLog name of the logging level (e.g., "DEBUG", "INFO")
*/
public static void enableLogsForClass(String className, String levelToLog) {
Level level = Level.valueOf(levelToLog.trim().toUpperCase());
if (level != null && verifyStringIsActualClass(className)) {
enableLogsForClassInternal(className, level);
}
}
/** Convenience methods for enabling logs at specific levels for classes. */
public static <T> void enableAllLogsForClass(Class<T> class_) { public static <T> void enableAllLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.ALL); enableLogsForClass(class_, Level.ALL);
} }
public static void enableAllLogsForClass(String className) {
enableLogsForClass(className, Level.ALL);
}
public static <T> void enableDebugLogsForClass(Class<T> class_) { public static <T> void enableDebugLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.DEBUG); enableLogsForClass(class_, Level.DEBUG);
} }
public static void enableDebugLogsForClass(String className) {
enableLogsForClass(className, Level.DEBUG);
}
public static <T> void enableErrorLogsForClass(Class<T> class_) { public static <T> void enableErrorLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.ERROR); enableLogsForClass(class_, Level.ERROR);
} }
public static void enableErrorLogsForClass(String className) {
enableLogsForClass(className, Level.ERROR);
}
public static <T> void enableFatalLogsForClass(Class<T> class_) { public static <T> void enableFatalLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.FATAL); enableLogsForClass(class_, Level.FATAL);
} }
public static void enableFatalLogsForClass(String className) {
enableLogsForClass(className, Level.FATAL);
}
public static <T> void enableInfoLogsForClass(Class<T> class_) { public static <T> void enableInfoLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.INFO); enableLogsForClass(class_, Level.INFO);
} }
public static void enableInfoLogsForClass(String className) {
enableLogsForClass(className, Level.INFO);
}
public static <T> void enableTraceLogsForClass(Class<T> class_) { public static <T> void enableTraceLogsForClass(Class<T> class_) {
enableLogsForClass(class_, Level.TRACE); enableLogsForClass(class_, Level.TRACE);
} }
public static void enableTraceLogsForClass(String className) {
enableLogsForClass(className, Level.TRACE);
}
} }

View File

@@ -0,0 +1,104 @@
package org.toop;
import static org.junit.jupiter.api.Assertions.*;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class LoggingTest {
private LoggerContext ctx;
@BeforeEach
void setUp() {
ctx = (LoggerContext) LogManager.getContext(false);
Logging.enableAllLogs(Level.DEBUG); // reset root logger before each test
}
@AfterEach
void tearDown() {
Logging.enableAllLogs(Level.DEBUG); // restore root logger after each test
}
@Test
void testDisableAllLogs_setsRootLevelOff() {
Logging.disableAllLogs();
LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger();
assertEquals(Level.OFF, rootConfig.getLevel());
}
@Test
void testEnableAllLogs_setsRootLevelAll() {
Logging.enableAllLogs();
LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger();
assertEquals(Level.ALL, rootConfig.getLevel());
}
@Test
void testEnableAllLogs_LevelParam_setsRootLevel() {
Logging.enableAllLogs(Level.WARN);
LoggerConfig rootConfig = ctx.getConfiguration().getRootLogger();
assertEquals(Level.WARN, rootConfig.getLevel());
}
@Test
void testDisableLogsForClass_addsLoggerWithOff() {
Logging.disableLogsForClass(LoggingTest.class);
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get(LoggingTest.class.getName());
assertNotNull(loggerConfig);
assertEquals(Level.OFF, loggerConfig.getLevel());
}
@Test
void testEnableLogsForClass_addsLoggerWithLevel() {
Logging.enableLogsForClass(LoggingTest.class, Level.ERROR);
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get(LoggingTest.class.getName());
assertNotNull(loggerConfig);
assertEquals(Level.ERROR, loggerConfig.getLevel());
}
@Test
void testEnableLogsForClass_withStringLevel() {
Logging.enableLogsForClass(LoggingTest.class.getName(), "INFO");
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get(LoggingTest.class.getName());
assertNotNull(loggerConfig);
assertEquals(Level.INFO, loggerConfig.getLevel());
}
@Test
void testEnableDebugLogsForClass_setsDebug() {
Logging.enableDebugLogsForClass(LoggingTest.class);
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get(LoggingTest.class.getName());
assertNotNull(loggerConfig);
assertEquals(Level.DEBUG, loggerConfig.getLevel());
}
@Test
void testEnableInfoLogsForClass_setsInfo() {
Logging.enableInfoLogsForClass(LoggingTest.class);
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get(LoggingTest.class.getName());
assertNotNull(loggerConfig);
assertEquals(Level.INFO, loggerConfig.getLevel());
}
@Test
void testDisableLogsForNonexistentClass_doesNothing() {
Logging.disableLogsForClass("org.toop.DoesNotExist");
LoggerConfig loggerConfig = ctx.getConfiguration().getLoggers().get("org.toop.DoesNotExist");
assertNull(loggerConfig); // class doesn't exist, so no logger added
}
}