RainbowGumSystemLogger.java
package io.jstach.rainbowgum.systemlogger;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import io.jstach.rainbowgum.LogEvent;
import io.jstach.rainbowgum.LogRouter;
/**
* Rainbow Gum System Logger implementation. As noted in the module doc this can be used
* by others without worry of it registering a {@link System.LoggerFinder}.
*
* @apiNote This class is final and cannot be extended. If you think it would be useful to
* extend file an issue.
*/
public final class RainbowGumSystemLogger implements System.Logger {
private final String loggerName;
private final LogRouter router;
private final SystemLoggerEventFactory eventFactory;
/**
* Provides a system logger that will use the given root router.
* @param loggerName standard dotted logger name.
* @param router root router usually the global.
* @return un-cached system logger.
*/
public static RainbowGumSystemLogger of(String loggerName, LogRouter router) {
return new RainbowGumSystemLogger(loggerName, router);
}
RainbowGumSystemLogger(String loggerName, LogRouter router) {
super();
this.loggerName = loggerName;
this.router = router;
this.eventFactory = new SystemLoggerEventFactory(loggerName);
}
private LogEvent event(Level level, @Nullable String formattedMessage, @Nullable Throwable throwable) {
return eventFactory.eventNoArg(level, formattedMessage, throwable);
}
@Override
public String getName() {
return this.loggerName;
}
@Override
public boolean isLoggable(Level level) {
return router.route(loggerName, SystemLoggerEventFactory.fixLevel(level)).isEnabled();
}
@Override
public void log(Level level, @Nullable String msg) {
this._log(level, msg, (Throwable) null);
}
/*
* java.lang.System.Logger#log(Level, Supplier<String>) declares Supplier<String>, not
* Supplier<@Nullable String>, but like the single-String log(Level, String) overload
* right above, a supplier returning null is treated the same as no message - accepted
* wider than the JDK's own unannotated interface requires, same reasoning as
* rainbowgum-slf4j's MDCAdapter/LoggingEventBuilder astubs.
*/
@SuppressWarnings({ "exports", "NullAway" })
@Override
public void log(Level level, Supplier<@Nullable String> msgSupplier) {
this._log(level, msgSupplier, (Throwable) null);
}
@Override
public void log(Level level, Object obj) {
Objects.requireNonNull(obj, "obj");
level = SystemLoggerEventFactory.fixLevel(level);
var route = router.route(loggerName, level);
if (route.isEnabled()) {
String formattedMessage = obj == null ? "" : obj.toString();
LogEvent event = event(level, formattedMessage, null);
route.log(event);
}
}
@Override
public void log(Level level, @Nullable String msg, @Nullable Throwable throwable) {
this._log(level, msg, throwable);
}
// To keep call depth consistent
private void _log(Level level, @Nullable String msg, @Nullable Throwable throwable) {
level = SystemLoggerEventFactory.fixLevel(level);
var route = router.route(loggerName, level);
if (route.isEnabled()) {
LogEvent event = event(level, msg, throwable);
route.log(event);
}
}
@SuppressWarnings({ "exports", "NullAway" })
@Override
public void log(Level level, Supplier<@Nullable String> msgSupplier, @Nullable Throwable throwable) {
this._log(level, msgSupplier, throwable);
}
// To keep call depth consistent
private void _log(Level level, Supplier<@Nullable String> msgSupplier, @Nullable Throwable throwable) {
level = SystemLoggerEventFactory.fixLevel(level);
var route = router.route(loggerName, level);
if (route.isEnabled()) {
String formattedMessage = msgSupplier.get();
LogEvent event = event(level, formattedMessage, throwable);
route.log(event);
}
}
@Override
public void log(Level level, @Nullable ResourceBundle bundle, @Nullable String msg, @Nullable Throwable throwable) {
_log(level, bundle, msg, throwable);
}
private void _log(Level level, @Nullable ResourceBundle bundle, @Nullable String msg,
@Nullable Throwable throwable) {
level = SystemLoggerEventFactory.fixLevel(level);
var route = router.route(loggerName, level);
if (route.isEnabled()) {
String formattedMessage = eventFactory.message(bundle, msg);
LogEvent event = event(level, formattedMessage, throwable);
route.log(event);
}
}
@Override
public void log(Level level, @Nullable ResourceBundle bundle, @Nullable String format, @Nullable Object... args) {
this._log(level, bundle, format, args);
}
// To keep call depth consistent.
private void _log(Level level, @Nullable ResourceBundle bundle, @Nullable String format, @Nullable Object... args) {
level = SystemLoggerEventFactory.fixLevel(level);
var route = router.route(loggerName, level);
if (route.isEnabled()) {
String message = eventFactory.message(bundle, format);
LogEvent event = eventFactory.eventArgs(level, message, args);
route.log(event);
}
}
}