Skip to content

Commit

Permalink
Fix log levels not affecting loggers
Browse files Browse the repository at this point in the history
The current way of initializing loggers causes all loggers to
default to INFO level, even if a different level is specified
via the config.json or programmatically.

Let's create a logger named `ab3` to serve as the base logger, and
automatically prefix all loggers created using LogCenter#getLogger(...)
with `ab3.` so that they all become descendants of the base logger. This
allows us to change the logging level of all loggers simply by changing
the logging level of the base logger (unless those loggers have
specified their own logging level).

Implications: Loggers not created using the LogCenter#getLogger(...)
methods will not come under the above control mechanism unless
their name starts with `ab3.`.
  • Loading branch information
Eclipse-Dominator committed Jun 17, 2023
1 parent 9356ae9 commit 8775e85
Showing 1 changed file with 40 additions and 51 deletions.
91 changes: 40 additions & 51 deletions src/main/java/seedu/address/commons/core/LogsCenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,32 @@ public class LogsCenter {
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
private static final String LOG_FILE = "addressbook.log";
private static Level currentLogLevel = Level.INFO;
private static final Logger baseLogger = LogsCenter.getBaseLogger();
private static final Logger logger = LogsCenter.getLogger(LogsCenter.class);
private static FileHandler fileHandler;
private static ConsoleHandler consoleHandler;

/**
* Initializes with a custom log level (specified in the {@code config} object)
* Loggers obtained *AFTER* this initialization will have their logging level changed<br>
* Logging levels for existing loggers will only be updated if the logger with the same name
* is requested again from the LogsCenter.
* Initializes loggers with the log level specified in the {@code config} object. Applies to all loggers created
* using {@link #getLogger(String)} and {@link #getLogger(Class)} methods except for those that are manually set.
*/
public static void init(Config config) {
currentLogLevel = config.getLogLevel();
logger.info("currentLogLevel: " + currentLogLevel);
logger.info("log level set as: " + currentLogLevel);
// set the level of the baseLogger which will be inherited by other loggers
baseLogger.setLevel(currentLogLevel);
}

/**
* Creates a logger with the given name.
*/
public static Logger getLogger(String name) {
Logger logger = Logger.getLogger(name);
logger.setUseParentHandlers(false);

// Java organizes loggers into a hierarchy based on their names (using '.' as a separator, similar to how Java
// packages form a hierarchy). Furthermore, loggers without a level inherit the level of their parent logger.
// By prefixing names of all loggers with baseLogger's name + ".", we make the baseLogger the parent of all
// loggers. This allows us to change the level of all loggers simply by changing the baseLogger level.
Logger logger = Logger.getLogger(baseLogger.getName() + "." + name);
removeHandlers(logger);
addConsoleHandler(logger);
addFileHandler(logger);

return Logger.getLogger(name);
logger.setUseParentHandlers(true);
return logger;
}

/**
Expand All @@ -60,53 +59,43 @@ public static <T> Logger getLogger(Class<T> clazz) {
}

/**
* Adds the {@code consoleHandler} to the {@code logger}. <br>
* Creates the {@code consoleHandler} if it is null.
* Creates and returns a base logger with the default configuration and containing a {@code ConsoleHandler}
* and a {@code FileHandler}.
* The base logger is the parent of all other loggers. Changing the level of the base logger will change
* the level of all other loggers if they are untweaked. Similarly, all loggers created from this class will
* inherit the handlers of the base logger.
*/
private static void addConsoleHandler(Logger logger) {
if (consoleHandler == null) {
consoleHandler = createConsoleHandler();
}
logger.addHandler(consoleHandler);
}
private static Logger getBaseLogger() {
Logger baseLogger = Logger.getLogger("ab3");
baseLogger.setUseParentHandlers(false);
removeHandlers(baseLogger);

/**
* Remove all the handlers from {@code logger}.
*/
private static void removeHandlers(Logger logger) {
Arrays.stream(logger.getHandlers())
.forEach(logger::removeHandler);
}
// Level.ALL is used because loggers filter the log messages by level already,
// there is no need to control log message level of the handlers.

/**
* Adds the {@code fileHandler} to the {@code logger}. <br>
* Creates {@code fileHandler} if it is null.
*/
private static void addFileHandler(Logger logger) {
// add a ConsoleHandler to log to the console
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
baseLogger.addHandler(consoleHandler);

// add a FileHandler to log to a file
try {
if (fileHandler == null) {
fileHandler = createFileHandler();
}
logger.addHandler(fileHandler);
FileHandler fileHandler = new FileHandler(LOG_FILE, MAX_FILE_SIZE_IN_BYTES, MAX_FILE_COUNT, true);
fileHandler.setFormatter(new SimpleFormatter());
fileHandler.setLevel(Level.ALL);
baseLogger.addHandler(fileHandler);
} catch (IOException e) {
logger.warning("Error adding file handler for logger.");
}

return baseLogger;
}

/**
* Creates a {@code FileHandler} for the log file.
* @throws IOException if there are problems opening the file.
* Removes all handlers from the {@code logger}.
*/
private static FileHandler createFileHandler() throws IOException {
FileHandler fileHandler = new FileHandler(LOG_FILE, MAX_FILE_SIZE_IN_BYTES, MAX_FILE_COUNT, true);
fileHandler.setFormatter(new SimpleFormatter());
fileHandler.setLevel(currentLogLevel);
return fileHandler;
}

private static ConsoleHandler createConsoleHandler() {
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(currentLogLevel);
return consoleHandler;
private static void removeHandlers(Logger logger) {
Arrays.stream(logger.getHandlers())
.forEach(logger::removeHandler);
}
}

0 comments on commit 8775e85

Please sign in to comment.