158 lines
5.4 KiB
Java
158 lines
5.4 KiB
Java
package io.gitlab.jfronny.commons.logger;
|
|
|
|
import io.gitlab.jfronny.commons.ref.WeakSet;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.Objects;
|
|
import java.util.ServiceLoader;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* A logger factory that allows apps to swap the backing factory at runtime, automatically updating all created loggers.
|
|
*/
|
|
public class HotswapLoggerFinder extends LeveledLoggerFinder {
|
|
private static final Set<HotswapLoggerFinder> KNOWN_INSTANCES = new WeakSet<>();
|
|
private static LeveledLoggerFinder DEFAULT_FACTORY = LeveledLoggerFinder.get(StdoutLogger::fancy);
|
|
private static System.Logger.Level DEFAULT_LEVEL = System.Logger.Level.INFO;
|
|
|
|
/**
|
|
* Resets all known instances to use the default logger factory.
|
|
*/
|
|
public static void resetAllStrategies() {
|
|
updateAllStrategies(StdoutLogger::fancy);
|
|
}
|
|
|
|
/**
|
|
* Updates all known instances to use the new logger factory.
|
|
* @param factory the new logger factory to use for all known instances
|
|
*/
|
|
public static void updateAllStrategies(System.LoggerFinder factory) {
|
|
updateAllStrategies(LeveledLoggerFinder.get(factory));
|
|
}
|
|
|
|
public static void updateAllStrategies(LeveledLoggerFinder.Simple factory) {
|
|
updateAllStrategies(LeveledLoggerFinder.get(factory));
|
|
}
|
|
|
|
/**
|
|
* Updates all known instances to use the new logger factory.
|
|
* @param factory the new logger factory to use for all known instances
|
|
*/
|
|
public static void updateAllStrategies(LeveledLoggerFinder factory) {
|
|
DEFAULT_FACTORY = Objects.requireNonNull(factory);
|
|
for (HotswapLoggerFinder f : KNOWN_INSTANCES) {
|
|
f.updateStrategy(factory);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates all known instances to use the new minimum log level if supported.
|
|
* @param minimumLevel the new minimum level to use for all known instances
|
|
*/
|
|
public static void updateAllDefaultLevels(System.Logger.Level minimumLevel) {
|
|
DEFAULT_LEVEL = Objects.requireNonNull(minimumLevel);
|
|
for (HotswapLoggerFinder f : KNOWN_INSTANCES) {
|
|
f.updateDefaultLevel(minimumLevel);
|
|
}
|
|
}
|
|
|
|
static {
|
|
try {
|
|
ServiceLoader.load(LoggerConfiguration.class).forEach(LoggerConfiguration::configure);
|
|
} catch (Throwable t) {
|
|
System.err.println("Could not initialize LoggerConfiguration");
|
|
t.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public HotswapLoggerFinder() {
|
|
KNOWN_INSTANCES.add(this);
|
|
}
|
|
|
|
private LeveledLoggerFinder defaultFactory = DEFAULT_FACTORY;
|
|
private System.Logger.Level minimumLevel = DEFAULT_LEVEL;
|
|
private int version = 0;
|
|
|
|
/**
|
|
* Resets the strategy to use the default logger factory.
|
|
*/
|
|
public void resetStrategy() {
|
|
updateStrategy(StdoutLogger::fancy);
|
|
}
|
|
|
|
/**
|
|
* Updates the strategy to use the new logger factory.
|
|
* @param factory the new logger factory to use
|
|
*/
|
|
public void updateStrategy(System.LoggerFinder factory) {
|
|
if (factory instanceof LeveledLoggerFinder f) {
|
|
updateStrategy(f);
|
|
} else {
|
|
updateStrategy(LeveledLoggerFinder.get(factory));
|
|
}
|
|
}
|
|
|
|
public void updateStrategy(LeveledLoggerFinder.Simple factory) {
|
|
updateStrategy(LeveledLoggerFinder.get(factory));
|
|
}
|
|
|
|
/**
|
|
* Updates the strategy to use the new logger factory.
|
|
* @param factory the new logger factory to use
|
|
*/
|
|
public void updateStrategy(LeveledLoggerFinder factory) {
|
|
synchronized (this) {
|
|
defaultFactory = Objects.requireNonNull(factory);
|
|
version++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the minimum log level to use if supported.
|
|
* @param minimumLevel the new minimum level to use if supported
|
|
*/
|
|
public void updateDefaultLevel(System.Logger.Level minimumLevel) {
|
|
synchronized (this) {
|
|
this.minimumLevel = Objects.requireNonNull(minimumLevel);
|
|
version++;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public SystemLoggerPlus getLogger(String name, Module module, @Nullable System.Logger.Level level) {
|
|
return new SwappableDelegateLogger(name, module, level);
|
|
}
|
|
|
|
private class SwappableDelegateLogger extends DelegateLogger {
|
|
private final String name;
|
|
private final Module module;
|
|
private final boolean keepLevel;
|
|
private Level lastMinimumLevel;
|
|
private System.Logger delegate;
|
|
int version = -1;
|
|
|
|
private SwappableDelegateLogger(String name, Module module, @Nullable Level level) {
|
|
this.name = name == null ? "null" : name;
|
|
this.module = module;
|
|
this.keepLevel = level != null;
|
|
this.lastMinimumLevel = level == null ? HotswapLoggerFinder.this.minimumLevel : level;
|
|
updateStrategy();
|
|
}
|
|
|
|
public void updateStrategy() {
|
|
if (this.version == HotswapLoggerFinder.this.version) return;
|
|
synchronized (HotswapLoggerFinder.this) {
|
|
this.version = HotswapLoggerFinder.this.version;
|
|
if (!keepLevel) this.lastMinimumLevel = HotswapLoggerFinder.this.minimumLevel;
|
|
this.delegate = HotswapLoggerFinder.this.defaultFactory.getLogger(this.name, module, this.lastMinimumLevel);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected System.Logger getDelegate() {
|
|
updateStrategy();
|
|
return delegate;
|
|
}
|
|
}
|
|
}
|