feat: 更新线程检查 添加调试

Signed-off-by: 502647092 <admin@yumc.pw>
dev
502647092 2017-01-19 21:22:48 +08:00
parent 5f628e08f1
commit c18bae3b8e
7 changed files with 143 additions and 142 deletions

194
pom.xml
View File

@ -1,98 +1,100 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>pw.yumc</groupId> <groupId>pw.yumc</groupId>
<artifactId>Yum</artifactId> <artifactId>Yum</artifactId>
<version>2.7.8</version> <version>2.7.8</version>
<name>Yum</name> <name>Yum</name>
<description>Minecraft 服务器插件管理系统</description> <description>Minecraft 服务器插件管理系统</description>
<build> <build>
<finalName>${project.name}</finalName> <finalName>${project.name}</finalName>
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
</resources> </resources>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>3.1</version> <artifactId>maven-shade-plugin</artifactId>
<configuration> <version>2.3</version>
<source>1.7</source> <configuration>
<target>1.7</target> <createDependencyReducedPom>false</createDependencyReducedPom>
</configuration> <minimizeJar>true</minimizeJar>
</plugin> <artifactSet>
<plugin> <includes>
<groupId>org.apache.maven.plugins</groupId> <include>pw.yumc:YumCore</include>
<artifactId>maven-shade-plugin</artifactId> </includes>
<version>2.3</version> </artifactSet>
<configuration> <relocations>
<createDependencyReducedPom>false</createDependencyReducedPom> <relocation>
<minimizeJar>true</minimizeJar> <pattern>pw.yumc.YumCore</pattern>
<artifactSet> <shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern>
<includes> </relocation>
<include>pw.yumc:YumCore</include> </relocations>
</includes> </configuration>
</artifactSet> <executions>
<relocations> <execution>
<relocation> <phase>package</phase>
<pattern>pw.yumc.YumCore</pattern> <goals>
<shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern> <goal>shade</goal>
</relocation> </goals>
</relocations> </execution>
</configuration> </executions>
<executions> </plugin>
<execution> <plugin>
<phase>package</phase> <groupId>org.apache.maven.plugins</groupId>
<goals> <artifactId>maven-compiler-plugin</artifactId>
<goal>shade</goal> <configuration>
</goals> <source>1.7</source>
</execution> <target>1.7</target>
</executions> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<ciManagement> <ciManagement>
<system>Jenkins</system> <system>Jenkins</system>
<url>http://ci.yumc.pw/job/${project.artifactId}/</url> <url>http://ci.yumc.pw/job/${project.artifactId}/</url>
</ciManagement> </ciManagement>
<properties> <properties>
<update.description>§a全新 2.X 版本 更多守护与优化</update.description> <update.description>§a全新 2.X 版本 更多守护与优化</update.description>
<update.changes> <update.changes>
§c注意 §6- §aYum更新需要§d重启服务器!§c重启服务器!§4重启服务器!; §c注意 §6- §aYum更新需要§d重启服务器!§c重启服务器!§4重启服务器!;
§b2.7.7 §6- §c修复部分插件重载时提示Plugin already initialized的问题!; §b2.7.7 §6- §c修复部分插件重载时提示Plugin already initialized的问题!;
§6- §c修复§eBukkitDev§c下载地址跳转问题...; §6- §c修复§eBukkitDev§c下载地址跳转问题...;
§6- §c修复§eBukkitDev§c下载为空时的异常...; §6- §c修复§eBukkitDev§c下载为空时的异常...;
</update.changes> </update.changes>
<env.GIT_COMMIT>DEV</env.GIT_COMMIT> <env.GIT_COMMIT>DEV</env.GIT_COMMIT>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <maven.compiler.source>1.7</maven.compiler.source>
<repositories> <maven.compiler.target>1.7</maven.compiler.target>
<repository> </properties>
<id>yumc-repo</id> <repositories>
<url>http://repo.yumc.pw/content/groups/public/</url> <repository>
</repository> <id>yumc-repo</id>
</repositories> <url>http://repo.yumc.pw/content/groups/public/</url>
<distributionManagement> </repository>
<repository> </repositories>
<id>jtb</id> <distributionManagement>
<name>YUMC</name> <repository>
<url>http://repo.yumc.pw/content/repositories/yumcenter/</url> <id>jtb</id>
</repository> <name>YUMC</name>
</distributionManagement> <url>http://repo.yumc.pw/content/repositories/yumcenter/</url>
<dependencies> </repository>
<dependency> </distributionManagement>
<groupId>pw.yumc</groupId> <dependencies>
<artifactId>YumCore</artifactId> <dependency>
<type>jar</type> <groupId>pw.yumc</groupId>
<version>1.5</version> <artifactId>YumCore</artifactId>
</dependency> <type>jar</type>
<dependency> <version>1.5</version>
<groupId>pw.yumc</groupId> </dependency>
<artifactId>BukkitInjectedTools</artifactId> <dependency>
<type>jar</type> <groupId>pw.yumc</groupId>
<version>1.0</version> <artifactId>BukkitInjectedTools</artifactId>
</dependency> <type>jar</type>
</dependencies> <version>1.0</version>
</dependency>
</dependencies>
</project> </project>

View File

@ -70,8 +70,6 @@ public class Yum extends JavaPlugin {
public void onLoad() { public void onLoad() {
// 初始化配置 // 初始化配置
ConfigManager.i(); ConfigManager.i();
// 初始化更新列
// UpdatePlugin.getUpdateList();
// 启用网络注入 // 启用网络注入
NetworkManager.register(this); NetworkManager.register(this);
} }
@ -135,7 +133,7 @@ public class Yum extends JavaPlugin {
if (tt != null) { if (tt != null) {
tt.cancel(); tt.cancel();
} }
task.scheduleAtFixedRate(tt = new MainThreadCheckTask(mainThread), 0, 5000); task.scheduleAtFixedRate(tt = new MainThreadCheckTask(mainThread), 0, 500);
} }
} }
} }

View File

@ -11,7 +11,6 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.command.SimpleCommandMap; import org.bukkit.command.SimpleCommandMap;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -31,6 +30,7 @@ import pw.yumc.YumCore.commands.CommandSub;
import pw.yumc.YumCore.commands.annotation.Async; import pw.yumc.YumCore.commands.annotation.Async;
import pw.yumc.YumCore.commands.annotation.Cmd; import pw.yumc.YumCore.commands.annotation.Cmd;
import pw.yumc.YumCore.commands.annotation.Help; import pw.yumc.YumCore.commands.annotation.Help;
import pw.yumc.YumCore.commands.annotation.Option;
import pw.yumc.YumCore.commands.interfaces.Executor; import pw.yumc.YumCore.commands.interfaces.Executor;
import pw.yumc.YumCore.kit.PKit; import pw.yumc.YumCore.kit.PKit;
import pw.yumc.YumCore.kit.StrKit; import pw.yumc.YumCore.kit.StrKit;
@ -60,7 +60,7 @@ public class MonitorCommand implements Executor {
private String lag = prefix + "§a当前服务器插件能耗如下§6(单位: %)"; private String lag = prefix + "§a当前服务器插件能耗如下§6(单位: %)";
private String lagprefix = " §6插件名称 §c主线程 §a命令 §b事件 §d任务"; private String lagprefix = " §6插件名称 §c主线程 §a命令 §b事件 §d任务";
private String laglist = "§6%-2s §b%-20s §c%-25s §a%-5.2f §b%-5.2f §d%-5.2f"; private String laglist = "§6%-2s §b%-18s §c%-25s §a%-5.2f §b%-5.2f §d%-5.2f";
private String no_error = prefix + "§a自服务器启动以来尚未发现报错!"; private String no_error = prefix + "§a自服务器启动以来尚未发现报错!";
private String last_error = prefix + "§c最后一次错误异常由 §b%s §c造成 详细如下:"; private String last_error = prefix + "§c最后一次错误异常由 §b%s §c造成 详细如下:";
@ -182,17 +182,19 @@ public class MonitorCommand implements Executor {
@Cmd(aliases = "l") @Cmd(aliases = "l")
@Help("查看插件总耗时") @Help("查看插件总耗时")
@Async @Async
public void lag(CommandSender sender, int size) { public void lag(CommandSender sender, @Option("def:8") int size) {
Map<String, Long> mm = MonitorManager.getMonitor(); Map<String, Long> mm = MonitorManager.getMonitor();
int max = 8;
sender.sendMessage(lag); sender.sendMessage(lag);
sender.sendMessage(lagprefix); sender.sendMessage(lagprefix);
int index = 0;
for (Entry<String, Long> entry : mm.entrySet()) { for (Entry<String, Long> entry : mm.entrySet()) {
if (++size > max) { if (++index > size) {
break; break;
} }
MonitorInfo mi = MonitorManager.getMonitorInfo(entry.getKey()); MonitorInfo mi = MonitorManager.getMonitorInfo(entry.getKey());
sender.sendMessage(String.format(laglist, size, entry.getKey(), getPer(sender, mi.monitor), mi.cmd, mi.event, mi.task)); if (mi.monitor != 0) {
sender.sendMessage(String.format(laglist, index, StrKit.substring(entry.getKey(), 0, 18), getPer(sender, mi.monitor), mi.cmd, mi.event, mi.task));
}
} }
} }
@ -209,11 +211,6 @@ public class MonitorCommand implements Executor {
lastError.printStackTrace(); lastError.printStackTrace();
} }
@Cmd
public void lk(CommandSender sender) {
MonitorManager.sendObject(sender);
}
@Cmd(aliases = "ri") @Cmd(aliases = "ri")
@Help("重载能耗监控器") @Help("重载能耗监控器")
public void reinject(CommandSender sender) { public void reinject(CommandSender sender) {
@ -279,7 +276,7 @@ public class MonitorCommand implements Executor {
} }
private String getPer(CommandSender sender, double per) { private String getPer(CommandSender sender, double per) {
String ps = sender instanceof Player ? "||" : "|"; String ps = "≡";
double p = per / 5; double p = per / 5;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (p < 3) { if (p < 3) {

View File

@ -81,6 +81,10 @@ public class ConfigManager {
return thread.getBoolean("MainThreadCheck", true); return thread.getBoolean("MainThreadCheck", true);
} }
public boolean isMainThreadDebug() {
return thread.getBoolean("Debug");
}
public boolean isMonitorDebug() { public boolean isMonitorDebug() {
return monitor.getBoolean("Debug"); return monitor.getBoolean("Debug");
} }

View File

@ -25,7 +25,7 @@ import pw.yumc.YumCore.kit.LogKit;
* @author * @author
*/ */
public class MonitorManager { public class MonitorManager {
public static String prefix = "§6[§a能耗监控§6] "; public static String prefix = "§6[§bYum §a能耗监控§6] ";
private static String errMsg = prefix + "§c命令执行异常 请反馈下列信息给腐竹!"; private static String errMsg = prefix + "§c命令执行异常 请反馈下列信息给腐竹!";
private static String errP = "§6插件名称: §b%s"; private static String errP = "§6插件名称: §b%s";
private static String errN = "§6异常名称: §c%s"; private static String errN = "§6异常名称: §c%s";
@ -104,7 +104,7 @@ public class MonitorManager {
int l = e.getStackTrace().length > 5 ? 5 : e.getStackTrace().length; int l = e.getStackTrace().length > 5 ? 5 : e.getStackTrace().length;
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
StackTraceElement ste = e.getStackTrace()[i]; StackTraceElement ste = e.getStackTrace()[i];
elog(String.format(errStackTrace, ste.getClassName(), ste.getMethodName(), ste.getFileName(), ste.getLineNumber())); elog(String.format(errStackTrace, ste.getClassName(), ste.getMethodName(), ste.getFileName() == null ? "未知" : ste.getFileName(), ste.getLineNumber()));
} }
if (debug) { if (debug) {
Log.console(devInfo); Log.console(devInfo);
@ -126,10 +126,6 @@ public class MonitorManager {
sender.sendMessage(String.format(errM, e.getMessage())); sender.sendMessage(String.format(errM, e.getMessage()));
} }
public static void sendObject(CommandSender sender) {
sender.sendMessage(String.format("totalTime@%s monitor@%s cmd@%s event@%s task@%s", totalTime, sum(monitor.values()), sum(cmd.values()), sum(event.values()), sum(task.values())));
}
/** /**
* 使 Mapvalue * 使 Mapvalue
* *

View File

@ -7,6 +7,7 @@ import java.util.TimerTask;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import pw.yumc.Yum.managers.ConfigManager;
import pw.yumc.YumCore.bukkit.Log; import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.bukkit.compatible.C; import pw.yumc.YumCore.bukkit.compatible.C;
import pw.yumc.YumCore.kit.PKit; import pw.yumc.YumCore.kit.PKit;
@ -20,13 +21,14 @@ import pw.yumc.YumCore.plugin.protocollib.PacketKit;
*/ */
public class MainThreadCheckTask extends TimerTask { public class MainThreadCheckTask extends TimerTask {
private static Method tickMethod; private static Method tickMethod;
private String prefix = "§6[§bYum §a线程管理§6] "; private String prefix = "§6[§a线程管理§6] ";
private String warnPNet = "§6插件 §b%s §c在主线程进行网络操作 §4服务器处于停止状态..."; private String warnPNet = "§6插件 §b%s §c在主线程进行网络操作 §4服务器处于停止状态...";
private String warnPIO = "§6插件 §b%s §c在主线程进行IO操作 §4服务器处于停止状态..."; private String warnPIO = "§6插件 §b%s §c在主线程进行IO操作 §4服务器处于停止状态...";
private String warnNet = "§c主线程存在网络操作 §4服务器处于停止状态..."; private String warnNet = "§c主线程存在网络操作 §4服务器处于停止状态...";
private String warnIO = "§c主线程存在IO操作 §4服务器处于停止状态..."; private String warnIO = "§c主线程存在IO操作 §4服务器处于停止状态...";
private String deliver = "§c服务器处于停止状态 已超过 %s 秒 激活心跳 防止线程关闭..."; private String deliver = "§c服务器处于停止状态 已超过 %s 秒 激活心跳 防止线程关闭...";
private int stopTime = 0; private String errStackTrace = " §e位于 §c%s.%s(§4%s:%s§c)";
private double stopTime = 0;
private Thread mainThread; private Thread mainThread;
static { static {
@ -46,6 +48,7 @@ public class MainThreadCheckTask extends TimerTask {
// According to this post the thread is still in Runnable although it's waiting for // According to this post the thread is still in Runnable although it's waiting for
// file/http ressources // file/http ressources
// https://stackoverflow.com/questions/20795295/why-jstack-out-says-thread-state-is-runnable-while-socketread // https://stackoverflow.com/questions/20795295/why-jstack-out-says-thread-state-is-runnable-while-socketread
String tip = null;
if (mainThread.getState() == State.RUNNABLE) { if (mainThread.getState() == State.RUNNABLE) {
// Based on this post we have to check the top element of the stack // Based on this post we have to check the top element of the stack
// https://stackoverflow.com/questions/20891386/how-to-detect-thread-being-blocked-by-io // https://stackoverflow.com/questions/20891386/how-to-detect-thread-being-blocked-by-io
@ -55,30 +58,29 @@ public class MainThreadCheckTask extends TimerTask {
// Socket/SQL (connect) - java.net.DualStackPlainSocketImpl.connect0 // Socket/SQL (connect) - java.net.DualStackPlainSocketImpl.connect0
// Socket/SQL (read) - java.net.SocketInputStream.socketRead0 // Socket/SQL (read) - java.net.SocketInputStream.socketRead0
// Socket/SQL (write) - java.net.SocketOutputStream.socketWrite0 // Socket/SQL (write) - java.net.SocketOutputStream.socketWrite0
if (isElementEqual(topElement, "java.net.DualStackPlainSocketImpl", "connect0") if (isElementEqual(topElement, "java.net.DualStackPlainSocketImpl", "connect0") || isElementEqual(topElement, "java.net.SocketInputStream", "socketRead0")
|| isElementEqual(topElement, "java.net.SocketInputStream", "socketRead0")
|| isElementEqual(topElement, "java.net.SocketOutputStream", "socketWrite0")) { || isElementEqual(topElement, "java.net.SocketOutputStream", "socketWrite0")) {
Plugin plugin = PKit.getOperatePlugin(stackTrace); Plugin plugin = PKit.getOperatePlugin(stackTrace);
if (plugin != null) { tip = plugin != null ? String.format(warnPNet, plugin.getName()) : warnNet;
Log.console(prefix + warnPNet, plugin.getName());
} else {
Log.console(prefix + warnNet);
}
tick();
} }
// File (in) - java.io.FileInputStream.readBytes // File (in) - java.io.FileInputStream.readBytes
// File (out) - java.io.FileOutputStream.writeBytes // File (out) - java.io.FileOutputStream.writeBytes
else if (isElementEqual(topElement, "java.io.FileInputStream", "readBytes") else if (isElementEqual(topElement, "java.io.FileInputStream", "readBytes") || isElementEqual(topElement, "java.io.FileOutputStream", "writeBytes")) {
|| isElementEqual(topElement, "java.io.FileOutputStream", "writeBytes")) {
Plugin plugin = PKit.getOperatePlugin(stackTrace); Plugin plugin = PKit.getOperatePlugin(stackTrace);
if (plugin != null) { tip = plugin != null ? String.format(warnPIO, plugin.getName()) : warnIO;
Log.console(prefix + warnPIO, plugin.getName()); }
} else { }
Log.console(prefix + warnIO); if (tip != null) {
tick();
if (stopTime > 1) {
Log.console(prefix + tip);
if (ConfigManager.i().isMainThreadDebug()) {
int l = stackTrace.length > 10 ? 10 : stackTrace.length;
for (int i = 0; i < l; i++) {
StackTraceElement ste = stackTrace[i];
Log.console(errStackTrace, ste.getClassName(), ste.getMethodName(), ste.getFileName() == null ? "未知" : ste.getFileName(), ste.getLineNumber());
}
} }
tick();
} else {
stopTime = 0;
} }
} else { } else {
stopTime = 0; stopTime = 0;
@ -91,8 +93,8 @@ public class MainThreadCheckTask extends TimerTask {
} }
private void tick() { private void tick() {
stopTime += 5; stopTime += 0.5;
if (stopTime >= 45) { if (stopTime >= 45 && stopTime % 5 == 0) {
Log.console(prefix + deliver, stopTime); Log.console(prefix + deliver, stopTime);
wttick(); wttick();
} }
@ -107,10 +109,10 @@ public class MainThreadCheckTask extends TimerTask {
tickMethod.invoke(null); tickMethod.invoke(null);
} }
for (final Player player : C.Player.getOnlinePlayers()) { for (final Player player : C.Player.getOnlinePlayers()) {
player.sendMessage("§4注意: §c服务器主线程处于停止状态 请等待操作完成!"); Log.sender(player, "§4注意: §c服务器主线程处于停止状态 请等待操作完成!");
PacketKit.keep_live(player); PacketKit.keep_live(player);
} }
} catch (final Throwable e) { } catch (final Throwable ignored) {
} }
} }
} }

View File

@ -3,9 +3,11 @@
############################ ############################
#配置版本号 请勿修改!!! #配置版本号 请勿修改!!!
Version: 1.0 Version: 1.1
#是否开启线程安全检测 #是否开启线程安全检测
ThreadSafe: true ThreadSafe: true
#是否开启主线程IO检测 #是否开启主线程IO检测
MainThreadCheck: true MainThreadCheck: true
#是否开启调试模式
Debug: false