From c98c713da8c2cc66c477872ea44dcd4fa59d5371 Mon Sep 17 00:00:00 2001 From: JFronny Date: Fri, 15 Mar 2024 11:54:41 +0100 Subject: [PATCH] chore: add comments explaining the logging system --- .../src/main/java/io/gitlab/jfronny/libjf/LibJf.java | 11 +++++++++++ .../io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java | 3 +++ 2 files changed, 14 insertions(+) diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java index b2f7228..094be49 100644 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java @@ -30,6 +30,10 @@ public class LibJf implements PreLaunchEntrypoint { bootstrap(); if (!setup) { setup = true; + // Sometimes a mod using LibJF may want to log before game libraries are initialized. + // For that case, an implementation of System.Logger that redirects to Fabric Loader's logger is used at startup. + // After the game is initialized though, that becomes unnecessary, and we can switch to using SLF4J directly. + // The setup method is called after the game is initialized, so this is the perfect place to do this. HotswapLoggerFinder.updateAllStrategies((name, module, level) -> new SLF4JPlatformLogger(LoggerFactory.getLogger(name))); } } @@ -37,9 +41,16 @@ public class LibJf implements PreLaunchEntrypoint { public static void bootstrap() { if (!bootstrapped) { bootstrapped = true; + // I use System.Logger for logging. + // LibJF ships a service loaded in System.LoggerFinder, which delegates to Fabric Loader and (later on) SLF4J (after setup). if (LOGGER instanceof DelegateLogger) { + // If the ServiceLoader was able to find this service, any Logger generated will be a DelegateLogger since that class is used by the HotswapLoggerFinder. + // This means that redirection to SLF4J is already set up and we don't need to do anything. LOGGER.debug("HotswapLoggerFinder was loaded successfully. No need to install JULBridge."); } else { + // If Fabric Loader is run in production, the ServiceLoader may not pick up this implementation quickly enough. + // In that case, the JUL backend is selected and this cannot be changed, so we need to redirect logs from JUL instead. + // The JULBridge does exactly that by redirecting JUL logs to loggers created by its own instance of EarlyLoggerSetup. JULBridge.install(); LOGGER.debug("JULBridge was installed. If available in your launcher, please enable the ServiceLoader fix for better performance."); } diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java index 1a05e0b..f5a94f9 100644 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java @@ -7,6 +7,9 @@ import org.jetbrains.annotations.Nullable; public class EarlyLoggerSetup extends LeveledLoggerFinder { static { + // When a logger is used before the game is initialized, SLF4J is not yet available. + // To support that, this implementation which redirects to Fabric Loader's internal logging abstraction is used instead. + // After the game is initialized, something calls LibJF.setup (usually preEntry), which replaces this factory with a SLF4J-based one. HotswapLoggerFinder.updateAllStrategies((name, module, level) -> new LoaderPlatformLogger(name)); }