Skip to content

Commit a939bde

Browse files
committed
feat auto reload config
1 parent 26e7363 commit a939bde

7 files changed

Lines changed: 195 additions & 75 deletions

File tree

src/main/java/monkey/info/command/InfoCommand.java

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
import carpet.CarpetExtension;
44
import carpet.CarpetServer;
5-
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
6-
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
7-
import monkey.info.command.metrics.Mobcaps;
5+
import carpet.settings.ParsedRule;
6+
import com.mojang.brigadier.CommandDispatcher;
87
import monkey.info.command.metrics.Tick;
8+
import monkey.info.command.utils.CarpetExtraTranslations;
99
import net.fabricmc.api.ModInitializer;
1010
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
1111
import net.minecraft.server.MinecraftServer;
12+
import net.minecraft.server.command.ServerCommandSource;
1213
import org.apache.logging.log4j.LogManager;
1314
import org.apache.logging.log4j.Logger;
15+
import org.apache.logging.log4j.util.TriConsumer;
1416

15-
import java.util.Timer;
17+
import java.util.Map;
1618

1719
public class InfoCommand implements CarpetExtension, ModInitializer {
1820
public static final Logger LOGGER = LogManager.getLogger("info-command");
1921
public static MinecraftServer server;
20-
private final Timer metricUpdateLoop;
21-
private HTTPServer httpServer;
22+
public final Prometheus prometheus;
2223

2324
public InfoCommand() {
24-
metricUpdateLoop = new Timer("Metric Update Loop");
25-
25+
prometheus = new Prometheus();
2626
}
2727

2828
@Override
@@ -31,52 +31,49 @@ public void onInitialize() {
3131
ServerLifecycleEvents.SERVER_STARTING.register(server -> InfoCommand.server = server);
3232
}
3333

34-
// @Override
35-
// public void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
36-
// }
37-
3834
@Override
39-
public void onServerLoaded(MinecraftServer server) {
40-
JvmMetrics.builder().register();
41-
42-
MetricUpdate metricUpdater = new MetricUpdate();
43-
metricUpdater.registerMetric(new Tick());
44-
metricUpdater.registerMetric(new Mobcaps());
45-
46-
this.getMetricUpdateLoop().schedule(metricUpdater, 0, InfoCommandSettings.prometheusUpdateInterval);
47-
48-
try {
49-
HTTPServer httpServer = HTTPServer.builder()
50-
.port(InfoCommandSettings.prometheusPort)
51-
.buildAndStart();
52-
53-
this.setHttpServer(httpServer);
54-
} catch (Exception e) {
55-
LOGGER.error("Start HttpServer error:", e);
56-
}
35+
public void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
36+
Tick.registerCommand(dispatcher);
5737
}
5838

5939
@Override
60-
public void onGameStarted() {
61-
CarpetServer.settingsManager.parseSettingsClass(InfoCommandSettings.class);
40+
public void onServerLoaded(MinecraftServer server) {
41+
this.prometheus.start();
6242
}
6343

6444
@Override
6545
public void onServerClosed(MinecraftServer server) {
66-
this.getHttpServer().close();
67-
this.getMetricUpdateLoop().cancel();
46+
this.prometheus.stop();
6847
}
6948

70-
71-
public Timer getMetricUpdateLoop() {
72-
return metricUpdateLoop;
49+
@Override
50+
public void onGameStarted() {
51+
CarpetServer.settingsManager.parseSettingsClass(InfoCommandSettings.class);
52+
CarpetServer.settingsManager.addRuleObserver(new OnConfigChange(this));
7353
}
7454

75-
public HTTPServer getHttpServer() {
76-
return httpServer;
55+
56+
@Override
57+
public Map<String, String> canHasTranslations(String lang) {
58+
return CarpetExtraTranslations.getTranslationFromResourcePath(lang);
7759
}
7860

79-
public void setHttpServer(HTTPServer httpServer) {
80-
this.httpServer = httpServer;
61+
private record OnConfigChange(
62+
InfoCommand infoCommand
63+
) implements TriConsumer<ServerCommandSource, ParsedRule<?>, String> {
64+
65+
@Override
66+
public void accept(ServerCommandSource serverCommandSource, ParsedRule<?> parsedRule, String s) {
67+
if (!parsedRule.categories.contains(InfoCommandSettings.INFO_COMMAND)) {
68+
return;
69+
}
70+
71+
String name = parsedRule.name;
72+
if (name.equals("prometheusEnable") && !parsedRule.getBoolValue()) {
73+
infoCommand.prometheus.stop();
74+
} else if (name.startsWith("prometheus")) {
75+
infoCommand.prometheus.start(); // reload prometheus server
76+
}
77+
}
8178
}
8279
}

src/main/java/monkey/info/command/InfoCommandSettings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class InfoCommandSettings {
1414
)
1515
public static boolean prometheusEnable = false;
1616
@Rule(
17-
options = {"9060", "9061", "9062", "9063", "9064", "9065", "9066", "9067", "9068", "9069"},
17+
options = {"9060", "9061", "9062", "9063"},
1818
category = {INFO_COMMAND},
1919
desc = "prometheus server port",
2020
validate = ValidatePrometheusPort.class

src/main/java/monkey/info/command/MetricUpdate.java

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package monkey.info.command;
2+
3+
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
4+
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
5+
import io.prometheus.metrics.model.registry.PrometheusRegistry;
6+
import monkey.info.command.metrics.Metric;
7+
import monkey.info.command.metrics.Mobcaps;
8+
import monkey.info.command.metrics.Tick;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
import java.util.ArrayList;
12+
import java.util.List;
13+
import java.util.Timer;
14+
import java.util.TimerTask;
15+
16+
public class Prometheus extends TimerTask {
17+
private final List<Metric> metrics = new ArrayList<>();
18+
private final PrometheusRegistry registry;
19+
private @Nullable Timer metricUpdateLoop;
20+
private @Nullable HTTPServer httpServer;
21+
22+
public Prometheus() {
23+
registry = new PrometheusRegistry();
24+
JvmMetrics.builder().register(registry);
25+
}
26+
27+
@Override
28+
public void run() {
29+
if (InfoCommand.server == null || !InfoCommandSettings.prometheusEnable) return;
30+
31+
for (Metric metric : this.getMetrics()) {
32+
try {
33+
metric.update(InfoCommand.server);
34+
} catch (Exception e) {
35+
InfoCommand.LOGGER.error("Error updating metric " + metric.getName(), e);
36+
}
37+
}
38+
}
39+
40+
public void start() {
41+
this.stop();
42+
this.registerMetric(new Tick());
43+
this.registerMetric(new Mobcaps());
44+
45+
if (metricUpdateLoop == null) metricUpdateLoop = new Timer("Metric Update Loop");
46+
metricUpdateLoop.scheduleAtFixedRate(new TimerTask() {
47+
@Override
48+
public void run() {
49+
if (InfoCommand.server == null || !InfoCommandSettings.prometheusEnable) return;
50+
InfoCommand.LOGGER.info("tick");
51+
52+
for (Metric metric : getMetrics()) {
53+
try {
54+
metric.update(InfoCommand.server);
55+
} catch (Exception e) {
56+
InfoCommand.LOGGER.error("Error updating metric " + metric.getName(), e);
57+
}
58+
}
59+
}
60+
}, 0, InfoCommandSettings.prometheusUpdateInterval);
61+
62+
try {
63+
httpServer = HTTPServer.builder()
64+
.port(InfoCommandSettings.prometheusPort)
65+
.registry(registry)
66+
.buildAndStart();
67+
} catch (Exception e) {
68+
InfoCommand.LOGGER.error("Start HttpServer error:", e);
69+
}
70+
}
71+
72+
public void stop() {
73+
for (Metric metrics : this.metrics) {
74+
registry.unregister(metrics.getGauge());
75+
}
76+
this.metrics.clear();
77+
if (httpServer != null) {
78+
httpServer.close();
79+
httpServer = null;
80+
}
81+
if (metricUpdateLoop != null) {
82+
try {
83+
metricUpdateLoop.cancel();
84+
} catch (Exception ignored) {
85+
}
86+
}
87+
metricUpdateLoop = null;
88+
}
89+
90+
public void registerMetric(Metric metric) {
91+
this.metrics.add(metric);
92+
registry.register(metric.getGauge());
93+
}
94+
95+
public List<Metric> getMetrics() {
96+
return metrics;
97+
}
98+
}

src/main/java/monkey/info/command/metrics/Metric.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public abstract class Metric {
99

1010
public Metric(String name, String help, String... labels) {
1111
this.name = name;
12-
this.gauge = Gauge.builder().name("minecraft_" + name).help(help).labelNames(labels).register();
12+
this.gauge = Gauge.builder().name("minecraft_" + name).help(help).labelNames(labels).build();
1313
}
1414

1515
public abstract void update(MinecraftServer server);

src/main/java/monkey/info/command/metrics/Tick.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package monkey.info.command.metrics;
22

33
import carpet.helpers.TickSpeed;
4+
import carpet.utils.Messenger;
5+
import com.mojang.brigadier.CommandDispatcher;
46
import net.minecraft.server.MinecraftServer;
7+
import net.minecraft.server.command.ServerCommandSource;
58
import net.minecraft.util.math.MathHelper;
69

10+
import java.util.Locale;
11+
12+
import static net.minecraft.server.command.CommandManager.literal;
713

814
public class Tick extends Metric {
915
public Tick() {
@@ -18,6 +24,23 @@ public static double getTPS(double MSPT) {
1824
return 1000.0D / Math.max(TickSpeed.time_warp_start_time != 0 ? 0.0 : TickSpeed.mspt, MSPT);
1925
}
2026

27+
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
28+
dispatcher.register(
29+
literal("tps").executes((c) -> {
30+
double MSPT = getMSPT(c.getSource().getServer());
31+
String color = Messenger.heatmap_color(MSPT, TickSpeed.mspt);
32+
33+
Messenger.m(
34+
c.getSource(),
35+
"g TPS: ", String.format(Locale.US, "%s %.1f", color, getTPS(MSPT)),
36+
"g MSPT: ", String.format(Locale.US, "%s %.1f", color, MSPT)
37+
);
38+
return (int) TickSpeed.tickrate;
39+
})
40+
);
41+
}
42+
43+
2144
@Override
2245
public void update(MinecraftServer server) {
2346
double mspt = getMSPT(server);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package monkey.info.command.utils;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import com.google.gson.reflect.TypeToken;
6+
import org.apache.commons.io.IOUtils;
7+
8+
import java.io.IOException;
9+
import java.io.InputStream;
10+
import java.nio.charset.StandardCharsets;
11+
import java.util.Collections;
12+
import java.util.Map;
13+
14+
// from https://github.com/gnembon/carpet-extra/blob/70ac69d9095a1cf0cfbc6f1f8e49fed84d012a90/src/main/java/carpetextra/utils/CarpetExtraTranslations.java
15+
public class CarpetExtraTranslations {
16+
public static Map<String, String> getTranslationFromResourcePath(String lang) {
17+
InputStream langFile = CarpetExtraTranslations.class.getClassLoader().getResourceAsStream("assets/info-command/lang/%s.json".formatted(lang));
18+
if (langFile == null) {
19+
// we don't have that language
20+
return Collections.emptyMap();
21+
}
22+
23+
String jsonData;
24+
try {
25+
jsonData = IOUtils.toString(langFile, StandardCharsets.UTF_8);
26+
} catch (IOException e) {
27+
return Collections.emptyMap();
28+
}
29+
30+
Gson gson = new GsonBuilder().setLenient().create(); // lenient allows for comments
31+
return gson.fromJson(jsonData, new TypeToken<Map<String, String>>() {
32+
}.getType());
33+
}
34+
}

0 commit comments

Comments
 (0)