diff --git a/pom.xml b/pom.xml index 11d90f2..2e0391f 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 pw.yumc Yum - 2.6.4 + 2.6.5 Yum Minecraft 服务器插件管理系统 @@ -60,6 +60,7 @@ &a全新 2.X 版本 更多守护与优化 + &b2.6.5 &6- &c修复list命令 &a添加全局能耗统计...; &b2.6.4 &6- &e添加从&bBukkitDev&e下载和更新...; &b2.6.3 &6- &a注入操作延时执行 防止部分任务未注册 添加手动注入...; &b2.6.2 &6- &d能耗监控添加忽略列表 &3详见monitor.yml...; diff --git a/src/main/java/pw/yumc/Yum/Yum.java b/src/main/java/pw/yumc/Yum/Yum.java index ff1c3ee..c9e456c 100644 --- a/src/main/java/pw/yumc/Yum/Yum.java +++ b/src/main/java/pw/yumc/Yum/Yum.java @@ -33,6 +33,7 @@ import pw.yumc.Yum.runnables.MainThreadCheckTask; * @since 2015年8月21日下午5:14:39 */ public class Yum extends JavaPlugin { + public static boolean disable = false;; public static Thread mainThread = null; public static Timer task = new Timer(); public static TimerTask tt; @@ -45,6 +46,7 @@ public class Yum extends JavaPlugin { @Override public void onDisable() { NetworkManager.unregister(); + disable = true; } @Override @@ -59,6 +61,10 @@ public class Yum extends JavaPlugin { new VersionChecker(this); YumAPI.updateRepo(Bukkit.getConsoleSender()); YumAPI.updateCheck(Bukkit.getConsoleSender()); + if (disable) { + YumAPI.updateInject(); + disable = false; + } } @Override diff --git a/src/main/java/pw/yumc/Yum/commands/MonitorCommand.java b/src/main/java/pw/yumc/Yum/commands/MonitorCommand.java index a828778..e6a98ae 100644 --- a/src/main/java/pw/yumc/Yum/commands/MonitorCommand.java +++ b/src/main/java/pw/yumc/Yum/commands/MonitorCommand.java @@ -32,6 +32,8 @@ import pw.yumc.Yum.inject.CommandInjector; import pw.yumc.Yum.inject.ListenerInjector; import pw.yumc.Yum.inject.TaskInjector; import pw.yumc.Yum.managers.ConfigManager; +import pw.yumc.Yum.managers.MonitorManager; +import pw.yumc.Yum.managers.MonitorManager.MonitorInfo; /** * @@ -49,16 +51,20 @@ public class MonitorCommand implements HandlerCommands { private final String avg = "§6平均耗时: §d%.5f毫秒!"; private final String avg_warn = "§6平均耗时: §c%.5f毫秒!"; - private final String injected = "§a插件 §b%s §a成功注入能耗监控器!"; - private final String uninjected = "§a插件 §b%s §a成功撤销能耗监控器!"; - private final String notEnable = "§c插件 §b%s §c未成功加载 无法执行注入!"; + private final String reinject = prefix + "§a能耗监控器重载完毕!"; + private final String injected = prefix + "§a插件 §b%s §a成功注入能耗监控器!"; + private final String uninjected = prefix + "§a插件 §b%s §a成功撤销能耗监控器!"; + private final String notEnable = prefix + "§c插件 §b%s §c未成功加载 无法执行注入!"; + + private final String lagprefix = "§6插件名称 §c主线程耗时 §a命令耗时 §b事件耗时 §d任务耗时"; + private final String laglist = "§b%-15s §c%-11.2f §a%-9.2f §b%-9.2f §d%-9.2f"; private final String no_error = prefix + "§a自服务器启动以来尚未发现报错!"; private final String last_error = prefix + "§c最后一次错误异常由 §b%s §c造成 详细如下:"; private final String p_n_f = prefix + "§c插件 §b%s §c不存在!"; - private final double um = 1000000.0; + private final double um = 1000000.00; public MonitorCommand(final Yum yum) { final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "monitor"); @@ -140,7 +146,7 @@ public class MonitorCommand implements HandlerCommands { } for (final String event : eventTotalTime.keySet()) { final StringBuffer str = new StringBuffer(); - str.append("§6- §e" + event + " "); + str.append(String.format("§6- §e%-25s ", event)); str.append(String.format(total, eventTotalTime.get(event) / um)); str.append(String.format(count, eventCount.get(event))); if (eventCount.get(event) != 0) { @@ -162,9 +168,24 @@ public class MonitorCommand implements HandlerCommands { } if (plugin.isEnabled()) { YumAPI.inject(plugin); - sender.sendMessage(String.format(prefix + injected, pname)); + sender.sendMessage(String.format(injected, pname)); } else { - sender.sendMessage(String.format(prefix + notEnable, pname)); + sender.sendMessage(String.format(notEnable, pname)); + } + } + + @HandlerCommand(name = "lag", aliases = "l", description = "查看插件总耗时") + public void lag(final InvokeCommandEvent e) { + final CommandSender sender = e.getSender(); + final Map mm = MonitorManager.getMonitor(); + int i = 0; + sender.sendMessage(lagprefix); + for (final Entry entry : mm.entrySet()) { + if (i++ > 5) { + break; + } + final MonitorInfo mi = MonitorManager.getMonitorInfo(entry.getKey()); + sender.sendMessage(String.format(laglist, entry.getKey(), mi.monitor, mi.cmd, mi.event, mi.task)); } } @@ -182,6 +203,13 @@ public class MonitorCommand implements HandlerCommands { } } + @HandlerCommand(name = "reinject", aliases = "i", description = "重载能耗监控器") + public void reinject(final InvokeCommandEvent e) { + final CommandSender sender = e.getSender(); + YumAPI.updateInject(); + sender.sendMessage(reinject); + } + @HandlerCommand(name = "task", description = "查看插件任务能耗", minimumArguments = 1, possibleArguments = "[插件名称]") public void task(final InvokeCommandEvent e) { final String pname = e.getArgs()[0]; @@ -199,8 +227,7 @@ public class MonitorCommand implements HandlerCommands { if (task instanceof TaskInjector) { final TaskInjector executor = (TaskInjector) task; final StringBuffer str = new StringBuffer(); - final Class taskName = executor.getOriginalTask().getClass(); - str.append("§6- §e" + (StrKit.isBlank(taskName.getSimpleName()) ? taskName.getName() : taskName.getSimpleName()) + " "); + str.append("§6- §e" + getClassName(executor.getOriginalTask().getClass()) + " "); str.append(String.format(total, executor.totalTime / um)); str.append(String.format(count, executor.count)); if (executor.count != 0) { @@ -223,7 +250,11 @@ public class MonitorCommand implements HandlerCommands { } if (plugin.isEnabled()) { YumAPI.uninject(plugin); - sender.sendMessage(String.format(prefix + uninjected, pname)); + sender.sendMessage(String.format(uninjected, pname)); } } + + private String getClassName(final Class clazz) { + return StrKit.isBlank(clazz.getSimpleName()) ? clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1) : clazz.getSimpleName(); + } } diff --git a/src/main/java/pw/yumc/Yum/commands/YumCommand.java b/src/main/java/pw/yumc/Yum/commands/YumCommand.java index 2a9207c..0e2bb1a 100644 --- a/src/main/java/pw/yumc/Yum/commands/YumCommand.java +++ b/src/main/java/pw/yumc/Yum/commands/YumCommand.java @@ -253,7 +253,9 @@ public class YumCommand implements HandlerCommands, Listener { fm.then(unload).command("yum unload " + pname); fm.then(" "); fm.then(reload).command("yum re " + pname); + fm.then(" "); fm.then(delete).command("yum del " + pname); + fm.send(sender); } } diff --git a/src/main/java/pw/yumc/Yum/inject/CommandInjector.java b/src/main/java/pw/yumc/Yum/inject/CommandInjector.java index 2c86199..45c3cf3 100644 --- a/src/main/java/pw/yumc/Yum/inject/CommandInjector.java +++ b/src/main/java/pw/yumc/Yum/inject/CommandInjector.java @@ -18,6 +18,7 @@ import cn.citycraft.PluginHelper.ext.kit.Reflect; import cn.citycraft.PluginHelper.kit.PluginKit; import cn.citycraft.PluginHelper.kit.StrKit; import pw.yumc.Yum.commands.MonitorCommand; +import pw.yumc.Yum.managers.MonitorManager; public class CommandInjector implements TabExecutor { private final String prefix = "§6[§bYum §a命令监控§6] "; @@ -43,11 +44,13 @@ public class CommandInjector implements TabExecutor { final PluginCommand pluginCommand = (PluginCommand) command; final Plugin plugin = pluginCommand.getPlugin(); if (plugin.equals(toInjectPlugin)) { - final CommandExecutor executor = Reflect.on(command).get("executor"); + CommandExecutor executor = Reflect.on(command).get("executor"); + TabCompleter completer = Reflect.on(command).get("completer");; if (executor instanceof CommandInjector) { - return; + final CommandInjector cInjector = (CommandInjector) executor; + executor = cInjector.getOriginalExecutor(); + completer = cInjector.getOriginalCompleter(); } - final TabCompleter completer = Reflect.on(command).get("completer"); final CommandInjector commandInjector = new CommandInjector(executor, completer, toInjectPlugin); Reflect.on(command).set("executor", commandInjector); Reflect.on(command).set("completer", commandInjector); @@ -100,6 +103,7 @@ public class CommandInjector implements TabExecutor { } totalTime += lag; count++; + MonitorManager.addCmd(plugin.getName(), lag); return result; } catch (Throwable e) { while (e.getCause() != null) { diff --git a/src/main/java/pw/yumc/Yum/inject/ListenerInjector.java b/src/main/java/pw/yumc/Yum/inject/ListenerInjector.java index 206f847..1c9731d 100644 --- a/src/main/java/pw/yumc/Yum/inject/ListenerInjector.java +++ b/src/main/java/pw/yumc/Yum/inject/ListenerInjector.java @@ -17,6 +17,7 @@ import cn.citycraft.PluginHelper.ext.kit.Reflect; import cn.citycraft.PluginHelper.kit.PluginKit; import pw.yumc.Yum.commands.MonitorCommand; import pw.yumc.Yum.managers.ConfigManager; +import pw.yumc.Yum.managers.MonitorManager; public class ListenerInjector implements EventExecutor { private final String prefix = "§6[§bYum §a事件监控§6] "; @@ -40,9 +41,9 @@ public class ListenerInjector implements EventExecutor { if (listener instanceof TimedRegisteredListener) { return; } - final EventExecutor originalExecutor = Reflect.on(listener).get("executor"); + EventExecutor originalExecutor = Reflect.on(listener).get("executor"); if (originalExecutor instanceof ListenerInjector) { - return; + originalExecutor = ((ListenerInjector) originalExecutor).getOriginalExecutor(); } final ListenerInjector listenerInjector = new ListenerInjector(originalExecutor, plugin); Reflect.on(listener).set("executor", listenerInjector); @@ -82,6 +83,7 @@ public class ListenerInjector implements EventExecutor { eventTotalTime.put(en, end - start); eventCount.put(en, 1); } + MonitorManager.addEvent(plugin.getName(), lag); } else { originalExecutor.execute(listener, event); } diff --git a/src/main/java/pw/yumc/Yum/inject/TaskInjector.java b/src/main/java/pw/yumc/Yum/inject/TaskInjector.java index cfc13d4..c569c46 100644 --- a/src/main/java/pw/yumc/Yum/inject/TaskInjector.java +++ b/src/main/java/pw/yumc/Yum/inject/TaskInjector.java @@ -11,6 +11,7 @@ import cn.citycraft.PluginHelper.ext.kit.Reflect; import cn.citycraft.PluginHelper.kit.PluginKit; import cn.citycraft.PluginHelper.kit.StrKit; import pw.yumc.Yum.commands.MonitorCommand; +import pw.yumc.Yum.managers.MonitorManager; public class TaskInjector implements Runnable { private final String prefix = "§6[§bYum §a任务监控§6] "; @@ -38,9 +39,9 @@ public class TaskInjector implements Runnable { for (final BukkitTask pendingTask : pendingTasks) { // 忽略异步任务 if (pendingTask.isSync() && pendingTask.getOwner().equals(plugin)) { - final Runnable originalTask = Reflect.on(pendingTask).get("task"); + Runnable originalTask = Reflect.on(pendingTask).get("task"); if (originalTask instanceof TaskInjector) { - return; + originalTask = ((TaskInjector) originalTask).getOriginalTask(); } final TaskInjector taskInjector = new TaskInjector(originalTask, plugin); Reflect.on(pendingTask).set("task", taskInjector); @@ -80,6 +81,7 @@ public class TaskInjector implements Runnable { } totalTime += lag; count++; + MonitorManager.addTask(plugin.getName(), lag); } catch (Throwable e) { while (e.getCause() != null) { e = e.getCause(); diff --git a/src/main/java/pw/yumc/Yum/listeners/PluginListener.java b/src/main/java/pw/yumc/Yum/listeners/PluginListener.java index 11eabb8..1da56f7 100644 --- a/src/main/java/pw/yumc/Yum/listeners/PluginListener.java +++ b/src/main/java/pw/yumc/Yum/listeners/PluginListener.java @@ -9,6 +9,7 @@ import org.bukkit.event.server.PluginEnableEvent; import cn.citycraft.PluginHelper.kit.PKit; import cn.citycraft.PluginHelper.kit.PluginKit; import pw.yumc.Yum.api.YumAPI; +import pw.yumc.Yum.managers.MonitorManager; /** * @@ -29,6 +30,7 @@ public class PluginListener implements Listener { @EventHandler public void onPluginEnable(final PluginEnableEvent e) { + MonitorManager.reset(e.getPlugin().getName()); PluginKit.runTaskLater(new Runnable() { @Override public void run() { diff --git a/src/main/java/pw/yumc/Yum/managers/MonitorManager.java b/src/main/java/pw/yumc/Yum/managers/MonitorManager.java new file mode 100644 index 0000000..b7c46b0 --- /dev/null +++ b/src/main/java/pw/yumc/Yum/managers/MonitorManager.java @@ -0,0 +1,98 @@ +package pw.yumc.Yum.managers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @since 2016年7月19日 下午3:55:54 + * @author 喵♂呜 + */ +public class MonitorManager { + private static Map monitor = new HashMap<>(); + private static Map task = new HashMap<>(); + private static Map event = new HashMap<>(); + private static Map cmd = new HashMap<>(); + + private final static double um = 1000000.00; + + public static void addCmd(final String pname, final long time) { + monitor.put(pname, monitor.get(pname) + time); + cmd.put(pname, cmd.get(pname) + time); + } + + public static void addEvent(final String pname, final long time) { + monitor.put(pname, monitor.get(pname) + time); + event.put(pname, event.get(pname) + time); + } + + public static void addTask(final String pname, final long time) { + monitor.put(pname, monitor.get(pname) + time); + task.put(pname, task.get(pname) + time); + } + + public static Map getMonitor() { + return sortMapByValue(monitor); + } + + public static MonitorInfo getMonitorInfo(final String pname) { + return new MonitorInfo(monitor.get(pname) / um, cmd.get(pname) / um, event.get(pname) / um, task.get(pname) / um); + } + + public static void reset(final String pname) { + monitor.put(pname, 0L); + task.put(pname, 0L); + event.put(pname, 0L); + cmd.put(pname, 0L); + } + + /** + * 使用 Map按value进行排序 + * + * @param map + * @return + */ + public static Map sortMapByValue(final Map oriMap) { + if (oriMap == null || oriMap.isEmpty()) { + return null; + } + final Map sortedMap = new LinkedHashMap(); + final List> entryList = new ArrayList>(oriMap.entrySet()); + Collections.sort(entryList, new MonitorComparator()); + final Iterator> iter = entryList.iterator(); + Entry tmpEntry = null; + while (iter.hasNext()) { + tmpEntry = iter.next(); + sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue()); + } + return sortedMap; + } + + public static class MonitorInfo { + public double monitor; + public double cmd; + public double event; + public double task; + + public MonitorInfo(final double monitor, final double cmd, final double event, final double task) { + this.monitor = monitor; + this.cmd = cmd; + this.event = event; + this.task = task; + } + } + + static class MonitorComparator implements Comparator> { + @Override + public int compare(final Entry o1, final Entry o2) { + return o2.getValue().compareTo(o1.getValue()); + } + } +}