diff options
Diffstat (limited to 'spark-common/src/main/java')
9 files changed, 390 insertions, 197 deletions
diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java index 7a33c39..6b3eb21 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java +++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java @@ -33,6 +33,10 @@ import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.monitor.tick.TpsCalculator; import me.lucko.spark.common.sampler.TickCounter; import me.lucko.spark.common.util.BytebinClient; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; import okhttp3.OkHttpClient; import java.util.ArrayList; @@ -116,7 +120,7 @@ public class SparkPlatform<S> { command.executor().execute(this, sender, resp, new Arguments(rawArgs)); } catch (IllegalArgumentException e) { e.printStackTrace(); - resp.replyPrefixed("&c" + e.getMessage()); + resp.replyPrefixed(TextComponent.of(e.getMessage(), TextColor.RED)); } return; } @@ -146,14 +150,36 @@ public class SparkPlatform<S> { } private void sendUsage(CommandResponseHandler<S> sender) { - sender.replyPrefixed("&fspark &7v" + getPlugin().getVersion()); + sender.replyPrefixed(TextComponent.builder() + .append(TextComponent.of("spark", TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("v" + getPlugin().getVersion(), TextColor.GRAY)) + .build() + ); for (Command<S> command : this.commands) { - sender.reply("&6&l> &7/" + getPlugin().getLabel() + " " + command.aliases().get(0)); + sender.reply(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.GOLD).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("/" + getPlugin().getLabel() + " " + command.aliases().get(0), TextColor.GRAY)) + .build() + ); for (Command.ArgumentInfo arg : command.arguments()) { if (arg.requiresParameter()) { - sender.reply(" &8[&7--" + arg.argumentName() + "&8 <" + arg.parameterDescription() + ">]"); + sender.reply(TextComponent.builder(" ") + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY)) + .append(Component.space()) + .append(TextComponent.of("<" + arg.parameterDescription() + ">", TextColor.DARK_GRAY)) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build() + ); } else { - sender.reply(" &8[&7--" + arg.argumentName() + "]"); + sender.reply(TextComponent.builder(" ") + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY)) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build() + ); } } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java index 481a615..19eb3d3 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java +++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java @@ -22,6 +22,7 @@ package me.lucko.spark.common; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.sampler.TickCounter; +import net.kyori.text.Component; import java.nio.file.Path; import java.util.Set; @@ -36,9 +37,7 @@ public interface SparkPlugin<S> { Set<S> getSendersWithPermission(String permission); - void sendMessage(S sender, String message); - - void sendLink(S sender, String url); + void sendMessage(S sender, Component message); void runAsync(Runnable r); diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java b/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java index 9d604bd..94e1946 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java @@ -21,14 +21,24 @@ package me.lucko.spark.common.command; import me.lucko.spark.common.SparkPlatform; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; import java.util.Set; import java.util.function.Consumer; public class CommandResponseHandler<S> { - /** The prefix used in all messages */ - private static final String PREFIX = "&8[&e&l⚡&8] &7"; + /** The prefix used in all messages "&8[&e&l⚡&8] &7" */ + private static final TextComponent PREFIX = TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(TextComponent.builder("⚡").color(TextColor.YELLOW).decoration(TextDecoration.BOLD, TextDecoration.State.TRUE).build()) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .append(TextComponent.of(" ")) + .build(); private final SparkPlatform<S> platform; private final S sender; @@ -48,28 +58,21 @@ public class CommandResponseHandler<S> { senders.forEach(action); } - public void reply(String message) { + public void reply(Component message) { this.platform.getPlugin().sendMessage(this.sender, message); } - public void broadcast(String message) { + public void broadcast(Component message) { allSenders(sender -> this.platform.getPlugin().sendMessage(sender, message)); } - public void replyPrefixed(String message) { - this.platform.getPlugin().sendMessage(this.sender, PREFIX + message); + public void replyPrefixed(Component message) { + reply(PREFIX.append(message)); } - public void broadcastPrefixed(String message) { - allSenders(sender -> this.platform.getPlugin().sendMessage(sender, PREFIX + message)); + public void broadcastPrefixed(Component message) { + broadcast(PREFIX.append(message)); } - public void replyLink(String link) { - this.platform.getPlugin().sendLink(this.sender, link); - } - - public void broadcastLink(String link) { - allSenders(sender -> this.platform.getPlugin().sendLink(sender, link)); - } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java index 66cee54..097d264 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java @@ -26,6 +26,10 @@ import me.lucko.spark.common.command.CommandModule; import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.monitor.cpu.CpuMonitor; import me.lucko.spark.common.monitor.tick.TpsCalculator; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; import java.io.IOException; import java.lang.management.ManagementFactory; @@ -45,50 +49,77 @@ public class HealthModule<S> implements CommandModule<S> { @Override public void registerCommands(Consumer<Command<S>> consumer) { consumer.accept(Command.<S>builder() - .aliases("tps") - .executor((platform, sender, resp, arguments) -> { - TpsCalculator tpsCalculator = platform.getTpsCalculator(); - if (tpsCalculator != null) { - resp.replyPrefixed("TPS from last 5s, 10s, 1m, 5m, 15m:"); - resp.replyPrefixed(" " + tpsCalculator.toFormattedString()); - } else { - resp.replyPrefixed("Not supported!"); - } - }) - .tabCompleter(Command.TabCompleter.empty()) - .build() + .aliases("tps") + .executor((platform, sender, resp, arguments) -> { + TpsCalculator tpsCalculator = platform.getTpsCalculator(); + if (tpsCalculator != null) { + resp.replyPrefixed(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:")); + resp.replyPrefixed(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build()); + } else { + resp.replyPrefixed(TextComponent.of("Not supported!")); + } + }) + .tabCompleter(Command.TabCompleter.empty()) + .build() ); consumer.accept(Command.<S>builder() .aliases("healthreport", "health", "ht") .argumentUsage("memory", null) .executor((platform, sender, resp, arguments) -> { - resp.replyPrefixed("&7Generating server health report..."); + resp.replyPrefixed(TextComponent.of("Generating server health report...")); platform.getPlugin().runAsync(() -> { - List<String> report = new ArrayList<>(15); - report.add(""); + List<Component> report = new ArrayList<>(15); + report.add(Component.empty()); TpsCalculator tpsCalculator = platform.getTpsCalculator(); if (tpsCalculator != null) { - report.add("&8&l>&6 TPS from last 5s, 10s, 1m, 5m, 15m:"); - report.add(" " + tpsCalculator.toFormattedString()); - report.add(""); + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:", TextColor.GOLD)) + .build() + ); + report.add(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build()); + report.add(Component.empty()); } MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); - MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage(); - report.add("&8&l>&6 Memory usage: "); - report.add(" &f" + formatBytes(heapUsage.getUsed()) + " &7/ &f" + formatBytes(heapUsage.getMax()) + - " &7(&a" + percent(heapUsage.getUsed(), heapUsage.getMax()) + "&7)"); - report.add(" " + generateMemoryUsageDiagram(heapUsage, 40)); - report.add(""); + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("Memory usage:", TextColor.GOLD)) + .build() + ); + report.add(TextComponent.builder(" ") + .append(TextComponent.of(formatBytes(heapUsage.getUsed()), TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("/", TextColor.GRAY)) + .append(Component.space()) + .append(TextComponent.of(formatBytes(heapUsage.getMax()), TextColor.WHITE)) + .append(TextComponent.of(" ")) + .append(TextComponent.of("(", TextColor.GRAY)) + .append(TextComponent.of(percent(heapUsage.getUsed(), heapUsage.getMax()), TextColor.GREEN)) + .append(TextComponent.of(")", TextColor.GRAY)) + .build() + ); + report.add(TextComponent.builder(" ").append(generateMemoryUsageDiagram(heapUsage, 40)).build()); + report.add(Component.empty()); if (arguments.boolFlag("memory")) { MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage(); - report.add("&8&l>&6 Non-heap memory usage: "); - report.add(" &f" + formatBytes(nonHeapUsage.getUsed())); - report.add(""); + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("Non-heap memory usage:", TextColor.GOLD)) + .build() + ); + report.add(TextComponent.builder(" ") + .append(TextComponent.of(formatBytes(nonHeapUsage.getUsed()), TextColor.WHITE)) + .build() + ); + report.add(Component.empty()); List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean memoryPool : memoryPoolMXBeans) { @@ -103,16 +134,37 @@ public class HealthModule<S> implements CommandModule<S> { usage = new MemoryUsage(usage.getInit(), usage.getUsed(), usage.getCommitted(), usage.getCommitted()); } - report.add("&8&l>&6 " + memoryPool.getName() + " pool usage: "); - report.add(" &f" + formatBytes(usage.getUsed()) + " &7/ &f" + formatBytes(usage.getMax()) + - " &7(&a" + percent(usage.getUsed(), usage.getMax()) + "&7)"); - report.add(" " + generateMemoryPoolDiagram(usage, collectionUsage,40)); - + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of(memoryPool.getName() + " pool usage:", TextColor.GOLD)) + .build() + ); + report.add(TextComponent.builder(" ") + .append(TextComponent.of(formatBytes(usage.getUsed()), TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("/", TextColor.GRAY)) + .append(Component.space()) + .append(TextComponent.of(formatBytes(usage.getMax()), TextColor.WHITE)) + .append(TextComponent.of(" ")) + .append(TextComponent.of("(", TextColor.GRAY)) + .append(TextComponent.of(percent(usage.getUsed(), usage.getMax()), TextColor.GREEN)) + .append(TextComponent.of(")", TextColor.GRAY)) + .build() + ); + report.add(TextComponent.builder(" ").append(generateMemoryPoolDiagram(usage, collectionUsage, 40)).build()); if (collectionUsage != null) { - report.add(" &c- &7Usage at last GC: &f" + formatBytes(collectionUsage.getUsed())); + report.add(TextComponent.builder(" ") + .append(TextComponent.of("-", TextColor.RED)) + .append(Component.space()) + .append(TextComponent.of("Usage at last GC:", TextColor.GRAY)) + .append(Component.space()) + .append(TextComponent.of(formatBytes(collectionUsage.getUsed()), TextColor.WHITE)) + .build() + ); } - report.add(""); + report.add(Component.empty()); } } @@ -120,17 +172,30 @@ public class HealthModule<S> implements CommandModule<S> { double processCpuLoad = CpuMonitor.getProcessCpuLoad(); if (systemCpuLoad >= 0 || processCpuLoad >= 0) { - report.add("&8&l>&6 CPU usage: "); + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("CPU usage:", TextColor.GOLD)) + .build() + ); if (systemCpuLoad >= 0) { - report.add(" &7System: &a" + percent(systemCpuLoad, 1.0d)); - report.add(" " + generateCpuUsageDiagram(systemCpuLoad, 40)); - report.add(""); + report.add(TextComponent.builder(" ") + .append(TextComponent.of("System: ", TextColor.GRAY)) + .append(TextComponent.of(percent(systemCpuLoad, 1.0d), TextColor.GREEN)) + .build() + ); + report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(systemCpuLoad, 40)).build()); + report.add(Component.empty()); } if (processCpuLoad >= 0) { - report.add(" &7Process: &a" + percent(processCpuLoad, 1.0d)); - report.add(" " + generateCpuUsageDiagram(processCpuLoad, 40)); - report.add(""); + report.add(TextComponent.builder(" ") + .append(TextComponent.of("Process: ", TextColor.GRAY)) + .append(TextComponent.of(percent(processCpuLoad, 1.0d), TextColor.GREEN)) + .build() + ); + report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(processCpuLoad, 40)).build()); + report.add(Component.empty()); } } @@ -138,17 +203,33 @@ public class HealthModule<S> implements CommandModule<S> { FileStore fileStore = Files.getFileStore(Paths.get(".")); long totalSpace = fileStore.getTotalSpace(); long usedSpace = totalSpace - fileStore.getUsableSpace(); - - report.add("&8&l>&6 Disk usage: "); - report.add(" &f" + formatBytes(usedSpace) + " &7/ &f" + formatBytes(totalSpace) + - " &7(&a" + percent(usedSpace, totalSpace) + "&7)"); - report.add(" " + generateDiskUsageDiagram(usedSpace, totalSpace, 40)); - report.add(""); + report.add(TextComponent.builder() + .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) + .append(Component.space()) + .append(TextComponent.of("Disk usage:", TextColor.GOLD)) + .build() + ); + report.add(TextComponent.builder(" ") + .append(TextComponent.of(formatBytes(usedSpace), TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("/", TextColor.GRAY)) + .append(Component.space()) + .append(TextComponent.of(formatBytes(totalSpace), TextColor.WHITE)) + .append(TextComponent.of(" ")) + .append(TextComponent.of("(", TextColor.GRAY)) + .append(TextComponent.of(percent(usedSpace, totalSpace), TextColor.GREEN)) + .append(TextComponent.of(")", TextColor.GRAY)) + .build() + ); + report.add(TextComponent.builder(" ").append(generateDiskUsageDiagram(usedSpace, totalSpace, 40)).build()); + report.add(Component.empty()); } catch (IOException e) { e.printStackTrace(); } - report.forEach(resp::reply); + TextComponent.Builder builder = TextComponent.builder(); + report.forEach(line -> builder.append(line).append(Component.newline())); + resp.reply(builder.build()); }); }) .tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--memory")) @@ -161,7 +242,7 @@ public class HealthModule<S> implements CommandModule<S> { return (int) percent + "%"; } - private static String generateMemoryUsageDiagram(MemoryUsage usage, int length) { + private static TextComponent generateMemoryUsageDiagram(MemoryUsage usage, int length) { double used = usage.getUsed(); double committed = usage.getCommitted(); double max = usage.getMax(); @@ -169,18 +250,23 @@ public class HealthModule<S> implements CommandModule<S> { int usedChars = (int) ((used * length) / max); int committedChars = (int) ((committed * length) / max); - String line = "&7" + Strings.repeat("/", usedChars); + TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", usedChars)).color(TextColor.GRAY); if (committedChars > usedChars) { - line += Strings.repeat(" ", (committedChars - usedChars) - 1) + "&e|"; + line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1))); + line.append(TextComponent.of("|", TextColor.YELLOW)); } if (length > committedChars) { - line += Strings.repeat(" ", (length - committedChars)); + line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars)))); } - return "&8[" + line + "&8]"; + return TextComponent.builder() + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(line.build()) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build(); } - private static String generateMemoryPoolDiagram(MemoryUsage usage, MemoryUsage collectionUsage, int length) { + private static TextComponent generateMemoryPoolDiagram(MemoryUsage usage, MemoryUsage collectionUsage, int length) { double used = usage.getUsed(); double collectionUsed = used; if (collectionUsage != null) { @@ -193,32 +279,45 @@ public class HealthModule<S> implements CommandModule<S> { int collectionUsedChars = (int) ((collectionUsed * length) / max); int committedChars = (int) ((committed * length) / max); - String line = "&7" + Strings.repeat("/", collectionUsedChars); + TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", collectionUsedChars)).color(TextColor.GRAY); + if (usedChars > collectionUsedChars) { - line += "&c|&7" + Strings.repeat("/", (usedChars - collectionUsedChars) - 1); + line.append(TextComponent.of("|", TextColor.RED)); + line.append(TextComponent.of(Strings.repeat("/", (usedChars - collectionUsedChars) - 1), TextColor.GRAY)); } if (committedChars > usedChars) { - line += Strings.repeat(" ", (committedChars - usedChars) - 1) + "&e|"; + line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1))); + line.append(TextComponent.of("|", TextColor.YELLOW)); } if (length > committedChars) { - line += Strings.repeat(" ", (length - committedChars)); + line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars)))); } - return "&8[" + line + "&8]"; + return TextComponent.builder() + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(line.build()) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build(); } - private static String generateCpuUsageDiagram(double usage, int length) { + private static TextComponent generateCpuUsageDiagram(double usage, int length) { int usedChars = (int) ((usage * length)); - - String line = "&7" + Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars); - return "&8[" + line + "&8]"; + String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars); + return TextComponent.builder() + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(TextComponent.of(line, TextColor.GRAY)) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build(); } - private static String generateDiskUsageDiagram(double used, double max, int length) { + private static TextComponent generateDiskUsageDiagram(double used, double max, int length) { int usedChars = (int) ((used * length) / max); - - String line = "&7" + Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars); - return "&8[" + line + "&8]"; + String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars); + return TextComponent.builder() + .append(TextComponent.of("[", TextColor.DARK_GRAY)) + .append(TextComponent.of(line, TextColor.GRAY)) + .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .build(); } private static String formatBytes(long bytes) { diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java index 583b1b6..e2d817d 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java @@ -26,6 +26,9 @@ import me.lucko.spark.common.command.CommandModule; import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.heapdump.HeapDump; import me.lucko.spark.common.heapdump.HeapDumpSummary; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; import okhttp3.MediaType; import java.io.IOException; @@ -45,32 +48,38 @@ public class MemoryModule<S> implements CommandModule<S> { .argumentUsage("run-gc-before", null) .executor((platform, sender, resp, arguments) -> { platform.getPlugin().runAsync(() -> { - if (arguments.boolFlag("run-gc-before")) { - resp.broadcastPrefixed("&7Running garbage collector..."); - System.gc(); - } - - resp.broadcastPrefixed("&7Creating a new heap dump summary, please wait..."); - - HeapDumpSummary heapDump; - try { - heapDump = HeapDumpSummary.createNew(); - } catch (Exception e) { - resp.broadcastPrefixed("&cAn error occurred whilst inspecting the heap."); - e.printStackTrace(); - return; - } - - byte[] output = heapDump.formCompressedDataPayload(); - try { - String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key(); - resp.broadcastPrefixed("&6Heap dump summmary output:"); - resp.broadcastLink(SparkPlatform.VIEWER_URL + key); - } catch (IOException e) { - resp.broadcastPrefixed("&cAn error occurred whilst uploading the data."); - e.printStackTrace(); - } - }); + if (arguments.boolFlag("run-gc-before")) { + resp.broadcastPrefixed(TextComponent.of("Running garbage collector...")); + System.gc(); + } + + resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump summary, please wait...")); + + HeapDumpSummary heapDump; + try { + heapDump = HeapDumpSummary.createNew(); + } catch (Exception e) { + resp.broadcastPrefixed(TextComponent.of("An error occurred whilst inspecting the heap.", TextColor.RED)); + e.printStackTrace(); + return; + } + + byte[] output = heapDump.formCompressedDataPayload(); + try { + String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key(); + String url = SparkPlatform.VIEWER_URL + key; + + resp.broadcastPrefixed(TextComponent.of("Heap dump summmary output:", TextColor.GOLD)); + resp.broadcast(TextComponent.builder(url) + .color(TextColor.GRAY) + .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)) + .build() + ); + } catch (IOException e) { + resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the data.", TextColor.RED)); + e.printStackTrace(); + } + }); }) .tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--run-gc-before")) .build() @@ -81,35 +90,34 @@ public class MemoryModule<S> implements CommandModule<S> { .argumentUsage("run-gc-before", null) .argumentUsage("include-non-live", null) .executor((platform, sender, resp, arguments) -> { - // ignore platform.getPlugin().runAsync(() -> { - Path pluginFolder = platform.getPlugin().getPluginFolder(); - try { - Files.createDirectories(pluginFolder); - } catch (IOException e) { - // ignore - } - - Path file = pluginFolder.resolve("heap-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + (HeapDump.isOpenJ9() ? ".phd" : ".hprof")); - boolean liveOnly = !arguments.boolFlag("include-non-live"); - - if (arguments.boolFlag("run-gc-before")) { - resp.broadcastPrefixed("&7Running garbage collector..."); - System.gc(); - } - - resp.broadcastPrefixed("&7Creating a new heap dump, please wait..."); - - try { - HeapDump.dumpHeap(file, liveOnly); - } catch (Exception e) { - resp.broadcastPrefixed("&cAn error occurred whilst creating a heap dump."); - e.printStackTrace(); - return; - } - - resp.broadcastPrefixed("&6Heap dump written to: " + file.toString()); - }); + Path pluginFolder = platform.getPlugin().getPluginFolder(); + try { + Files.createDirectories(pluginFolder); + } catch (IOException e) { + // ignore + } + + Path file = pluginFolder.resolve("heap-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + (HeapDump.isOpenJ9() ? ".phd" : ".hprof")); + boolean liveOnly = !arguments.boolFlag("include-non-live"); + + if (arguments.boolFlag("run-gc-before")) { + resp.broadcastPrefixed(TextComponent.of("Running garbage collector...")); + System.gc(); + } + + resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump, please wait...")); + + try { + HeapDump.dumpHeap(file, liveOnly); + } catch (Exception e) { + resp.broadcastPrefixed(TextComponent.of("An error occurred whilst creating a heap dump.", TextColor.RED)); + e.printStackTrace(); + return; + } + + resp.broadcastPrefixed(TextComponent.of("Heap dump written to: " + file.toString(), TextColor.GOLD)); + }); }) .tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--run-gc-before", "--include-non-live")) .build() diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java index 88430f9..e450b0b 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java @@ -31,6 +31,9 @@ import me.lucko.spark.common.sampler.SamplerBuilder; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.sampler.ThreadGrouper; import me.lucko.spark.common.sampler.TickCounter; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; import okhttp3.MediaType; import java.io.IOException; @@ -70,18 +73,18 @@ public class SamplerModule<S> implements CommandModule<S> { if (arguments.boolFlag("info")) { synchronized (this.activeSamplerMutex) { if (this.activeSampler == null) { - resp.replyPrefixed("&7There isn't an active sampling task running."); + resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); } else { long timeout = this.activeSampler.getEndTime(); if (timeout == -1) { - resp.replyPrefixed("&7There is an active sampler currently running, with no defined timeout."); + resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, with no defined timeout.")); } else { long timeoutDiff = (timeout - System.currentTimeMillis()) / 1000L; - resp.replyPrefixed("&7There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds."); + resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds.")); } long runningTime = (System.currentTimeMillis() - this.activeSampler.getStartTime()) / 1000L; - resp.replyPrefixed("&7It has been sampling for " + runningTime + " seconds so far."); + resp.replyPrefixed(TextComponent.of("It has been sampling for " + runningTime + " seconds so far.")); } } return; @@ -90,11 +93,11 @@ public class SamplerModule<S> implements CommandModule<S> { if (arguments.boolFlag("cancel")) { synchronized (this.activeSamplerMutex) { if (this.activeSampler == null) { - resp.replyPrefixed("&7There isn't an active sampling task running."); + resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); } else { this.activeSampler.cancel(); this.activeSampler = null; - resp.broadcastPrefixed("&6The active sampling task has been cancelled."); + resp.broadcastPrefixed(TextComponent.of("The active sampling task has been cancelled.", TextColor.GOLD)); } } return; @@ -103,10 +106,10 @@ public class SamplerModule<S> implements CommandModule<S> { if (arguments.boolFlag("stop") || arguments.boolFlag("upload")) { synchronized (this.activeSamplerMutex) { if (this.activeSampler == null) { - resp.replyPrefixed("&7There isn't an active sampling task running."); + resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); } else { this.activeSampler.cancel(); - resp.broadcastPrefixed("&7The active sampling operation has been stopped! Uploading results..."); + resp.broadcastPrefixed(TextComponent.of("The active sampling operation has been stopped! Uploading results...")); handleUpload(platform, resp, this.activeSampler); this.activeSampler = null; } @@ -116,12 +119,14 @@ public class SamplerModule<S> implements CommandModule<S> { int timeoutSeconds = arguments.intFlag("timeout"); if (timeoutSeconds != -1 && timeoutSeconds <= 10) { - resp.replyPrefixed("&cThe specified timeout is not long enough for accurate results to be formed. Please choose a value greater than 10."); + resp.replyPrefixed(TextComponent.of("The specified timeout is not long enough for accurate results to be formed. " + + "Please choose a value greater than 10.", TextColor.RED)); return; } if (timeoutSeconds != -1 && timeoutSeconds < 30) { - resp.replyPrefixed("&7The accuracy of the output will significantly improve when sampling is able to run for longer periods. Consider setting a timeout value over 30 seconds."); + resp.replyPrefixed(TextComponent.of("The accuracy of the output will significantly improve when sampling is able to run for longer periods. " + + "Consider setting a timeout value over 30 seconds.")); } double intervalMillis = arguments.doubleFlag("interval"); @@ -161,7 +166,7 @@ public class SamplerModule<S> implements CommandModule<S> { if (ticksOver != -1) { tickCounter = platform.getTickCounter(); if (tickCounter == null) { - resp.replyPrefixed("&cTick counting is not supported!"); + resp.replyPrefixed(TextComponent.of("Tick counting is not supported!", TextColor.RED)); return; } } @@ -169,11 +174,11 @@ public class SamplerModule<S> implements CommandModule<S> { Sampler sampler; synchronized (this.activeSamplerMutex) { if (this.activeSampler != null) { - resp.replyPrefixed("&7An active sampler is already running."); + resp.replyPrefixed(TextComponent.of("An active sampler is already running.")); return; } - resp.broadcastPrefixed("&7Initializing a new profiler, please wait..."); + resp.broadcastPrefixed(TextComponent.of("Initializing a new profiler, please wait...")); SamplerBuilder builder = new SamplerBuilder(); builder.threadDumper(threadDumper); @@ -188,11 +193,11 @@ public class SamplerModule<S> implements CommandModule<S> { } sampler = this.activeSampler = builder.start(); - resp.broadcastPrefixed("&6Profiler now active!"); + resp.broadcastPrefixed(TextComponent.of("Profiler now active!", TextColor.GOLD)); if (timeoutSeconds == -1) { - resp.broadcastPrefixed("&7Use '/" + platform.getPlugin().getLabel() + " stop' to stop profiling and upload the results."); + resp.broadcastPrefixed(TextComponent.of("Use '/" + platform.getPlugin().getLabel() + " stop' to stop profiling and upload the results.")); } else { - resp.broadcastPrefixed("&7The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds."); + resp.broadcastPrefixed(TextComponent.of("The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds.")); } } @@ -201,7 +206,7 @@ public class SamplerModule<S> implements CommandModule<S> { // send message if profiling fails future.whenCompleteAsync((s, throwable) -> { if (throwable != null) { - resp.broadcastPrefixed("&cSampling operation failed unexpectedly. Error: " + throwable.toString()); + resp.broadcastPrefixed(TextComponent.of("Sampling operation failed unexpectedly. Error: " + throwable.toString(), TextColor.RED)); throwable.printStackTrace(); } }); @@ -218,7 +223,7 @@ public class SamplerModule<S> implements CommandModule<S> { // await the result if (timeoutSeconds != -1) { future.thenAcceptAsync(s -> { - resp.broadcastPrefixed("&7The active sampling operation has completed! Uploading results..."); + resp.broadcastPrefixed(TextComponent.of("The active sampling operation has completed! Uploading results...")); handleUpload(platform, resp, s); }); } @@ -246,10 +251,16 @@ public class SamplerModule<S> implements CommandModule<S> { byte[] output = sampler.formCompressedDataPayload(); try { String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key(); - resp.broadcastPrefixed("&6Sampling results:"); - resp.broadcastLink(SparkPlatform.VIEWER_URL + key); + String url = SparkPlatform.VIEWER_URL + key; + + resp.broadcastPrefixed(TextComponent.of("Sampling results:", TextColor.GOLD)); + resp.broadcast(TextComponent.builder(url) + .color(TextColor.GRAY) + .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)) + .build() + ); } catch (IOException e) { - resp.broadcastPrefixed("&cAn error occurred whilst uploading the results."); + resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the results.", TextColor.RED)); e.printStackTrace(); } }); diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java index bea7a07..3b26018 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java @@ -26,6 +26,9 @@ import me.lucko.spark.common.command.CommandResponseHandler; import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.monitor.tick.TickMonitor; import me.lucko.spark.common.sampler.TickCounter; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; import java.util.function.Consumer; @@ -43,7 +46,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> { .executor((platform, sender, resp, arguments) -> { TickCounter tickCounter = platform.getTickCounter(); if (tickCounter == null) { - resp.replyPrefixed("&cNot supported!"); + resp.replyPrefixed(TextComponent.of("Not supported!", TextColor.RED)); return; } @@ -59,7 +62,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> { tickCounter.removeTickTask(this.activeTickMonitor); this.activeTickMonitor.close(); this.activeTickMonitor = null; - resp.broadcastPrefixed("&7Tick monitor disabled."); + resp.broadcastPrefixed(TextComponent.of("Tick monitor disabled.")); } }) .tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--threshold", "--without-gc")) @@ -76,7 +79,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> { } @Override - protected void sendMessage(String message) { + protected void sendMessage(Component message) { this.resp.broadcastPrefixed(message); } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java index 5693df6..3d91368 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java +++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java @@ -21,9 +21,14 @@ package me.lucko.spark.common.monitor.tick; import com.sun.management.GarbageCollectionNotificationInfo; +import com.sun.org.apache.regexp.internal.RE; import me.lucko.spark.common.monitor.memory.GarbageCollectionMonitor; import me.lucko.spark.common.sampler.TickCounter; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import java.awt.*; import java.text.DecimalFormat; import java.util.DoubleSummaryStatistics; @@ -52,7 +57,7 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec } } - protected abstract void sendMessage(String message); + protected abstract void sendMessage(Component message); @Override public void close() { @@ -69,8 +74,8 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec if (this.state == null) { this.state = State.SETUP; this.lastTickTime = now; - sendMessage("Tick monitor started. Before the monitor becomes fully active, the server's " + - "average tick rate will be calculated over a period of 120 ticks (approx 6 seconds)."); + sendMessage(TextComponent.of("Tick monitor started. Before the monitor becomes fully active, the server's " + + "average tick rate will be calculated over a period of 120 ticks (approx 6 seconds).")); return; } @@ -90,13 +95,33 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec // move onto the next state if (this.averageTickTime.getCount() >= 120) { - - sendMessage("&6Analysis is now complete."); - sendMessage("&f> &7Max: " + df.format(this.averageTickTime.getMax()) + "ms"); - sendMessage("&f> &7Min: " + df.format(this.averageTickTime.getMin()) + "ms"); - sendMessage("&f> &7Avg: " + df.format(this.averageTickTime.getAverage()) + "ms"); - sendMessage("Starting now, any ticks with >" + this.percentageChangeThreshold + "% increase in " + - "duration compared to the average will be reported."); + sendMessage(TextComponent.of("Analysis is now complete.", TextColor.GOLD)); + sendMessage(TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of(">", TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("Max: ")) + .append(TextComponent.of(df.format(this.averageTickTime.getMax()))) + .append(TextComponent.of("ms")) + .build() + ); + sendMessage(TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of(">", TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("Min: ")) + .append(TextComponent.of(df.format(this.averageTickTime.getMin()))) + .append(TextComponent.of("ms")) + .build() + ); + sendMessage(TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of(">", TextColor.WHITE)) + .append(Component.space()) + .append(TextComponent.of("Avg: ")) + .append(TextComponent.of(df.format(this.averageTickTime.getAverage()))) + .append(TextComponent.of("ms")) + .build() + ); + sendMessage(TextComponent.of("Starting now, any ticks with >" + this.percentageChangeThreshold + "% increase in " + + "duration compared to the average will be reported.")); this.avg = this.averageTickTime.getAverage(); this.state = State.MONITORING; @@ -111,8 +136,17 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec double percentageChange = (increase * 100d) / this.avg; if (percentageChange > this.percentageChangeThreshold) { - sendMessage("&7Tick &8#" + counter.getCurrentTick() + " &7lasted &6" + df.format(diff) + - "&7 ms. (&6" + df.format(percentageChange) + "% &7increase from average)"); + sendMessage(TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of("Tick ")) + .append(TextComponent.of("#" + counter.getCurrentTick(), TextColor.DARK_GRAY)) + .append(TextComponent.of(" lasted ")) + .append(TextComponent.of(df.format(diff), TextColor.GOLD)) + .append(TextComponent.of(" ms. ")) + .append(TextComponent.of("(")) + .append(TextComponent.of(df.format(percentageChange) + "%", TextColor.GOLD)) + .append(TextComponent.of("increase from avg)")) + .build() + ); } } } @@ -132,8 +166,16 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec gcType = "Old Gen GC"; } - sendMessage("&7Tick &8#" + this.tickCounter.getCurrentTick() + " &7included &4GC &7lasting &6" + - df.format(data.getGcInfo().getDuration()) + "&7 ms. (type = " + gcType + ")"); + sendMessage(TextComponent.builder().color(TextColor.GRAY) + .append(TextComponent.of("Tick ")) + .append(TextComponent.of("#" + this.tickCounter.getCurrentTick(), TextColor.DARK_GRAY)) + .append(TextComponent.of(" included ")) + .append(TextComponent.of("GC", TextColor.RED)) + .append(TextComponent.of(" lasting ")) + .append(TextComponent.of(df.format(data.getGcInfo().getDuration()), TextColor.GOLD)) + .append(TextComponent.of(" ms. (type = " + gcType + ")")) + .build() + ); } private enum State { diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java index 2f3af3e..90a7b78 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java +++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java @@ -21,6 +21,8 @@ package me.lucko.spark.common.monitor.tick; import me.lucko.spark.common.sampler.TickCounter; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; import java.math.BigDecimal; import java.math.RoundingMode; @@ -100,27 +102,27 @@ public class TpsCalculator implements TickCounter.TickTask { return this.tps15M; } - public String toFormattedString() { - return formatTps(this.tps5S.getAverage()) + ", " + - formatTps(this.tps10S.getAverage()) + ", " + - formatTps(this.tps1M.getAverage()) + ", " + - formatTps(this.tps5M.getAverage()) + ", " + - formatTps(this.tps15M.getAverage()); + public TextComponent toFormattedComponent() { + return TextComponent.builder() + .append(format(this.tps5S.getAverage())).append(TextComponent.of(", ")) + .append(format(this.tps10S.getAverage())).append(TextComponent.of(", ")) + .append(format(this.tps1M.getAverage())).append(TextComponent.of(", ")) + .append(format(this.tps5M.getAverage())).append(TextComponent.of(", ")) + .append(format(this.tps15M.getAverage())) + .build(); } - public static String formatTps(double tps) { - StringBuilder sb = new StringBuilder(); + private static TextComponent format(double tps) { + TextColor color; if (tps > 18.0) { - sb.append("&a"); + color = TextColor.GREEN; } else if (tps > 16.0) { - sb.append("&e"); + color = TextColor.YELLOW; } else { - sb.append("&c"); + color = TextColor.RED; } - if (tps > 20.0) { - sb.append('*'); - } - return sb.append(Math.min(Math.round(tps * 100.0) / 100.0, 20.0)).toString(); + + return TextComponent.of( (tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color); } /** |