Skip to content

Commit

Permalink
feat prometheus
Browse files Browse the repository at this point in the history
  • Loading branch information
a3510377 committed Nov 4, 2023
1 parent ab6e24f commit 7e967d6
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 57 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ dependencies {
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "carpet:fabric-carpet:${project.minecraft_version}-${project.carpet_core_version}"

implementation "io.prometheus:prometheus-metrics-core:${project.prometheus_version}"
implementation "io.prometheus:prometheus-metrics-instrumentation-jvm:${project.prometheus_version}"
implementation "io.prometheus:prometheus-metrics-exporter-httpserver:${project.prometheus_version}"

// Uncomment the following line to enable the deprecated Fabric API modules.
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.

Expand Down
4 changes: 3 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ yarn_mappings=1.17.1+build.65
loader_version=0.14.24
# check available versions on maven (https://masa.dy.fi/maven/carpet/fabric-carpet/) for the given minecraft version you are using
carpet_core_version=1.4.57+v220119
# https://github.com/prometheus/client_java
prometheus_version=1.0.0
# Mod Properties
mod_version=1.0.0
mod_version=1.1.0
maven_group=monkey.info.command
archives_base_name=infocommand
# Dependencies
Expand Down
91 changes: 62 additions & 29 deletions src/main/java/monkey/info/command/InfoCommand.java
Original file line number Diff line number Diff line change
@@ -1,49 +1,82 @@
package monkey.info.command;

import carpet.helpers.TickSpeed;
import carpet.utils.Messenger;
import com.mojang.brigadier.CommandDispatcher;
import carpet.CarpetExtension;
import carpet.CarpetServer;
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import monkey.info.command.metrics.Mobcaps;
import monkey.info.command.metrics.Tick;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.math.MathHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Locale;
import java.util.Timer;

import static net.minecraft.server.command.CommandManager.literal;
public class InfoCommand implements CarpetExtension, ModInitializer {
public static final Logger LOGGER = LogManager.getLogger("info-command");
public static MinecraftServer server;
private final Timer metricUpdateLoop;
private HTTPServer httpServer;

public class InfoCommand implements ModInitializer {
public static final Logger LOGGER = LogManager.getLogger("infocommand");
public InfoCommand() {
metricUpdateLoop = new Timer("Metric Update Loop");

public static double getMSPT(MinecraftServer server) {
return MathHelper.average(server.lastTickLengths) * 1.0E-6D;
}

public static double getTPS(double MSPT) {
return 1000.0D / Math.max(TickSpeed.time_warp_start_time != 0 ? 0.0 : TickSpeed.mspt, MSPT);
@Override
public void onInitialize() {
CarpetServer.manageExtension(new InfoCommand());
ServerLifecycleEvents.SERVER_STARTING.register(server -> InfoCommand.server = server);
}

public static void register(CommandDispatcher<ServerCommandSource> dispatcher, CommandManager.RegistrationEnvironment environment) {
dispatcher.register(
literal("tps").executes((c) -> {
double MSPT = getMSPT(c.getSource().getServer());
String color = Messenger.heatmap_color(MSPT, TickSpeed.mspt);
// @Override
// public void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
// }

@Override
public void onServerLoaded(MinecraftServer server) {
JvmMetrics.builder().register();

MetricUpdate metricUpdater = new MetricUpdate();
metricUpdater.registerMetric(new Tick());
metricUpdater.registerMetric(new Mobcaps());

Messenger.m(
c.getSource(),
"g TPS: ", String.format(Locale.US, "%s %.1f", color, getTPS(MSPT)),
"g MSPT: ", String.format(Locale.US, "%s %.1f", color, MSPT)
);
return (int) TickSpeed.tickrate;
})
);
this.getMetricUpdateLoop().schedule(metricUpdater, 0, InfoCommandSettings.prometheusUpdateInterval);

try {
HTTPServer httpServer = HTTPServer.builder()
.port(InfoCommandSettings.prometheusPort)
.buildAndStart();

this.setHttpServer(httpServer);
} catch (Exception e) {
LOGGER.error("Start HttpServer error:", e);
}
}

@Override
public void onInitialize() {
LOGGER.info("Hello Fabric world!");
public void onGameStarted() {
CarpetServer.settingsManager.parseSettingsClass(InfoCommandSettings.class);
}

@Override
public void onServerClosed(MinecraftServer server) {
this.getHttpServer().close();
this.getMetricUpdateLoop().cancel();
}


public Timer getMetricUpdateLoop() {
return metricUpdateLoop;
}

public HTTPServer getHttpServer() {
return httpServer;
}

public void setHttpServer(HTTPServer httpServer) {
this.httpServer = httpServer;
}
}
41 changes: 41 additions & 0 deletions src/main/java/monkey/info/command/InfoCommandSettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package monkey.info.command;

import carpet.settings.ParsedRule;
import carpet.settings.Rule;
import carpet.settings.Validator;
import carpet.utils.Messenger;
import net.minecraft.server.command.ServerCommandSource;

public class InfoCommandSettings {
public static final String INFO_COMMAND = "info-command";
@Rule(
category = {INFO_COMMAND},
desc = "enable prometheus server"
)
public static boolean prometheusEnable = false;
@Rule(
options = {"9060", "9061", "9062", "9063", "9064", "9065", "9066", "9067", "9068", "9069"},
category = {INFO_COMMAND},
desc = "prometheus server port",
validate = ValidatePrometheusPort.class
)
public static int prometheusPort = 9060;
@Rule(
category = {INFO_COMMAND},
desc = "prometheus update interval",
validate = ValidatePrometheusPort.class
)
public static int prometheusUpdateInterval = 1000;

public static class ValidatePrometheusPort extends Validator<Integer> {
@Override
public Integer validate(ServerCommandSource source, ParsedRule<Integer> currentRule, Integer newValue, String string) {
return newValue >= 0 && newValue <= 65535 ? newValue : null;
}

@Override
public void notifyFailure(ServerCommandSource source, ParsedRule<Integer> currentRule, String providedValue) {
Messenger.m(source, "r Wrong value for " + currentRule.name + ": " + providedValue + ", should be 0-65535");
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/monkey/info/command/MetricUpdate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package monkey.info.command;

import monkey.info.command.metrics.Metric;

import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

public class MetricUpdate extends TimerTask {
private final List<Metric> metrics = new ArrayList<>();

@Override
public void run() {
if (InfoCommand.server == null || !InfoCommandSettings.prometheusEnable) return;

for (Metric metric : this.getMetrics()) {
try {
metric.update(InfoCommand.server);
} catch (Exception e) {
InfoCommand.LOGGER.error("Error updating metric " + metric.getName(), e);
}
}
}

public void registerMetric(Metric metric) {
this.metrics.add(metric);
}

public List<Metric> getMetrics() {
return metrics;
}
}
24 changes: 24 additions & 0 deletions src/main/java/monkey/info/command/metrics/Metric.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package monkey.info.command.metrics;

import io.prometheus.metrics.core.metrics.Gauge;
import net.minecraft.server.MinecraftServer;

public abstract class Metric {
private final String name;
private final Gauge gauge;

public Metric(String name, String help, String... labels) {
this.name = name;
this.gauge = Gauge.builder().name("minecraft_" + name).help(help).labelNames(labels).register();
}

public abstract void update(MinecraftServer server);

public Gauge getGauge() {
return gauge;
}

public String getName() {
return name;
}
}
40 changes: 40 additions & 0 deletions src/main/java/monkey/info/command/metrics/Mobcaps.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package monkey.info.command.metrics;

import carpet.utils.SpawnReporter;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.SpawnHelper;
import net.minecraft.world.World;

public class Mobcaps extends Metric {
public Mobcaps() {
super("mobcaps", "minecraft mobcaps data", "type", "world");
}

@Override
public void update(MinecraftServer server) {
// edit from: https://github.com/gnembon/fabric-carpet/blob/7486670918f733aaf6ae3b595290947802024d02/src/main/java/carpet/utils/SpawnReporter.java#L105
for (ServerWorld world : server.getWorlds()) {
RegistryKey<World> dim = world.getRegistryKey();
SpawnHelper.Info lastSpawner = world.getChunkManager().getSpawnInfo();
int chunkcount = SpawnReporter.chunkCounts.getOrDefault(dim, -1);

if (lastSpawner != null) {
for (SpawnGroup enumcreaturetype : SpawnGroup.values()) {
Object2IntMap<SpawnGroup> dimCounts = lastSpawner.getGroupToCount();
String enumcreature = enumcreaturetype.toString();
String worldName = world.getRegistryKey().getValue().toString();

int cur = dimCounts.getOrDefault(enumcreaturetype, -1);
int max = (int) (chunkcount * ((double) enumcreaturetype.getCapacity() / SpawnReporter.currentMagicNumber()));

this.getGauge().labelValues(enumcreature, worldName).set(cur);
this.getGauge().labelValues(enumcreature + "_MAX", worldName).set(max);
}
}
}
}
}
28 changes: 28 additions & 0 deletions src/main/java/monkey/info/command/metrics/Tick.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package monkey.info.command.metrics;

import carpet.helpers.TickSpeed;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.MathHelper;


public class Tick extends Metric {
public Tick() {
super("tick", "server mspt and tps", "type");
}

public static double getMSPT(MinecraftServer server) {
return MathHelper.average(server.lastTickLengths) * 1.0E-6D;
}

public static double getTPS(double MSPT) {
return 1000.0D / Math.max(TickSpeed.time_warp_start_time != 0 ? 0.0 : TickSpeed.mspt, MSPT);
}

@Override
public void update(MinecraftServer server) {
double mspt = getMSPT(server);

this.getGauge().labelValues("mspt").set(mspt);
this.getGauge().labelValues("tps").set(getTPS(mspt));
}
}
24 changes: 0 additions & 24 deletions src/main/java/monkey/info/command/mixin/InfoCommandMix.java

This file was deleted.

4 changes: 1 addition & 3 deletions src/main/resources/infocommand.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
"required": true,
"package": "monkey.info.command.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"InfoCommandMix"
],
"mixins": [],
"injectors": {
"defaultRequire": 1
}
Expand Down

0 comments on commit 7e967d6

Please sign in to comment.