From 265b26d6e3d5826aafd471c34651836c6eb22991 Mon Sep 17 00:00:00 2001 From: ishland Date: Wed, 27 Jan 2021 23:53:20 +0800 Subject: [PATCH] Detailed lag and crash reports (#369) Added "Suspected Plugins" to Watchdog and crash reports --- PATCHES.md | 2 + .../0008-Detailed-lag-and-crash-reports.patch | 66 +++++++++ .../0065-Detailed-lag-and-crash-reports.patch | 126 ++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 patches/api/0008-Detailed-lag-and-crash-reports.patch create mode 100644 patches/server/0065-Detailed-lag-and-crash-reports.patch diff --git a/PATCHES.md b/PATCHES.md index ce88480a..5ae69910 100644 --- a/PATCHES.md +++ b/PATCHES.md @@ -132,6 +132,8 @@ # Patches | server | Delay chunk unloads | Spottedleaf | | | server | Despawn rate config options per projectile type | jmp | | | server | Detail more information in watchdog dumps | Spottedleaf | | +| server | Detailed lag and crash reports | ishland | | +| api | Detailed lag and crash reports | ishland | | | server | Disable loot drops on death by cramming | William Blake Galbreath | | | server | Disable outdated build check | William Blake Galbreath | | | api | Disable reload command | Ivan Pekov | | diff --git a/patches/api/0008-Detailed-lag-and-crash-reports.patch b/patches/api/0008-Detailed-lag-and-crash-reports.patch new file mode 100644 index 00000000..78c06d97 --- /dev/null +++ b/patches/api/0008-Detailed-lag-and-crash-reports.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ishland +Date: Wed, 27 Jan 2021 23:35:30 +0800 +Subject: [PATCH] Detailed lag and crash reports + +Added "Suspected Plugins" to Watchdog and crash reports + +diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +index 26685f59b235ea5b4c4fb7ae21acb5149edaa2b3..a90945e434aa3729e2ec5355a4340c995316a2f7 100644 +--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java ++++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +@@ -905,4 +905,9 @@ public final class SimplePluginManager implements PluginManager { + } + // Paper end + ++ // Yatopia start - Accessor ++ public Collection 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 384edf9890dfbd1cddfdcac4db1ebe9a4d761f78..6d39959389e2eebb4acf19dfb1efc5cf692db135 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -439,4 +439,9 @@ public final class JavaPluginLoader implements PluginLoader { + } + } + } ++ // Yatopia start - Accessor ++ public List 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 7760be3e34fa20825faf145d9fb5b2855c1a4602..2e8f3efdb683c44b3e42bb0187bc907e64cde288 100644 +--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +@@ -232,4 +232,13 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot + '}'; + } + // Paper end ++ ++ // Yatopia start - Accessor ++ public java.util.Collection> 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/patches/server/0065-Detailed-lag-and-crash-reports.patch b/patches/server/0065-Detailed-lag-and-crash-reports.patch new file mode 100644 index 00000000..6fc4c969 --- /dev/null +++ b/patches/server/0065-Detailed-lag-and-crash-reports.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ishland +Date: Wed, 27 Jan 2021 23:35:30 +0800 +Subject: [PATCH] Detailed lag and crash reports + +Added "Suspected Plugins" to Watchdog and crash reports + +diff --git a/src/main/java/net/minecraft/server/CrashReport.java b/src/main/java/net/minecraft/server/CrashReport.java +index cc6e6f245ee5e73bd570cf42381bf55ee0b364d3..e52eb754debd3abe02da978825e53839e87302fc 100644 +--- a/src/main/java/net/minecraft/server/CrashReport.java ++++ b/src/main/java/net/minecraft/server/CrashReport.java +@@ -87,6 +87,8 @@ public class CrashReport { + if (this.h != null && this.h.length > 0) { + stringbuilder.append("-- Head --\n"); + stringbuilder.append("Thread: ").append(Thread.currentThread().getName()).append("\n"); ++ org.yatopiamc.yatopia.server.util.StackTraceUtils.printPlugins(this.h, stringbuilder::append); // Yatopia ++ stringbuilder.append("\n"); // Yatopia + stringbuilder.append("Stacktrace:\n"); + StackTraceElement[] astacktraceelement = this.h; + int i = astacktraceelement.length; +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 27cdbcdad0ae7be6a2aa8b9982bcd80205c48c9b..a9fc37242e9fe19dcace4f154cb3a6da94a7775a 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1039,6 +1039,8 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant log.log(Level.SEVERE, msg)); ++ log.log(Level.SEVERE, ""); ++ // Yatopia end + log.log( Level.SEVERE, "\tStack:" ); + // + for ( StackTraceElement stack : thread.getStackTrace() ) +diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/StackTraceUtils.java b/src/main/java/org/yatopiamc/yatopia/server/util/StackTraceUtils.java +new file mode 100644 +index 0000000000000000000000000000000000000000..627debed74cd8400371de887c2667ff839288de3 +--- /dev/null ++++ b/src/main/java/org/yatopiamc/yatopia/server/util/StackTraceUtils.java +@@ -0,0 +1,72 @@ ++package org.yatopiamc.yatopia.server.util; ++ ++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.Collection; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Map; ++import java.util.Set; ++import java.util.function.Consumer; ++ ++public class StackTraceUtils { ++ ++ public static void printPlugins(StackTraceElement[] stackTrace, Consumer out) { ++ Map>> loadedClasses = scanForPluginClasses(); ++ ++ Set suspectedPlugins = new HashSet<>(); ++ for (StackTraceElement stackTraceElement : stackTrace) { ++ for (Map.Entry>> pluginSetEntry : loadedClasses.entrySet()) { ++ if (pluginSetEntry.getValue().stream().anyMatch(clazz -> clazz.getName().equals(stackTraceElement.getClassName()))) ++ suspectedPlugins.add(pluginSetEntry.getKey()); ++ } ++ } ++ ++ 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 Map>> scanForPluginClasses() { ++ Map>> loadedClasses = new Object2ObjectOpenHashMap<>(); ++ if (Bukkit.getPluginManager() instanceof SimplePluginManager) { ++ final SimplePluginManager pluginManager = (SimplePluginManager) Bukkit.getPluginManager(); ++ final Collection pluginLoaders = pluginManager.getPluginLoaders(); ++ for (PluginLoader pluginLoader : pluginLoaders) { ++ if (pluginLoader instanceof JavaPluginLoader) { ++ JavaPluginLoader javaPluginLoader = (JavaPluginLoader) pluginLoader; ++ final List classLoaders = javaPluginLoader.getClassLoaders(); ++ for (PluginClassLoader classLoader : classLoaders) { ++ loadedClasses.put(classLoader.getPlugin(), new ObjectOpenHashSet<>(classLoader.getLoadedClasses())); ++ } ++ } ++ } ++ } ++ return loadedClasses; ++ } ++ ++}