mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-11-28 21:56:37 +01:00
1539317fe0
Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: e04368045 Updated Upstream (Bukkit/CraftBukkit) (#5794) Empirecraft Changes: e187791e Updated Paper
259 lines
13 KiB
Diff
259 lines
13 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: ishland <ishlandmc@yeah.net>
|
|
Date: Fri, 29 Jan 2021 09:57:47 +0800
|
|
Subject: [PATCH] Suspected plugins report
|
|
|
|
Added "Suspected Plugins" to Watchdog, crash reports and exception messages
|
|
|
|
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
|
index 0e25119564dfa9cb12f3c5dc5f653d7f2c147a9d..747494010c85bded946451375d38b36c85f72986 100644
|
|
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
|
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
|
@@ -577,7 +577,11 @@ public final class SimplePluginManager implements PluginManager {
|
|
|
|
// Paper start
|
|
private void handlePluginException(String msg, Throwable ex, Plugin plugin) {
|
|
- server.getLogger().log(Level.SEVERE, msg, ex);
|
|
+ // Yatopia start - detailed report
|
|
+ server.getLogger().log(Level.SEVERE, msg);
|
|
+ org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg));
|
|
+ server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex);
|
|
+ // Yatopia end
|
|
callEvent(new ServerExceptionEvent(new ServerPluginEnableDisableException(msg, ex, plugin)));
|
|
}
|
|
// Paper end
|
|
@@ -638,7 +642,11 @@ public final class SimplePluginManager implements PluginManager {
|
|
} catch (Throwable ex) {
|
|
// Paper start - error reporting
|
|
String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName();
|
|
- server.getLogger().log(Level.SEVERE, msg, ex);
|
|
+ // Yatopia start - detailed report
|
|
+ server.getLogger().log(Level.SEVERE, msg);
|
|
+ org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg));
|
|
+ server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex);
|
|
+ // Yatopia end
|
|
if (!(event instanceof ServerExceptionEvent)) { // We don't want to cause an endless event loop
|
|
callEvent(new ServerExceptionEvent(new ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event)));
|
|
}
|
|
@@ -923,4 +931,10 @@ public final class SimplePluginManager implements PluginManager {
|
|
}
|
|
// Paper end
|
|
|
|
+ // Yatopia start - Accessor
|
|
+ @NotNull
|
|
+ public Collection<PluginLoader> getPluginLoaders() {
|
|
+ return new HashSet<>(fileAssociations.values());
|
|
+ }
|
|
+ // Yatopia end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
|
|
index 04fa3991f6ce4e9dad804f28fc6c947695857089..cb11eab6e13ed1c395b8f7db033c9a2817f4089c 100644
|
|
--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
|
|
+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
|
|
@@ -111,7 +111,7 @@ public abstract class JavaPlugin extends PluginBase {
|
|
* @return File containing this plugin
|
|
*/
|
|
@NotNull
|
|
- protected File getFile() {
|
|
+ public File getFile() { // Yatopia
|
|
return file;
|
|
}
|
|
|
|
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
index b622cedeeee017f042bcf92485d81832030a8030..f1d3042e7f224059547ac840524cae5dd80ecd8b 100644
|
|
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
@@ -369,7 +369,11 @@ public final class JavaPluginLoader implements PluginLoader {
|
|
try {
|
|
jPlugin.setEnabled(true);
|
|
} catch (Throwable ex) {
|
|
- server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
|
|
+ // Yatopia start - detailed report
|
|
+ server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)");
|
|
+ org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg));
|
|
+ server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex);
|
|
+ // Yatopia end
|
|
// Paper start - Disable plugins that fail to load
|
|
server.getPluginManager().disablePlugin(jPlugin, true); // Paper - close Classloader on disable - She's dead jim
|
|
return;
|
|
@@ -404,7 +408,11 @@ public final class JavaPluginLoader implements PluginLoader {
|
|
try {
|
|
jPlugin.setEnabled(false);
|
|
} catch (Throwable ex) {
|
|
- server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
|
|
+ // Yatopia start - detailed report
|
|
+ server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)");
|
|
+ org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg));
|
|
+ server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex);
|
|
+ // Yatopia end
|
|
}
|
|
|
|
if (cloader instanceof PluginClassLoader) {
|
|
@@ -428,11 +436,20 @@ public final class JavaPluginLoader implements PluginLoader {
|
|
loader.close();
|
|
}
|
|
} catch (IOException e) {
|
|
+ // Yatopia start - detailed report
|
|
server.getLogger().log(Level.WARNING, "Error closing the Plugin Class Loader for " + plugin.getDescription().getFullName());
|
|
+ org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(e, _msg -> server.getLogger().log(Level.WARNING, _msg));
|
|
+ server.getLogger().log(Level.WARNING, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, e);
|
|
+ // Yatopia end
|
|
e.printStackTrace();
|
|
}
|
|
// Paper end
|
|
}
|
|
}
|
|
}
|
|
+ // Yatopia start - Accessor
|
|
+ public List<PluginClassLoader> getClassLoaders() {
|
|
+ return java.util.Collections.unmodifiableList(loaders);
|
|
+ }
|
|
+ // Yatopia end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java
|
|
index 4b484d5c2a605188f55ea8cdc0c2839ee6d850ff..a246f43f2e28864b4795a0ffddfec361e1318938 100644
|
|
--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java
|
|
+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java
|
|
@@ -252,4 +252,13 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot
|
|
'}';
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Yatopia start - Accessor
|
|
+ public java.util.Collection<Class<?>> getLoadedClasses() {
|
|
+ return java.util.Collections.unmodifiableCollection(
|
|
+ new java.util.HashSet<>(classes.values()).stream()
|
|
+ .filter(clazz -> clazz.getClassLoader() == this).collect(java.util.stream.Collectors.toSet())
|
|
+ );
|
|
+ }
|
|
+ // Yatopia end
|
|
}
|
|
diff --git a/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java b/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0aa9bc6ad0a85d469b29201b9da29165bafb874c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java
|
|
@@ -0,0 +1,105 @@
|
|
+package org.yatopiamc.yatopia.api.internal;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.plugin.Plugin;
|
|
+import org.bukkit.plugin.PluginLoader;
|
|
+import org.bukkit.plugin.SimplePluginManager;
|
|
+import org.bukkit.plugin.java.JavaPlugin;
|
|
+import org.bukkit.plugin.java.JavaPluginLoader;
|
|
+import org.bukkit.plugin.java.PluginClassLoader;
|
|
+
|
|
+import java.util.Arrays;
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+import java.util.HashSet;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.concurrent.TimeUnit;
|
|
+import java.util.function.Consumer;
|
|
+import java.util.function.Supplier;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+public class StackTraceUtils {
|
|
+
|
|
+ public static final String EXCEPTION_DETAILS_BELOW = "Exception details below: ";
|
|
+
|
|
+ private static final Supplier<Map<Plugin, Set<Class<?>>>> loadedClassesSupplier = Suppliers.memoizeWithExpiration(StackTraceUtils::scanForPluginClasses, 5, TimeUnit.SECONDS);
|
|
+
|
|
+ public static void print(StackTraceElement[] stackTrace, Consumer<String> out) {
|
|
+ Set<Plugin> suspectedPlugins = getSuspectedPluginsFromStackTrace(stackTrace);
|
|
+
|
|
+ printSuspectedPlugins(out, suspectedPlugins);
|
|
+ }
|
|
+
|
|
+ public static void print(Throwable t, Consumer<String> out) {
|
|
+ Set<Plugin> suspectedPlugins = getSuspectedPluginsFromStackTrace(getStackTracesFromThrowable(t).toArray(new StackTraceElement[0]));
|
|
+
|
|
+ printSuspectedPlugins(out, suspectedPlugins);
|
|
+ }
|
|
+
|
|
+ private static Set<StackTraceElement> getStackTracesFromThrowable(Throwable t) {
|
|
+ if(t == null) return Collections.emptySet();
|
|
+ Set<StackTraceElement> elements = new ObjectOpenHashSet<>();
|
|
+ elements.addAll(getStackTracesFromThrowable(t.getCause()));
|
|
+ elements.addAll(Arrays.stream(t.getSuppressed()).flatMap(throwable -> getStackTracesFromThrowable(throwable).stream()).collect(Collectors.toSet()));
|
|
+ elements.addAll(Arrays.asList(t.getStackTrace()));
|
|
+ return elements;
|
|
+ }
|
|
+
|
|
+ private static void printSuspectedPlugins(Consumer<String> out, Set<Plugin> suspectedPlugins) {
|
|
+ if (!suspectedPlugins.isEmpty()) {
|
|
+ out.accept("Suspected Plugins: ");
|
|
+ for (Plugin plugin : suspectedPlugins) {
|
|
+ StringBuilder builder = new StringBuilder("\t");
|
|
+ builder.append(plugin.getName())
|
|
+ .append("{")
|
|
+ .append(plugin.isEnabled() ? "enabled" : "disabled")
|
|
+ .append(",").append("ver=").append(plugin.getDescription().getVersion());
|
|
+ if (!plugin.isNaggable())
|
|
+ builder.append(",").append("nag");
|
|
+ if (plugin instanceof JavaPlugin)
|
|
+ builder.append(",").append("path=").append(((JavaPlugin) plugin).getFile());
|
|
+
|
|
+ builder.append("}");
|
|
+ out.accept(builder.toString());
|
|
+ }
|
|
+ } else {
|
|
+ out.accept("Suspected Plugins: None");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static Set<Plugin> getSuspectedPluginsFromStackTrace(StackTraceElement[] stackTrace) {
|
|
+ Map<Plugin, Set<Class<?>>> loadedClasses = loadedClassesSupplier.get();
|
|
+ Set<Plugin> suspectedPlugins = new HashSet<>();
|
|
+ for (StackTraceElement stackTraceElement : stackTrace) {
|
|
+ for (Map.Entry<Plugin, Set<Class<?>>> pluginSetEntry : loadedClasses.entrySet()) {
|
|
+ if (pluginSetEntry.getValue().stream().anyMatch(clazz -> clazz.getName().equals(stackTraceElement.getClassName())))
|
|
+ suspectedPlugins.add(pluginSetEntry.getKey());
|
|
+ }
|
|
+ }
|
|
+ return suspectedPlugins;
|
|
+ }
|
|
+
|
|
+ private static Map<Plugin, Set<Class<?>>> scanForPluginClasses() {
|
|
+ Map<Plugin, Set<Class<?>>> loadedClasses = new Object2ObjectOpenHashMap<>();
|
|
+ if (Bukkit.getPluginManager() instanceof SimplePluginManager) {
|
|
+ final SimplePluginManager pluginManager = (SimplePluginManager) Bukkit.getPluginManager();
|
|
+ final Collection<PluginLoader> pluginLoaders = pluginManager.getPluginLoaders();
|
|
+ for (PluginLoader pluginLoader : pluginLoaders) {
|
|
+ if (pluginLoader instanceof JavaPluginLoader) {
|
|
+ JavaPluginLoader javaPluginLoader = (JavaPluginLoader) pluginLoader;
|
|
+ final List<PluginClassLoader> classLoaders = javaPluginLoader.getClassLoaders();
|
|
+ for (PluginClassLoader classLoader : classLoaders) {
|
|
+ loadedClasses.put(classLoader.getPlugin(), new ObjectOpenHashSet<>(classLoader.getLoadedClasses()));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return loadedClasses;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
|
|
index 82b2783497947f336b0dd95db61f31f8f77f446c..d0673f4cea94ce833a08bc3395fe3cc0abb614cb 100644
|
|
--- a/src/test/java/org/bukkit/AnnotationTest.java
|
|
+++ b/src/test/java/org/bukkit/AnnotationTest.java
|
|
@@ -57,8 +57,11 @@ public class AnnotationTest {
|
|
"co/aikar/timings/TimingHistory$2$1$2",
|
|
"co/aikar/timings/TimingHistory$3",
|
|
"co/aikar/timings/TimingHistory$4",
|
|
- "co/aikar/timings/TimingHistoryEntry$1"
|
|
+ "co/aikar/timings/TimingHistoryEntry$1",
|
|
// Paper end
|
|
+ // Yatopia start
|
|
+ "org/yatopiamc/yatopia/api/internal/StackTraceUtils"
|
|
+ // Yatopia end
|
|
};
|
|
|
|
@Test
|