Created
February 15, 2026 13:09
-
-
Save VapidLinus/efaddd41c997ad29d5cbae7c4d41a80f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.hypixel.hytale.logger.backend; | |
| import com.google.common.flogger.backend.LogData; | |
| import com.google.common.flogger.backend.LoggerBackend; | |
| import com.google.common.flogger.backend.system.SimpleLogRecord; | |
| import com.hypixel.hytale.logger.sentry.HytaleSentryHandler; | |
| import com.hypixel.hytale.logger.sentry.SkipSentryException; | |
| import io.sentry.IScopes; | |
| import java.io.PrintStream; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Objects; | |
| import java.util.Map.Entry; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| import java.util.concurrent.CopyOnWriteArrayList; | |
| import java.util.function.BiConsumer; | |
| import java.util.function.Function; | |
| import java.util.logging.FileHandler; | |
| import java.util.logging.Level; | |
| import java.util.logging.LogRecord; | |
| import javax.annotation.Nonnull; | |
| import javax.annotation.Nullable; | |
| public class HytaleLoggerBackend extends LoggerBackend { | |
| public static Function<String, Level> LOG_LEVEL_LOADER; | |
| public static final PrintStream REAL_SOUT = System.out; | |
| public static final PrintStream REAL_SERR = System.err; | |
| private static final Map<String, HytaleLoggerBackend> CACHE = new ConcurrentHashMap<>(); | |
| private static final HytaleLoggerBackend ROOT_LOGGER = new HytaleLoggerBackend("Hytale", null); | |
| private static final int OFF_VALUE = Level.OFF.intValue(); | |
| private final String name; | |
| private final HytaleLoggerBackend parent; | |
| @Nonnull | |
| private Level level = Level.INFO; | |
| private BiConsumer<Level, Level> onLevelChange; | |
| @Nullable | |
| private HytaleSentryHandler sentryHandler; | |
| private boolean propagateSentryToParent = true; | |
| @Nonnull | |
| private CopyOnWriteArrayList<CopyOnWriteArrayList<LogRecord>> subscribers = new CopyOnWriteArrayList<>(); | |
| protected HytaleLoggerBackend(String name) { | |
| this.name = name; | |
| this.parent = ROOT_LOGGER; | |
| } | |
| protected HytaleLoggerBackend(String name, HytaleLoggerBackend parent) { | |
| this.name = name; | |
| this.parent = parent; | |
| } | |
| @Override | |
| public String getLoggerName() { | |
| return this.name; | |
| } | |
| @Nonnull | |
| public Level getLevel() { | |
| return this.level; | |
| } | |
| @Override | |
| public boolean isLoggable(@Nonnull Level lvl) { | |
| int levelValue = this.level.intValue(); | |
| return lvl.intValue() >= levelValue && levelValue != OFF_VALUE; | |
| } | |
| @Override | |
| public void log(@Nonnull LogData data) { | |
| this.log(SimpleLogRecord.create(data)); | |
| } | |
| @Override | |
| public void handleError(@Nonnull RuntimeException error, @Nonnull LogData badData) { | |
| this.log(SimpleLogRecord.error(error, badData)); | |
| } | |
| public void log(@Nonnull LogRecord logRecord) { | |
| this.log(logRecord, false); | |
| } | |
| public void log(@Nonnull LogRecord logRecord, boolean sentryHandled) { | |
| if (this.sentryHandler != null && !sentryHandled && logRecord.getThrown() != null && !SkipSentryException.hasSkipSentry(logRecord.getThrown())) { | |
| this.sentryHandler.publish(logRecord); | |
| sentryHandled = true; | |
| } | |
| if (!this.propagateSentryToParent && !sentryHandled && logRecord.getThrown() != null) { | |
| sentryHandled = true; | |
| } | |
| if (this.parent != null) { | |
| this.parent.log(logRecord, sentryHandled); | |
| } else { | |
| HytaleFileHandler.INSTANCE.log(logRecord); | |
| HytaleConsole.INSTANCE.publish(logRecord); | |
| for (int i = 0; i < this.subscribers.size(); i++) { | |
| this.subscribers.get(i).add(logRecord); | |
| } | |
| } | |
| } | |
| public static void subscribe(CopyOnWriteArrayList<LogRecord> subscriber) { | |
| if (!ROOT_LOGGER.subscribers.contains(subscriber)) { | |
| ROOT_LOGGER.subscribers.add(subscriber); | |
| } | |
| } | |
| public static void unsubscribe(CopyOnWriteArrayList<LogRecord> subscriber) { | |
| if (ROOT_LOGGER.subscribers.contains(subscriber)) { | |
| ROOT_LOGGER.subscribers.remove(subscriber); | |
| } | |
| } | |
| @Nonnull | |
| public HytaleLoggerBackend getSubLogger(String name) { | |
| HytaleLoggerBackend hytaleLoggerBackend = new HytaleLoggerBackend(this.name + "][" + name, this); | |
| hytaleLoggerBackend.loadLogLevel(); | |
| return hytaleLoggerBackend; | |
| } | |
| public void setSentryClient(@Nullable IScopes scope) { | |
| if (scope != null) { | |
| this.sentryHandler = new HytaleSentryHandler(scope); | |
| this.sentryHandler.setLevel(Level.ALL); | |
| } else { | |
| this.sentryHandler = null; | |
| } | |
| } | |
| public void setPropagatesSentryToParent(boolean propagate) { | |
| this.propagateSentryToParent = propagate; | |
| } | |
| public void setOnLevelChange(BiConsumer<Level, Level> onLevelChange) { | |
| this.onLevelChange = onLevelChange; | |
| } | |
| public void setLevel(@Nonnull Level newLevel) { | |
| Level old = this.level; | |
| this.level = newLevel; | |
| if (this.onLevelChange != null && !Objects.equals(old, newLevel)) { | |
| this.onLevelChange.accept(old, newLevel); | |
| } | |
| } | |
| public void loadLogLevel() { | |
| if (this.name != null && LOG_LEVEL_LOADER != null) { | |
| Level level = LOG_LEVEL_LOADER.apply(this.name); | |
| if (level != null) { | |
| this.setLevel(level); | |
| } | |
| } | |
| } | |
| public static void loadLevels(@Nonnull List<Entry<String, Level>> list) { | |
| for (Entry<String, Level> e : list) { | |
| getLogger(e.getKey()).setLevel(e.getValue()); | |
| } | |
| } | |
| public static void reloadLogLevels() { | |
| CACHE.values().forEach(HytaleLoggerBackend::loadLogLevel); | |
| } | |
| public static HytaleLoggerBackend getLogger() { | |
| return ROOT_LOGGER; | |
| } | |
| public static HytaleLoggerBackend getLogger(@Nonnull String name) { | |
| if (name.isEmpty()) { | |
| return getLogger(); | |
| } else { | |
| HytaleLoggerBackend logger = CACHE.computeIfAbsent(name, HytaleLoggerBackend::new); | |
| logger.loadLogLevel(); | |
| return logger; | |
| } | |
| } | |
| @Nonnull | |
| public static HytaleLoggerBackend getLogger(String name, BiConsumer<Level, Level> onLevelChange) { | |
| HytaleLoggerBackend logger = CACHE.computeIfAbsent(name, HytaleLoggerBackend::new); | |
| logger.setOnLevelChange(onLevelChange); | |
| logger.loadLogLevel(); | |
| return logger; | |
| } | |
| public static void setIndent(int indent) { | |
| HytaleConsole.INSTANCE.getFormatter().maxModuleName = indent; | |
| FileHandler fileHandler = HytaleFileHandler.INSTANCE.getFileHandler(); | |
| if (fileHandler != null) { | |
| ((HytaleLogFormatter)fileHandler.getFormatter()).maxModuleName = indent; | |
| } | |
| } | |
| public static boolean isJunitTest() { | |
| for (StackTraceElement element : Thread.currentThread().getStackTrace()) { | |
| if (element.getClassName().startsWith("org.junit.")) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| public static void rawLog(String message) { | |
| ROOT_LOGGER.log(new HytaleLoggerBackend.RawLogRecord(Level.ALL, message)); | |
| } | |
| public static class RawLogRecord extends LogRecord { | |
| public RawLogRecord(@Nonnull Level level, String msg) { | |
| super(level, msg); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment