diff --git a/src/main/java/org/toop/Logging.java b/src/main/java/org/toop/Logging.java index f60c6d1..2810016 100644 --- a/src/main/java/org/toop/Logging.java +++ b/src/main/java/org/toop/Logging.java @@ -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.LoggerConfig; -/** Options for logging. */ +/** + * Utility class for configuring logging levels dynamically at runtime using Log4j 2. + *

+ * 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. + *

+ */ public final class Logging { + + /** + * Disables all logging globally by setting the root logger level to {@link Level#OFF}. + */ public static void disableAllLogs() { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); @@ -16,6 +26,22 @@ public final class Logging { 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) { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); @@ -24,48 +50,157 @@ public final class Logging { ctx.updateLoggers(); } - public static void disableLogsForClass(Class 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); Configuration config = ctx.getConfiguration(); - LoggerConfig specificConfig = new LoggerConfig(class_.getName(), Level.OFF, true); - config.addLogger(class_.getName(), specificConfig); + config.removeLogger(className); + LoggerConfig specificConfig = new LoggerConfig(className, Level.OFF, false); + config.addLogger(className, specificConfig); ctx.updateLoggers(); } - public static void enableLogsForClass(Class class_, Level levelToLog) { + /** + * Disables logs for a specific class. + * + * @param class_ the class for which logs should be disabled + * @param type of the class + */ + public static void disableLogsForClass(Class 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); Configuration config = ctx.getConfiguration(); - LoggerConfig loggerConfig = config.getLoggers().get(class_.getName()); + LoggerConfig loggerConfig = config.getLoggers().get(className); if (loggerConfig == null) { - loggerConfig = new LoggerConfig(class_.getName(), levelToLog, true); - config.addLogger(class_.getName(), loggerConfig); + loggerConfig = new LoggerConfig(className, level, false); + config.addLogger(className, loggerConfig); } else { - loggerConfig.setLevel(levelToLog); + loggerConfig.setLevel(level); } ctx.updateLoggers(); } + /** + * Enables logging for a class at a specific level. + * + * @param class_ class to configure + * @param levelToLog the logging level to set + * @param type of the class + */ + public static void enableLogsForClass(Class 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 void enableAllLogsForClass(Class class_) { enableLogsForClass(class_, Level.ALL); } + public static void enableAllLogsForClass(String className) { + enableLogsForClass(className, Level.ALL); + } + public static void enableDebugLogsForClass(Class class_) { enableLogsForClass(class_, Level.DEBUG); } + public static void enableDebugLogsForClass(String className) { + enableLogsForClass(className, Level.DEBUG); + } + public static void enableErrorLogsForClass(Class class_) { enableLogsForClass(class_, Level.ERROR); } + public static void enableErrorLogsForClass(String className) { + enableLogsForClass(className, Level.ERROR); + } + public static void enableFatalLogsForClass(Class class_) { enableLogsForClass(class_, Level.FATAL); } + public static void enableFatalLogsForClass(String className) { + enableLogsForClass(className, Level.FATAL); + } + public static void enableInfoLogsForClass(Class class_) { enableLogsForClass(class_, Level.INFO); } + public static void enableInfoLogsForClass(String className) { + enableLogsForClass(className, Level.INFO); + } + public static void enableTraceLogsForClass(Class class_) { enableLogsForClass(class_, Level.TRACE); } + + public static void enableTraceLogsForClass(String className) { + enableLogsForClass(className, Level.TRACE); + } } diff --git a/src/test/java/org/toop/LoggingTest.java b/src/test/java/org/toop/LoggingTest.java new file mode 100644 index 0000000..dda0202 --- /dev/null +++ b/src/test/java/org/toop/LoggingTest.java @@ -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 + } +} \ No newline at end of file