prometheus 指令
[!INFO] Git Commit:
5ea0bc3| Updated: 2026-10-01
本 mod 只注册 1 个指令:/prometheus(别名 /prom),用于在不重启服务器的情况下
启停导出器。本 mod 没有其它指令,也没有权限节点(沿用 Forge 的权限等级体系)。
注册
@Mod.EventHandler
public void onServerStarting(FMLServerStartingEvent event) {
event.registerServerCommand(new ForgePrometheusCommand());
this.mc_server = event.getServer();
}
PrometheusExporterMod.java:220-227。在 FMLServerStartingEvent 中注册,即世界载入时。
由于 onPreInitialization 已在客户端侧提前 return(:207),
该指令只在服务端存在。
基本信息
| 属性 | 值 | 来源 |
|---|---|---|
| 指令名 | prometheus |
PrometheusCommand.java:50 |
| 别名 | prom |
PrometheusCommand.java:17 |
| 权限等级 | ExporterConfig.collector.command_permission_level,默认 4 |
ForgePrometheusCommand.java:125 |
| 用法 | /prometheus <start|stop|restart> |
PrometheusCommand.java:25 |
权限等级直接返回配置值而非硬编码 4,因此把 command_permission_level 调低(如设为 0)
可以让所有玩家重启导出器。范围 0–4 见 配置。
三个子命令
CommandArg 枚举定义三个子命令(PrometheusCommand.java:55-112):
| 子命令 | 内部枚举 | 动作 | 实现 |
|---|---|---|---|
start |
START |
启动导出器 | execStart(ForgePrometheusCommand.java:58-70) |
stop |
STOP |
停止导出器 | execStop(:77-85) |
restart |
RESTART |
先 stop 再 start | execRestart(:48-51) |
解析用两个静态映射表(PrometheusCommand.java:64-72),均在接口初始化时构建一次:
public static final String[] ARG_VALUES = Arrays.stream(CommandArg.values())
.map(CommandArg::getValue).toArray(String[]::new);
private static final Map<String, CommandArg> FROM = Arrays.stream(CommandArg.values())
.collect(Collectors.toMap(CommandArg::getValue, v -> v));
ARG_VALUES 是 public 的(因此有 @SuppressWarnings("ArraysAsListWithZeroOrOneArgument")),
供 tab 补全使用(ForgePrometheusCommand.java:34-41)。
参数校验
if (args.length != 1) throw new WrongUsageException(MSG_USAGE);
try { cmd = CommandArg.from(args[0]); }
catch (IllegalArgumentException e) { throw new WrongUsageException(MSG_USAGE); }
ForgePrometheusCommand.java:136-146。必须恰好 1 个参数——多于或少于都报用法错误。
CommandArg.from 对未知值抛 IllegalArgumentException(PrometheusCommand.java:101),
被转成 WrongUsageException。参数大小写敏感:/prometheus START 会失败。
幂等性:不会抛异常
start / stop 各自先检查状态,状态不符时不报错而是发提示消息:
| 操作 | 当前状态 | 行为 | 消息 |
|---|---|---|---|
start |
已停止 | startExporter() |
Prometheus exporter started. |
start |
已在运行 | 跳过 | Prometheus exporter is already running. |
stop |
在运行 | stopExporter() |
Prometheus exporter stopped. |
stop |
已停止 | 跳过 | Prometheus exporter is already stopped. |
restart |
两者皆可 | stop + start | 依 stop / start 各自的状态决定 |
ForgePrometheusCommand.java:58-85。这与 mod 公开 API 的行为不同——
PrometheusExporterMod.startExporter() / stopExporter() 在状态不符时
会抛 IllegalStateException(PrometheusExporterMod.java:267-269、:287-289)。
指令层做了一层保护,使得 restart 在任何状态下都安全。
restart 无独立消息,实现为先调 execStop 再调 execStart(:49-50);
由于两者的「状态不符则跳过」逻辑,若导出器本就未运行,restart 只等同于 start。
两类消息,两种发送方式
| 方法 | 实现 | 接收者 | 用到的消息 |
|---|---|---|---|
sendAdminMessage |
func_152373_a(sender, this, msgFormat, msgParams) |
命令来源方(OP) | started / stopped 两条成功消息 |
sendChatMessage |
sender.addChatMessage(new ChatComponentTranslation(...)) |
命令来源方 | already running / already stopped 两条状态提示 |
ForgePrometheusCommand.java:162-175。两者都用 ChatComponentTranslation,
但成功消息走 func_152373_a(1.7.10 中 CommandBase 的「发给管理员」通道,展开为带
commands.generic.usage 风格的输出),状态提示直接 addChatMessage。
sendChatMessage 声明为 private 却带 Object... msgParams 变参,而两处调用点
(:68、:83)都不传变参——变参在本 mod 中从未被使用。
消息不可本地化
全部 5 条消息都是 PrometheusCommand 接口中的硬编码英文字符串常量
(PrometheusCommand.java:25-50)。这源于一条失效的 TODO(:19-20):
// TODO: I can't get ChatComponentTranslation to work with strings defined in
// "assets/prometheus_exporter/lang/en_us.json".
该 TODO 引用的 assets/prometheus_exporter/lang/en_us.json 在仓库中并不存在。
由于消息以 ChatComponentTranslation 构造,Minecraft 会把英文字符串当作翻译键去查
lang 文件;查不到时回退为原字符串,所以英文玩家能看到正常文本,但中文/其它语言环境下
这 5 条消息不会翻译。这是从上游继承的既有问题,GTNH 移植未修复。
本 mod 的资源目录中没有任何语言文件。
端口占用不阻断启动
start 走 startExporter() → initHttpServer(),其中 BindException 被捕获:
try {
this.http_server = new HTTPServer(address, port, true);
LOG.info("Listening on {}:{}", address, port);
} catch (BindException e) {
LOG.error("Failed to start prometheus exporter, port {} already in use.", port);
}
PrometheusExporterMod.java:176-181。端口被占用时只记一条 error 日志,不抛异常、不提示玩家,
且 http_server 保持 null——但 initCollectors() 仍会执行(startExporter 中顺序是先 HTTP
后采集器,:272-275),is_running 仍被置为 true(:277)。
后果:此时执行 /prometheus start 会收到 already running(状态已是 running),
而实际没有可抓取的端点。排查端口冲突必须看服务端日志,
指令反馈在此场景下具有误导性。
new HTTPServer(address, port, true) 的第三个参数为 true,即daemon 模式——
源码注释(:172-173)说明这是必需的,否则 Minecraft 服务器进程无法正常退出。