Write DiscordSRV log messages to a file for debugging

This commit is contained in:
Vankka 2022-01-24 18:55:36 +02:00
parent 9f7a453132
commit 67e25a765a
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
33 changed files with 321 additions and 140 deletions

View File

@ -47,17 +47,12 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap {
@Override
public void onEnable() {
// Wait until dependencies ready, then initialize DiscordSRV
dependencies.join();
this.discordSRV = new BukkitDiscordSRV(this, logger);
dependencies.runWhenComplete(() -> discordSRV.invokeEnable());
getPlugin().getServer().getScheduler().runTaskLater(getPlugin(),
() -> dependencies.runWhenComplete(() -> discordSRV.invokeServerStarted()), 1L);
dependencies.loadAndEnable(() -> this.discordSRV = new BukkitDiscordSRV(this, logger));
getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), () -> discordSRV.invokeServerStarted(), 1L);
}
@Override
public void onDisable() {
dependencies.runWhenComplete(() -> discordSRV.invokeDisable());
dependencies.disable(discordSRV);
}
}

View File

@ -20,6 +20,7 @@ package com.discordsrv.bukkit.console;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
@ -43,7 +44,7 @@ public class BukkitConsole implements Console {
} catch (ClassNotFoundException ignored) {
// Log4j with Filter has been in the vanilla server since Minecraft 1.7,
// this is mostly for Bukkit servers that don't use the vanilla server software
discordSRV.logger().debug("Not using Log4j for advanced console features");
new NamedLogger(discordSRV, "CONSOLE").debug("Not using Log4j for advanced console features");
logging = JavaLoggerImpl.getRoot();
}
this.loggingBackend = logging;

View File

@ -25,8 +25,8 @@ import com.discordsrv.common.config.main.MainConfig;
import com.discordsrv.common.config.manager.ConnectionConfigManager;
import com.discordsrv.common.config.manager.MainConfigManager;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.proxy.ProxyDiscordSRV;
import com.discordsrv.common.scheduler.StandardScheduler;
import com.discordsrv.proxy.ProxyDiscordSRV;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;

View File

@ -47,15 +47,11 @@ public class DiscordSRVBungeeBootstrap extends BungeeBootstrap {
@Override
public void onEnable() {
// Wait until dependencies ready, then initialize DiscordSRV
dependencies.join();
this.discordSRV = new BungeeDiscordSRV(this, logger);
dependencies.runWhenComplete(discordSRV::invokeEnable);
dependencies.loadAndEnable(() -> this.discordSRV = new BungeeDiscordSRV(this, logger));
}
@Override
public void onDisable() {
dependencies.runWhenComplete(discordSRV::invokeDisable);
dependencies.disable(discordSRV);
}
}

View File

@ -27,6 +27,7 @@ import com.discordsrv.api.event.events.message.receive.game.ServerSwitchMessageR
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
import com.discordsrv.proxy.config.channels.ServerSwitchMessageConfig;
import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
@ -34,7 +35,7 @@ import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
public class ServerSwitchMessageModule extends AbstractGameMessageModule<ServerSwitchMessageConfig> {
public ServerSwitchMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "SERVER_SWITCH"));
}
@Subscribe(priority = EventPriority.LAST)

View File

@ -26,15 +26,16 @@ import com.discordsrv.api.event.events.message.forward.game.DeathMessageForwarde
import com.discordsrv.api.event.events.message.receive.game.DeathMessageReceiveEvent;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.server.config.channels.DeathMessageConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
import com.discordsrv.common.server.config.channels.DeathMessageConfig;
import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig;
public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageConfig> {
public DeathMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "DEATH"));
}
@Subscribe(priority = EventPriority.LAST)

View File

@ -23,6 +23,7 @@ import com.discordsrv.api.event.bus.EventBus;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadEvent;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent;
import com.discordsrv.api.linking.LinkingBackend;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.common.api.util.ApiInstanceUtil;
import com.discordsrv.common.channel.ChannelConfigHelper;
import com.discordsrv.common.channel.ChannelUpdaterModule;
@ -42,7 +43,6 @@ import com.discordsrv.common.function.CheckedFunction;
import com.discordsrv.common.function.CheckedRunnable;
import com.discordsrv.common.groupsync.GroupSyncModule;
import com.discordsrv.common.integration.LuckPermsIntegration;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.adapter.DependencyLoggerAdapter;
import com.discordsrv.common.logging.impl.DependencyLoggingHandler;
import com.discordsrv.common.logging.impl.DiscordSRVLogger;
@ -52,7 +52,6 @@ import com.discordsrv.common.messageforwarding.game.JoinMessageModule;
import com.discordsrv.common.messageforwarding.game.LeaveMessageModule;
import com.discordsrv.common.module.ModuleManager;
import com.discordsrv.common.module.type.AbstractModule;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.common.placeholder.ComponentResultStringifier;
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
import com.discordsrv.common.placeholder.context.GlobalTextHandlingContext;
@ -85,8 +84,8 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
private DiscordConnectionDetails discordConnectionDetails;
// DiscordSRV
private final DiscordSRVLogger logger;
private final ModuleManager moduleManager;
private DiscordSRVLogger logger;
private ModuleManager moduleManager;
private ChannelConfigHelper channelConfig;
private DiscordConnectionManager discordConnectionManager;
@ -95,11 +94,14 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
public AbstractDiscordSRV() {
ApiInstanceUtil.setInstance(this);
this.logger = new DiscordSRVLogger(this);
this.moduleManager = new ModuleManager(this);
}
/**
* Method that should be called at the end of implementors constructors.
*/
protected final void load() {
this.logger = new DiscordSRVLogger(this);
this.moduleManager = new ModuleManager(this);
this.eventBus = new EventBusImpl(this);
this.placeholderService = new PlaceholderServiceImpl(this);
this.componentFactory = new ComponentFactory(this);
@ -153,7 +155,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
// DiscordSRV
@Override
public Logger logger() {
public DiscordSRVLogger logger() {
return logger;
}
@ -184,6 +186,8 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
return configManager().config();
}
// Module
@Override
public <T extends Module> T getModule(Class<T> moduleType) {
return moduleManager.getModule(moduleType);
@ -212,6 +216,8 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
return Locale.getDefault();
}
// Status
@Override
public void setStatus(Status status) {
synchronized (this.status) {
@ -239,6 +245,8 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
}
}
// Lifecycle
protected CompletableFuture<Void> invokeLifecycle(CheckedRunnable runnable, String message, boolean enable) {
return invoke(() -> {
try {

View File

@ -28,6 +28,7 @@ import com.discordsrv.common.config.manager.MainConfigManager;
import com.discordsrv.common.console.Console;
import com.discordsrv.common.discord.api.DiscordAPIImpl;
import com.discordsrv.common.discord.connection.DiscordConnectionManager;
import com.discordsrv.common.logging.impl.DiscordSRVLogger;
import com.discordsrv.common.module.type.AbstractModule;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
@ -71,7 +72,7 @@ public interface DiscordSRV extends DiscordSRVApi {
DiscordAPIImpl discordAPI();
// Logger
Logger logger();
DiscordSRVLogger logger();
// Config
ConnectionConfigManager<? extends ConnectionConfig> connectionConfigManager();

View File

@ -20,6 +20,7 @@ package com.discordsrv.common.channel;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.ChannelUpdaterConfig;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.GuildChannel;
@ -39,7 +40,7 @@ public class ChannelUpdaterModule extends AbstractModule<DiscordSRV> {
private boolean firstReload = true;
public ChannelUpdaterModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "CHANNEL_UPDATER"));
}
@Override
@ -100,7 +101,7 @@ public class ChannelUpdaterModule extends AbstractModule<DiscordSRV> {
}
if (!anythingChanged) {
discordSRV.logger().debug("Skipping updating channel " + channel + ": nothing changed");
logger().debug("Skipping updating channel " + channel + ": nothing changed");
continue;
}

View File

@ -35,11 +35,11 @@ public class GlobalChannelLookupModule extends AbstractModule<DiscordSRV> {
@Subscribe(priority = EventPriority.LATE)
public void onGameChannelLookup(GameChannelLookupEvent event) {
if (checkProcessor(event)) {
return;
}
if (event.getChannelName().equalsIgnoreCase("global")) {
if (checkProcessor(event)) {
return;
}
event.process(defaultGlobalChannel);
}
}

View File

@ -18,6 +18,7 @@
package com.discordsrv.common.dependency;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.scheduler.threadfactory.CountingForkJoinWorkerThreadFactory;
import dev.vankka.dependencydownload.classpath.ClasspathAppender;
@ -28,15 +29,14 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.*;
import java.util.function.Supplier;
public class InitialDependencyLoader {
private final Logger logger;
private final ForkJoinPool taskPool;
private final CompletableFuture<?> completableFuture;
private final List<Runnable> tasks = new CopyOnWriteArrayList<>();
public InitialDependencyLoader(
Logger logger,
@ -44,6 +44,7 @@ public class InitialDependencyLoader {
String[] dependencyResources,
ClasspathAppender classpathAppender
) throws IOException {
this.logger = logger;
this.taskPool = new ForkJoinPool(
Runtime.getRuntime().availableProcessors(),
new CountingForkJoinWorkerThreadFactory("DiscordSRV Initialization #%s"),
@ -63,40 +64,51 @@ public class InitialDependencyLoader {
);
this.completableFuture = dependencyLoader.process(classpathAppender);
completableFuture.whenComplete((v, t) -> {
if (t != null) {
logger.error("Error loading dependencies", t);
return;
}
for (Runnable task : tasks) {
try {
task.run();
} catch (Throwable throwable) {
logger.error("Callback failed", throwable);
}
}
taskPool.shutdown();
});
completableFuture.whenComplete((v, t) -> taskPool.shutdown());
}
/**
* Joins the dependency download.
*/
public void join() {
completableFuture.join();
public void loadAndEnable(Supplier<DiscordSRV> discordSRVSupplier) {
load();
enable(discordSRVSupplier);
}
/**
* This will run on the current thread if dependencies are already downloaded, otherwise will be added to a list.
*/
public void runWhenComplete(Runnable runnable) {
if (completableFuture.isDone()) {
runnable.run();
public void load() {
try {
completableFuture.get();
} catch (ExecutionException | InterruptedException e) {
logger.error("Failed to download dependencies", e);
}
}
public void enable(Supplier<DiscordSRV> discordSRVSupplier) {
if (!completableFuture.isDone()) {
return;
}
discordSRVSupplier.get().invokeEnable();
}
public void reload(DiscordSRV discordSRV) {
if (discordSRV == null) {
return;
}
discordSRV.invokeReload();
}
public void disable(DiscordSRV discordSRV) {
if (!completableFuture.isDone()) {
completableFuture.cancel(true);
return;
}
tasks.add(runnable);
if (discordSRV == null) {
return;
}
try {
discordSRV.invokeDisable().get(15, TimeUnit.SECONDS);
} catch (InterruptedException | TimeoutException e) {
logger.warning("Timed out/interrupted shutting down DiscordSRV");
} catch (ExecutionException ignored) {}
}
}

View File

@ -27,14 +27,16 @@ import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.connection.ConnectionConfig;
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
import com.discordsrv.common.discord.api.entity.channel.DiscordDMChannelImpl;
import com.discordsrv.common.discord.api.entity.channel.DiscordTextChannelImpl;
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildImpl;
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildMemberImpl;
import com.discordsrv.common.discord.api.entity.guild.DiscordRoleImpl;
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl;
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
import com.discordsrv.common.discord.connection.DiscordConnectionManager;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.scheduler.Scheduler;
import com.discordsrv.common.scheduler.threadfactory.CountingThreadFactory;
import com.discordsrv.common.time.util.Timeout;
@ -102,7 +104,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
);
// Set default failure handling
RestAction.setDefaultFailure(new DefaultFailureCallback());
RestAction.setDefaultFailure(new DefaultFailureCallback(new NamedLogger(discordSRV, "DISCORD_REQUESTS")));
// Disable all mentions by default for safety
AllowedMentions.setDefaultMentions(Collections.emptyList());
@ -437,6 +439,12 @@ public class JDAConnectionManager implements DiscordConnectionManager {
private class DefaultFailureCallback implements Consumer<Throwable> {
private final Logger logger;
protected DefaultFailureCallback(Logger logger) {
this.logger = logger;
}
@Override
public void accept(Throwable t) {
if ((t instanceof InterruptedIOException || t instanceof InterruptedException)
@ -448,13 +456,13 @@ public class JDAConnectionManager implements DiscordConnectionManager {
boolean cancelled;
if ((cancelled = t instanceof CancellationException) || t instanceof TimeoutException) {
// Cancelling/timing out requests is always intentional
discordSRV.logger().debug("A request " + (cancelled ? "was cancelled" : "timed out"), t.getCause());
logger.debug("A request " + (cancelled ? "was cancelled" : "timed out"), t.getCause());
} else if (t instanceof RateLimitedException) {
// Log route & retry after on warn & context on debug
RateLimitedException exception = ((RateLimitedException) t);
discordSRV.logger().warning("A request on route " + exception.getRateLimitedRoute()
+ " was rate-limited for " + exception.getRetryAfter() + "ms");
discordSRV.logger().debug(exception.getCause());
logger.debug(exception.getCause());
} else if (t instanceof ErrorResponseException) {
ErrorResponseException exception = (ErrorResponseException) t;
if (exception.getErrorCode() == Response.ERROR_CODE) {
@ -464,7 +472,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
// Run the cause through this method again
accept(cause);
} else {
discordSRV.logger().error("Failed to complete request for a unknown reason", exception);
logger.error("Failed to complete request for a unknown reason", exception);
}
return;
}
@ -504,17 +512,17 @@ public class JDAConnectionManager implements DiscordConnectionManager {
discordSRV.logger().error("+--------------------------------------------------------------->");
} else {
// Log as debug as to not spam out the server console/log
discordSRV.logger().debug("Failed to complete a request, Discord returned a server error (HTTP 500)");
logger.debug("Failed to complete a request, Discord returned a server error (HTTP 500)");
}
// Log context to find what made the request
discordSRV.logger().debug(exception.getCause());
logger.debug(exception.getCause());
return;
}
default: break;
}
discordSRV.logger().error("Failed to complete a request: " + response.getMeaning());
discordSRV.logger().debug(exception);
logger.error("Failed to complete a request: " + response.getMeaning());
logger.debug(exception);
}
}
}

View File

@ -18,14 +18,18 @@
package com.discordsrv.common.event.bus;
import com.discordsrv.api.event.bus.EventBus;
import com.discordsrv.api.event.bus.EventListener;
import com.discordsrv.api.event.bus.*;
import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.bus.internal.EventStateHolder;
import com.discordsrv.api.event.events.Cancellable;
import com.discordsrv.api.event.events.Event;
import com.discordsrv.api.event.events.Processable;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.exception.InvalidListenerMethodException;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.NamedLogger;
import net.dv8tion.jda.api.events.GenericEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
@ -35,7 +39,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -48,11 +52,13 @@ public class EventBusImpl implements EventBus {
Pair.of(event -> event instanceof Processable && ((Processable) event).isProcessed(), EventStateHolder.PROCESSED)
);
private final Map<Object, Set<EventListenerImpl>> listeners = new ConcurrentHashMap<>();
private final Map<Object, List<EventListenerImpl>> listeners = new ConcurrentHashMap<>();
private final DiscordSRV discordSRV;
private final Logger logger;
public EventBusImpl(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
this.logger = new NamedLogger(discordSRV, "EVENT_BUS");
}
@Override
@ -64,8 +70,8 @@ public class EventBusImpl implements EventBus {
Class<?> listenerClass = eventListener.getClass();
List<Throwable> suppressedMethods = new ArrayList<>();
Set<EventListenerImpl> methods = new HashSet<>();
EnumMap<EventPriority, Set<EventListenerImpl>> methodsByPriority = new EnumMap<>(EventPriority.class);
List<EventListenerImpl> methods = new ArrayList<>();
EnumMap<EventPriority, List<EventListenerImpl>> methodsByPriority = new EnumMap<>(EventPriority.class);
Class<?> currentClass = listenerClass;
do {
@ -82,12 +88,12 @@ public class EventBusImpl implements EventBus {
}
listeners.put(eventListener, methods);
discordSRV.logger().debug("Listener " + eventListener.getClass().getName() + " subscribed");
logger.debug("Listener " + eventListener.getClass().getName() + " subscribed");
}
private void checkMethod(Class<?> listenerClass, Method method,
List<Throwable> suppressedMethods, Set<EventListenerImpl> methods,
EnumMap<EventPriority, Set<EventListenerImpl>> methodsByPriority) {
List<Throwable> suppressedMethods, List<EventListenerImpl> methods,
EnumMap<EventPriority, List<EventListenerImpl>> methodsByPriority) {
Subscribe annotation = method.getAnnotation(Subscribe.class);
if (annotation == null) {
return;
@ -137,7 +143,7 @@ public class EventBusImpl implements EventBus {
EventListenerImpl listener = new EventListenerImpl(listenerClass, annotation, firstParameter, method);
methods.add(listener);
methodsByPriority.computeIfAbsent(eventPriority, key -> new CopyOnWriteArraySet<>())
methodsByPriority.computeIfAbsent(eventPriority, key -> new CopyOnWriteArrayList<>())
.add(listener);
}
@ -149,7 +155,7 @@ public class EventBusImpl implements EventBus {
@Override
public void unsubscribe(@NotNull Object eventListener) {
listeners.remove(eventListener);
discordSRV.logger().debug("Listener " + eventListener.getClass().getName() + " unsubscribed");
logger.debug("Listener " + eventListener.getClass().getName() + " unsubscribed");
}
@Override
@ -176,7 +182,7 @@ public class EventBusImpl implements EventBus {
Class<?> eventClass = event.getClass();
for (EventPriority priority : EventPriority.values()) {
for (Map.Entry<Object, Set<EventListenerImpl>> entry : listeners.entrySet()) {
for (Map.Entry<Object, List<EventListenerImpl>> entry : listeners.entrySet()) {
Object listener = entry.getKey();
for (EventListenerImpl eventListener : entry.getValue()) {
if (eventListener.isIgnoringCancelled() && event instanceof Cancellable && ((Cancellable) event).isCancelled()) {
@ -198,7 +204,7 @@ public class EventBusImpl implements EventBus {
discordSRV.logger().error("Failed to pass " + event.getClass().getSimpleName() + " to " + eventListener, e.getCause());
}
long timeTaken = System.currentTimeMillis() - startTime;
discordSRV.logger().trace(eventListener + " took " + timeTaken + "ms to execute");
logger.trace(eventListener + " took " + timeTaken + "ms to execute");
for (int index = 0; index < STATES.size(); index++) {
Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> state = STATES.get(index);

View File

@ -22,12 +22,13 @@ import com.discordsrv.api.event.bus.EventListener;
import com.discordsrv.api.event.events.Cancellable;
import com.discordsrv.api.event.events.Processable;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.logging.Logger;
public final class EventUtil {
private EventUtil() {}
public static boolean checkProcessor(DiscordSRV discordSRV,Processable event) {
public static boolean checkProcessor(DiscordSRV discordSRV, Processable event, Logger logger) {
if (!event.isProcessed()) {
return false;
}
@ -36,12 +37,12 @@ public final class EventUtil {
.map(EventListener::className)
.orElse("Unknown");
if (!whoProcessed.startsWith("com.discordsrv")) {
discordSRV.logger().debug(event + " was handled by non-DiscordSRV handler: " + whoProcessed);
logger.debug(event + " was handled by non-DiscordSRV handler: " + whoProcessed);
}
return true;
}
public static boolean checkCancellation(DiscordSRV discordSRV, Cancellable event) {
public static boolean checkCancellation(DiscordSRV discordSRV, Cancellable event, Logger logger) {
if (!event.isCancelled()) {
return false;
}
@ -49,7 +50,7 @@ public final class EventUtil {
String whoCancelled = event.whoCancelled()
.map(EventListener::className)
.orElse("Unknown");
discordSRV.logger().debug(event + " was cancelled by " + whoCancelled);
logger.debug(event + " was cancelled by " + whoCancelled);
return true;
}
}

View File

@ -30,6 +30,7 @@ import com.discordsrv.common.groupsync.enums.GroupSyncCause;
import com.discordsrv.common.groupsync.enums.GroupSyncDirection;
import com.discordsrv.common.groupsync.enums.GroupSyncResult;
import com.discordsrv.common.groupsync.enums.GroupSyncSide;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule;
import com.discordsrv.common.module.type.PermissionDataProvider;
import com.discordsrv.common.player.IPlayer;
@ -53,7 +54,7 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
private final Cache<UUID, Map<String, Boolean>> expectedMinecraftChanges;
public GroupSyncModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "GROUP_SYNC"));
this.expectedDiscordChanges = discordSRV.caffeineBuilder()
.expireAfterWrite(30, TimeUnit.SECONDS)
.build();
@ -124,7 +125,7 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
for (Map.Entry<GroupSyncConfig.PairConfig, CompletableFuture<GroupSyncResult>> entry : pairs.entrySet()) {
summary.add(entry.getKey(), entry.getValue().join());
}
discordSRV.logger().debug(summary.toString());
logger().debug(summary.toString());
});
}
@ -224,9 +225,9 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
continue;
}
resyncPair(pair, uuid, userId)
.whenComplete((result, t) -> discordSRV.logger().debug(
new SynchronizationSummary(uuid, cause, pair, result).toString()));
resyncPair(pair, uuid, userId).whenComplete((result, t) -> logger().debug(
new SynchronizationSummary(uuid, cause, pair, result).toString()
));
}
}

View File

@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
public interface Logger {
default void info(String message) {
log(LogLevel.INFO, message, null);
log(null, LogLevel.INFO, message, null);
}
default void warning(String message) {
@ -34,7 +34,7 @@ public interface Logger {
warning(null, throwable);
}
default void warning(String message, Throwable throwable) {
log(LogLevel.WARNING, message, throwable);
log(null, LogLevel.WARNING, message, throwable);
}
default void error(String message) {
@ -44,7 +44,7 @@ public interface Logger {
error(null, throwable);
}
default void error(String message, Throwable throwable) {
log(LogLevel.ERROR, message, throwable);
log(null, LogLevel.ERROR, message, throwable);
}
default void debug(String message) {
@ -54,7 +54,7 @@ public interface Logger {
debug(null, throwable);
}
default void debug(String message, Throwable throwable) {
log(LogLevel.DEBUG, message, throwable);
log(null, LogLevel.DEBUG, message, throwable);
}
default void trace(String message) {
@ -64,9 +64,9 @@ public interface Logger {
trace(null, throwable);
}
default void trace(String message, Throwable throwable) {
log(LogLevel.TRACE, message, throwable);
log(null, LogLevel.TRACE, message, throwable);
}
void log(@NotNull LogLevel logLevel, @Nullable String message, @Nullable Throwable throwable);
void log(@Nullable String loggerName, @NotNull LogLevel logLevel, @Nullable String message, @Nullable Throwable throwable);
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.logging;
import com.discordsrv.common.DiscordSRV;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class NamedLogger implements Logger {
private final DiscordSRV discordSRV;
private final String name;
public NamedLogger(DiscordSRV discordSRV, String name) {
this.discordSRV = discordSRV;
this.name = name;
}
@Override
public void log(@Nullable String loggerName, @NotNull LogLevel logLevel, @Nullable String message, @Nullable Throwable throwable) {
discordSRV.logger().log(name, logLevel, message, throwable);
}
}

View File

@ -59,7 +59,7 @@ public class JavaLoggerImpl implements Logger, LoggingBackend {
}
@Override
public void log(@NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
public void log(@Nullable String loggerName, @NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
Level logLevel = LEVELS.getKey(level);
if (logLevel != null) {
logger.log(logLevel, message, throwable);

View File

@ -64,7 +64,7 @@ public class Log4JLoggerImpl implements Logger, LoggingBackend {
}
@Override
public void log(@NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
public void log(@Nullable String loggerName, @NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
Level logLevel = LEVELS.getKey(level);
logger.log(logLevel, message, throwable);
}

View File

@ -32,7 +32,7 @@ public class SLF4JLoggerImpl implements Logger {
}
@Override
public void log(@NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
public void log(@Nullable String loggerName, @NotNull LogLevel level, @Nullable String message, @Nullable Throwable throwable) {
if (!(level instanceof LogLevel.StandardLogLevel)) {
return;
}

View File

@ -84,6 +84,6 @@ public class DependencyLoggingHandler implements LogAppender {
}
}
discordSRV.logger().log(logLevel, "[" + name + "]" + (message != null ? " " + message : ""), throwable);
discordSRV.logger().log(null, logLevel, "[" + name + "]" + (message != null ? " " + message : ""), throwable);
}
}

View File

@ -23,24 +23,77 @@ import com.discordsrv.common.logging.LogLevel;
import com.discordsrv.common.logging.Logger;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class DiscordSRVLogger implements Logger {
private static final DateFormat DATE_TIME_FORMATTER = new SimpleDateFormat("EEE HH:mm:ss z");
private static final String LOG_LINE_FORMAT = "[%s] [%s] %s";
private static final String LOG_FILE_NAME_FORMAT = "%s-%s.log";
private final DiscordSRV discordSRV;
private final Path logsDirectory;
private final List<Path> debugLogs;
public DiscordSRVLogger(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
this.logsDirectory = discordSRV.dataDirectory().resolve("logs");
if (!Files.exists(logsDirectory)) {
try {
Files.createDirectory(logsDirectory);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
this.debugLogs = rotateLog("debug", 3);
}
public List<Path> getDebugLogs() {
return debugLogs;
}
@SuppressWarnings("SameParameterValue")
private List<Path> rotateLog(String label, int amount) {
try {
List<Path> logs = new ArrayList<>(amount);
for (int i = amount; i > 0; i--) {
Path log = logsDirectory.resolve(String.format(LOG_FILE_NAME_FORMAT, label, i));
logs.add(log);
if (!Files.exists(log)) {
continue;
}
if (i == amount) {
Files.delete(log);
continue;
}
Path to = logsDirectory.resolve(String.format(LOG_FILE_NAME_FORMAT, label, i + 1));
Files.move(log, to);
}
return logs;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public void log(@NotNull LogLevel logLevel, @Nullable String message, @Nullable Throwable throwable) {
if (logLevel == LogLevel.DEBUG || logLevel == LogLevel.TRACE || logLevel instanceof LogLevel.CustomLogLevel) {
// TODO: handle debug/trace
return;
}
public void log(@Nullable String loggerName, @NotNull LogLevel logLevel, @Nullable String message, @Nullable Throwable throwable) {
if (throwable instanceof InsufficientPermissionException) {
Permission permission = ((InsufficientPermissionException) throwable).getPermission();
String msg = "The bot is missing the \"" + permission.getName() + "\" permission";
@ -49,11 +102,55 @@ public class DiscordSRVLogger implements Logger {
} else {
message += ": " + msg;
}
discordSRV.platformLogger().log(logLevel, message, null);
discordSRV.logger().debug(throwable);
doLog(loggerName, logLevel, message, null);
doLog(loggerName, LogLevel.DEBUG, null, throwable);
return;
}
discordSRV.platformLogger().log(logLevel, message, throwable);
doLog(loggerName, logLevel, message, throwable);
}
private void doLog(String loggerName, LogLevel logLevel, String message, Throwable throwable) {
if (logLevel != LogLevel.DEBUG && logLevel != LogLevel.TRACE) {
discordSRV.platformLogger().log(null, logLevel, message, throwable);
}
// TODO: handle trace
Path debugLog = debugLogs.isEmpty() ? null : debugLogs.get(0);
if (debugLog == null || logLevel == LogLevel.TRACE) {
return;
}
long time = System.currentTimeMillis();
discordSRV.scheduler().runFork(() -> writeToFile(loggerName, debugLog, time, logLevel, message, throwable));
}
private void writeToFile(String loggerName, Path path, long time, LogLevel logLevel, String message, Throwable throwable) {
try {
Path parent = path.getParent();
if (!Files.exists(parent)) {
Files.createDirectories(parent);
}
if (!Files.exists(path)) {
Files.createFile(path);
}
if (message == null) {
message = "";
}
if (loggerName != null) {
message = "[" + loggerName + "] " + message;
}
String timestamp = DATE_TIME_FORMATTER.format(time);
String line = String.format(LOG_LINE_FORMAT, timestamp, logLevel.name(), message) + "\n";
if (throwable != null) {
line += ExceptionUtils.getStackTrace(throwable) + "\n";
}
Files.write(path, line.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
} catch (Throwable e) {
// Prevent infinite loop
discordSRV.platformLogger().error("Failed to write to debug log", e);
}
}
}

View File

@ -36,6 +36,7 @@ import com.discordsrv.common.config.main.DiscordIgnores;
import com.discordsrv.common.config.main.channels.DiscordToMinecraftChatConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule;
import net.kyori.adventure.text.Component;
@ -44,7 +45,7 @@ import java.util.Map;
public class DiscordChatMessageModule extends AbstractModule<DiscordSRV> {
public DiscordChatMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "DISCORD_TO_MINECRAFT"));
}
@Subscribe

View File

@ -38,6 +38,7 @@ import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.future.util.CompletableFutureUtil;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule;
import com.github.benmanes.caffeine.cache.Cache;
@ -50,7 +51,7 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
private final Cache<MessageReference, Set<MessageReference>> mapping;
public DiscordMessageMirroringModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "DISCORD_MIRRORING"));
this.mapping = discordSRV.caffeineBuilder()
.expireAfterWrite(30, TimeUnit.MINUTES)
.expireAfterAccess(10, TimeUnit.MINUTES)

View File

@ -35,6 +35,7 @@ import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageClusterImpl;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.module.type.AbstractModule;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
@ -47,8 +48,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
public abstract class AbstractGameMessageModule<T> extends AbstractModule<DiscordSRV> {
public AbstractGameMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
public AbstractGameMessageModule(DiscordSRV discordSRV, Logger logger) {
super(discordSRV, logger);
}
public abstract OrDefault<T> mapConfig(OrDefault<BaseChannelConfig> channelConfig);

View File

@ -28,11 +28,12 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.JoinMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
public class JoinMessageModule extends AbstractGameMessageModule<JoinMessageConfig> {
public JoinMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "JOIN_MESSAGES"));
}
@Override

View File

@ -28,11 +28,12 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.LeaveMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageConfig> {
public LeaveMessageModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "LEAVE_MESSAGES"));
}
@Override

View File

@ -37,6 +37,7 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildChannel;
import net.dv8tion.jda.api.entities.Member;
@ -65,7 +66,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
private final Map<Long, Map<Long, CachedMention>> channelMentions = new ConcurrentHashMap<>();
public MinecraftToDiscordChatModule(DiscordSRV discordSRV) {
super(discordSRV);
super(discordSRV, new NamedLogger(discordSRV, "MINECRAFT_TO_DISCORD"));
}
@Override

View File

@ -23,14 +23,25 @@ import com.discordsrv.api.event.events.Processable;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.event.util.EventUtil;
import com.discordsrv.common.logging.Logger;
public abstract class AbstractModule<DT extends DiscordSRV> implements Module {
protected final DT discordSRV;
private final Logger logger;
private boolean hasBeenEnabled = false;
public AbstractModule(DT discordSRV) {
this(discordSRV, discordSRV.logger());
}
public AbstractModule(DT discordSRV, Logger logger) {
this.discordSRV = discordSRV;
this.logger = logger;
}
public final Logger logger() {
return logger;
}
public final void enableModule() {
@ -49,10 +60,10 @@ public abstract class AbstractModule<DT extends DiscordSRV> implements Module {
// Utility
protected final boolean checkProcessor(Processable event) {
return EventUtil.checkProcessor(discordSRV, event);
return EventUtil.checkProcessor(discordSRV, event, logger());
}
protected final boolean checkCancellation(Cancellable event) {
return EventUtil.checkCancellation(discordSRV, event);
return EventUtil.checkCancellation(discordSRV, event, logger());
}
}

View File

@ -31,6 +31,7 @@ import com.discordsrv.common.scheduler.StandardScheduler;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MockDiscordSRV extends AbstractDiscordSRV<MainConfig, ConnectionConfig> {
@ -50,7 +51,7 @@ public class MockDiscordSRV extends AbstractDiscordSRV<MainConfig, ConnectionCon
@Override
public Path dataDirectory() {
return null;
return Paths.get("");
}
@Override

View File

@ -61,25 +61,24 @@ public class DiscordSRVSpongeBootstrap extends AbstractBootstrap implements ISpo
@Override
public void onConstruct() {
// Wait until dependencies ready, then initialize DiscordSRV
dependencies.join();
dependencies.load();
}
@Override
public void onStarted() {
this.discordSRV = new SpongeDiscordSRV(logger, pluginContainer, game, classLoader, dataDirectory);
dependencies.runWhenComplete(discordSRV::invokeEnable);
dependencies.runWhenComplete(discordSRV::invokeServerStarted);
dependencies.enable(() -> this.discordSRV = new SpongeDiscordSRV(logger, pluginContainer, game, classLoader, dataDirectory));
if (discordSRV != null) {
discordSRV.invokeServerStarted();
}
}
@Override
public void onRefresh() {
dependencies.runWhenComplete(discordSRV::invokeReload);
dependencies.reload(discordSRV);
}
@Override
public void onStopping() {
dependencies.runWhenComplete(discordSRV::invokeDisable);
dependencies.disable(discordSRV);
}
}

View File

@ -68,21 +68,17 @@ public class DiscordSRVVelocityBootstrap {
@Subscribe
public void onProxyInitialize(ProxyInitializeEvent event) {
// Wait until dependencies ready, then initialize DiscordSRV
dependencies.join();
this.discordSRV = new VelocityDiscordSRV(this, logger, proxyServer, pluginContainer, dataDirectory);
dependencies.runWhenComplete(discordSRV::invokeEnable);
dependencies.loadAndEnable(() -> this.discordSRV = new VelocityDiscordSRV(this, logger, proxyServer, pluginContainer, dataDirectory));
}
@Subscribe
public void onProxyReload(ProxyReloadEvent event) {
dependencies.runWhenComplete(discordSRV::invokeReload);
dependencies.reload(discordSRV);
}
@Subscribe
public void onProxyShutdown(ProxyShutdownEvent event) {
dependencies.runWhenComplete(discordSRV::invokeDisable);
dependencies.disable(discordSRV);
}
}

View File

@ -23,8 +23,8 @@ import com.discordsrv.common.config.main.MainConfig;
import com.discordsrv.common.config.manager.ConnectionConfigManager;
import com.discordsrv.common.config.manager.MainConfigManager;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.proxy.ProxyDiscordSRV;
import com.discordsrv.common.scheduler.StandardScheduler;
import com.discordsrv.proxy.ProxyDiscordSRV;
import com.discordsrv.velocity.console.VelocityConsole;
import com.discordsrv.velocity.player.VelocityPlayerProvider;
import com.velocitypowered.api.plugin.PluginContainer;