146 lines
4.9 KiB
Java
146 lines
4.9 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.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<>();
|
|
|
|
/**
|
|
* Resets all known instances to use the default logger factory.
|
|
*/
|
|
public static void resetAllStrategies() {
|
|
for (HotswapLoggerFinder factory : KNOWN_INSTANCES) {
|
|
factory.resetStrategy();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
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) {
|
|
for (HotswapLoggerFinder f : KNOWN_INSTANCES) {
|
|
f.updateDefaultLevel(minimumLevel);
|
|
}
|
|
}
|
|
|
|
public HotswapLoggerFinder() {
|
|
KNOWN_INSTANCES.add(this);
|
|
}
|
|
|
|
private LeveledLoggerFinder defaultFactory = LeveledLoggerFinder.get(StdoutLogger::fancy);
|
|
private System.Logger.Level minimumLevel = System.Logger.Level.INFO;
|
|
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;
|
|
}
|
|
}
|
|
}
|