OpenClaw diagnostics-prometheus 插件:从安装、受保护端点到 2048 序列上限的运行时指标导出全解
OpenClaw 的 diagnostics-prometheus 插件把 Gateway 的运行时诊断事件(模型调用、工具执行、消息收发、队列与内存信号等)转换成标准 Prometheus 文本格式,供 Prometheus、Grafana、VictoriaMetrics 等抓取器拉取。本文以 插件参考文档 为主体,结合插件源码与 Gateway 指标文档,完整覆盖分发信息、安装启用、端点注册、指标目录、标签策略与排障要点,并逐层展开到源码级的实现证据。
插件概览:Surface 是 plugin,分发渠道是 npm 与 ClawHub
参考文档对该插件的定位非常明确:它是 OpenClaw 的诊断 Prometheus 导出器(exporter for runtime metrics),分发信息如下:
- 包名:
@openclaw/diagnostics-prometheus - 安装渠道:npm;ClawHub 规格为
clawhub:@openclaw/diagnostics-prometheus - Surface(能力面):
plugin
仓库中的元数据可以进一步印证这些事实。package.json 中声明了两种安装规格与宿主版本约束:
"install": {
"clawhubSpec": "clawhub:@openclaw/diagnostics-prometheus",
"npmSpec": "@openclaw/diagnostics-prometheus",
"defaultChoice": "npm",
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.8.1"
}
也就是说,该插件默认通过 npm 安装,要求 OpenClaw 宿主版本不低于 2026.4.25。插件清单 openclaw.plugin.json 则声明了插件 id 为 diagnostics-prometheus,且 activation.onStartup 为 true——Gateway 启动时即激活该插件:
{
"id": "diagnostics-prometheus",
"name": "Diagnostics Prometheus",
"description": "OpenClaw diagnostics Prometheus exporter for runtime metrics.",
"activation": { "onStartup": true },
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {}
}
}
值得注意的是,configSchema 是一个带 additionalProperties: false 的空对象。从源码结构看,当前版本的抓取端点路径、认证方式是固定的,插件没有对外暴露可配置项;plugins.entries.diagnostics-prometheus.config 下无需(也不允许)添加额外字段。
安装、启用与抓取端点
安装命令
按 插件 README 的说明,安装命令为:
openclaw plugins install @openclaw/diagnostics-prometheus
安装或更新插件后需要重启 Gateway,因为 HTTP 路由是在插件启动阶段注册的。
启用插件
docs/gateway/prometheus.md 给出了配置与 CLI 两种启用方式。配置方式(JSON5):
{
plugins: {
allow: ["diagnostics-prometheus"],
entries: {
"diagnostics-prometheus": { enabled: true },
},
},
diagnostics: {
enabled: true,
},
}
CLI 方式:
openclaw plugins enable diagnostics-prometheus
其中 diagnostics.enabled 默认为 true;只有强约束环境才建议设为 false。文档明确提示:即使该值为 false,插件仍会注册 HTTP 路由,但没有任何诊断事件流入导出器,抓取响应将为空。
抓取受保护端点
端点为 GET /api/diagnostics/prometheus,Content-Type 是 text/plain; version=0.0.4; charset=utf-8,即标准 Prometheus exposition 格式。该路由使用 Gateway 认证(operator 作用域、trusted-operator 表面),不应作为无认证的公开 /metrics 端点暴露。带同一套 Gateway 鉴权的手动验证命令:
curl -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
http://127.0.0.1:18789/api/diagnostics/prometheus
Prometheus 侧接入示例:
# prometheus.yml
scrape_configs:
- job_name: openclaw
scrape_interval: 30s
metrics_path: /api/diagnostics/prometheus
authorization:
credentials_file: /etc/prometheus/openclaw-gateway-token
static_configs:
- targets: ["openclaw-gateway:18789"]
端点注册与事件订阅:源码级调用链
插件入口 index.ts 通过 definePluginEntry 完成两件事——注册服务与注册 HTTP 路由:
export default definePluginEntry({
id: "diagnostics-prometheus",
name: "Diagnostics Prometheus",
description: "Expose OpenClaw diagnostics metrics in Prometheus text format",
register(api) {
api.registerService(exporter.service);
api.registerHttpRoute({
path: "/api/diagnostics/prometheus",
auth: "gateway",
match: "exact",
gatewayRuntimeScopeSurface: "trusted-operator",
handler: exporter.handler,
});
},
});
几个关键点:
auth: "gateway"+gatewayRuntimeScopeSurface: "trusted-operator":这就是文档中"operator 作用域"警告的源码出处,端点与其余 operator API 走同一认证路径;match: "exact":精确匹配/api/diagnostics/prometheus,不接受前缀路径;- 路由 handler 与指标存储由
createDiagnosticsPrometheusExporter()统一创建,二者共享同一个内存存储实例。
核心实现位于 src/service.ts。服务生命周期(service.ts 约 L1019-L1089):
start:从ctx.internalDiagnostics.onEvent订阅诊断事件流,每个事件调用recordDiagnosticEvent(store, event, metadata),单事件处理失败只记日志、不中断订阅;随后向内部诊断桥上报telemetry.exporter启动事件(status: "started")。若内部诊断能力不可用,仅记录 error 日志。stop:取消订阅,上报status: "dropped",并调用store.reset()清空全部指标。
事件过滤逻辑在 shouldRecordDiagnosticEvent(service.ts L215-L217):
function shouldRecordDiagnosticEvent(metadata: DiagnosticEventMetadata): boolean {
return metadata.trusted || isInternalDiagnosticEventMetadata(metadata);
}
即只有"可信(trusted)"事件或"内部标记、由 dispatcher 持有"的诊断事件(队列、内存、会话恢复等信号)会被计入指标,与 Gateway 指标文档 开头的描述一致。
内存指标存储与 2048 序列上限
createPrometheusMetricStore(service.ts L96-L203)用三个 Map(counters / gauges / histograms)维护全部指标序列,序列键为 指标名|排序后的标签 JSON,保证同标签组合幂等聚合:
counter:只接受正的有限数值,累加到既有样本;gauge:直接覆盖为最新值;histogram:按桶阈值value <= bucket累加计数,同时维护count与sum;snapshot:返回浅拷贝,保证渲染期间不被并发写入干扰;reset:插件停止时整体清空。
防基数爆炸的核心机制是序列上限:
const MAX_PROMETHEUS_SERIES = 2048;
const DROPPED_SERIES_COUNTER_NAME = "openclaw_prometheus_series_dropped_total";
当三个 Map 的序列总数达到 2048 后,任何新序列(既有序列除外)直接丢弃并累加 openclaw_prometheus_series_dropped_total。文档建议把这个计数器当作"上游某属性在泄漏高基数值"的硬信号——导出器从不会自动放宽上限,正确做法是修复标签来源而不是抬高上限。
直方图桶设计
service.ts L48-L56 定义了四组固定桶阈值,分别对应不同量纲的观测值:
| 桶数组 | 取值范围 | 用途 |
|---|---|---|
DURATION_BUCKETS_SECONDS |
0.005s ~ 600s(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120, 300, 600) | 各类耗时直方图的默认桶 |
TOKEN_BUCKETS |
1 ~ 1048576(1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576) | Token 用量分布 |
BYTE_BUCKETS |
1KB ~ 16GB(1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296, 17179869184) | 音频帧、RSS 内存、超大载荷字节数 |
RATIO_BUCKETS |
0.01 ~ 16(0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 1, 2, 4, 8, 16) | 事件循环利用率、CPU 核占比等比率 |
所有耗时事件在入库前经 seconds(ms) 将毫秒转为秒(service.ts L60-L63),非有限值会被丢弃。
标签策略与敏感信息边界
参考文档的"Surface: plugin"之下,这套指标体系最重要的约束是低基数标签策略。源码层面,所有标签值都经过 normalizeDiagnosticValue(来自 openclaw/plugin-sdk/diagnostic-runtime)归一化,并按指标不同在失败时回退为 unknown / other / none。文档与实现共同确认的边界:
- 不出现在 Prometheus 输出中的原始标识:
runId、sessionKey、sessionId、callId、toolCallId、消息 ID、聊天 ID、provider 请求 ID 一律不输出;看起来像 scope 化会话键的值会被替换为unknown。 - 永不进入指标的内容:prompt/响应文本、工具输入输出、系统提示词、Talk 转录与音频载荷、会话键、主机名、文件路径、密钥值等。
- 错误信息处理同样受控:
safeErrorMessage(service.tsL205-L213)先经redactSensitiveText脱敏,再去除控制字符并截断到 500 字符,只用于内部日志,不进入指标标签。
指标目录
以下是 Gateway 指标文档 的完整指标表,与 recordDiagnosticEvent(service.ts L538 起)中各 case 分支一一对应:
| 指标 | 类型 | 标签 |
|---|---|---|
openclaw_run_completed_total |
counter | channel, model, outcome, provider, trigger |
openclaw_run_duration_seconds |
histogram | channel, model, outcome, provider, trigger |
openclaw_model_call_total |
counter | api, error_category, model, observation_unit, outcome, provider, transport |
openclaw_model_call_duration_seconds |
histogram | 同上 |
openclaw_model_failover_total |
counter | from_model, from_provider, lane, reason, suspended, to_model, to_provider |
openclaw_model_tokens_total |
counter | agent, channel, model, provider, token_type |
openclaw_gen_ai_client_token_usage |
histogram | model, provider, token_type |
openclaw_model_cost_usd_total |
counter | agent, channel, model, provider |
openclaw_model_usage_duration_seconds |
histogram | agent, channel, model, provider |
openclaw_skill_used_total |
counter | activation, agent, skill, source |
openclaw_tool_execution_total |
counter | error_category, outcome, params_kind, tool, tool_owner, tool_source |
openclaw_tool_execution_duration_seconds |
histogram | 同上 |
openclaw_tool_execution_blocked_total |
counter | denied_reason, params_kind, tool, tool_owner, tool_source |
openclaw_harness_run_total |
counter | channel, error_category, harness, model, outcome, phase, plugin, provider |
openclaw_harness_run_duration_seconds |
histogram | 同上 |
openclaw_webhook_received_total |
counter | channel, webhook |
openclaw_webhook_error_total |
counter | channel, webhook |
openclaw_webhook_duration_seconds |
histogram | channel, webhook |
openclaw_message_received_total |
counter | channel, source |
openclaw_message_dispatch_started_total |
counter | channel, source |
openclaw_message_dispatch_completed_total |
counter | channel, outcome, reason, source |
openclaw_message_dispatch_duration_seconds |
histogram | channel, outcome, reason, source |
openclaw_message_processed_total |
counter | channel, outcome, reason |
openclaw_message_processed_duration_seconds |
histogram | channel, outcome, reason |
openclaw_message_delivery_started_total |
counter | channel, delivery_kind |
openclaw_message_delivery_total |
counter | channel, delivery_kind, error_category, outcome |
openclaw_message_delivery_duration_seconds |
histogram | 同上 |
openclaw_talk_event_total |
counter | brain, event_type, mode, provider, transport |
openclaw_talk_event_duration_seconds |
histogram | 同上 |
openclaw_talk_audio_bytes |
histogram | 同上 |
openclaw_queue_lane_size |
gauge | lane |
openclaw_queue_lane_wait_seconds |
histogram | lane |
openclaw_session_state_total |
counter | reason, state |
openclaw_session_queue_depth |
gauge | state |
openclaw_session_turn_created_total |
counter | agent, channel, trigger |
openclaw_session_stuck_total |
counter | reason, state |
openclaw_session_stuck_age_seconds |
histogram | reason, state |
openclaw_session_recovery_total |
counter | action, active_work_kind, state, status |
openclaw_session_recovery_age_seconds |
histogram | 同上 |
openclaw_liveness_warning_total |
counter | reason |
openclaw_liveness_sessions |
gauge | state |
openclaw_liveness_event_loop_delay_p99_seconds |
histogram | reason |
openclaw_liveness_event_loop_delay_max_seconds |
histogram | reason |
openclaw_liveness_event_loop_utilization_ratio |
histogram | reason |
openclaw_liveness_cpu_core_ratio |
histogram | reason |
openclaw_payload_large_total |
counter | action, channel, plugin, reason, surface |
openclaw_payload_large_bytes |
histogram | 同上 |
openclaw_memory_bytes |
gauge | kind |
openclaw_memory_rss_bytes |
histogram | 无 |
openclaw_memory_pressure_total |
counter | level, reason |
openclaw_telemetry_exporter_total |
counter | exporter, reason, signal, status |
openclaw_prometheus_series_dropped_total |
counter | 无 |
openclaw_diagnostic_async_queue_dropped_total |
counter | drop_class |
openclaw_diagnostic_async_queue_length |
gauge | 无 |
两个值得在仪表盘设计时注意的语义细节:
observation_unit:"request"度量一次可观测的 provider 请求;"turn"度量一次可能包含多次隐藏 provider 请求的合成 agent turn(如 Claude Code 或 Codex CLI 场景)。对比延迟时应把两类序列分开看。openclaw_model_tokens_total的token_type覆盖input、output、cache_read、cache_write、prompt、total;其中仅input/output会额外写入符合 OpenTelemetry GenAI 语义约定的openclaw_gen_ai_client_token_usage直方图,便于跨 provider、跨服务统一做 Token 看板。openclaw_memory_bytes同时输出kind="rss"、kind="heap_total"、kind="heap_used"三条 gauge 序列,rss样本另入字节桶直方图。
文本格式渲染与 HTTP 行为
renderPrometheusMetrics(service.ts L219-L277)负责把快照渲染成 exposition 文本:
- 按指标名输出一次
# HELP/# TYPE头(emittedSet 去重),help 文本中的反斜杠与换行会被转义; - counter、gauge、histogram 三类样本分别按序列键字典序排序后逐条输出,保证同一份数据的输出是确定性的;
- 标签按 key 排序输出,标签值中的
\、换行、双引号均转义; - 每个直方图额外输出
+Inf桶、_sum与_count行,符合 Prometheus 客户端库惯例; - 数值格式化:非有限值输出
0,整数按整数字面量输出,浮点保留 12 位有效精度。
HTTP handler 的行为(createMetricsHandler,service.ts L979-L999):
- 仅接受
GET与HEAD,其他方法返回405并带Allow: GET, HEAD; - 响应头包含
Cache-Control: no-store、标准 Prometheus Content-Type 与精确Content-Length; HEAD只返回头不返回体。
常用 PromQL 配方
以下配方来自 Gateway 指标文档,可直接用于告警与看板:
# Tokens per minute, split by provider
sum by (provider) (rate(openclaw_model_tokens_total[1m]))
# Spend (USD) over the last hour, by model
sum by (model) (increase(openclaw_model_cost_usd_total[1h]))
# 95th percentile model run duration
histogram_quantile(
0.95,
sum by (le, provider, model)
(rate(openclaw_run_duration_seconds_bucket[5m]))
)
# Queue wait time SLO (95p under 2s)
histogram_quantile(
0.95,
sum by (le, lane) (rate(openclaw_queue_lane_wait_seconds_bucket[5m]))
) < 2
# Skill usage, split by bounded source
sum by (skill, source) (increase(openclaw_skill_used_total[24h]))
# Dropped Prometheus series (cardinality alarm)
increase(openclaw_prometheus_series_dropped_total[15m]) > 0
跨 provider 的 Token 看板建议优先使用 openclaw_gen_ai_client_token_usage,因为它遵循 OpenTelemetry GenAI 语义约定,与非 OpenClaw 的 GenAI 服务指标保持口径一致。
与 OpenTelemetry 导出的分工
OpenClaw 同时提供两个相互独立的遥测面,可以只启用其一、两者都启用、或都不启用:
- diagnostics-prometheus(本文主题):Pull 模型,Prometheus 抓取
/api/diagnostics/prometheus;无需外部 collector;走 Gateway 认证;仅指标面(无 trace、log)。适合已以 Prometheus + Grafana 为标准的栈。 - diagnostics-otel:Push 模型,通过 OTLP/HTTP 推送到 collector 或兼容后端;覆盖指标、trace、log;如需要两者兼得,可经由 OpenTelemetry Collector 的
prometheus/prometheusremotewrite导出器桥接到 Prometheus。
排障清单
结合文档与源码行为,常见问题与排查路径:
- 响应体为空:确认
diagnostics.enabled未被设为false(默认true);用openclaw plugins list --enabled确认插件已启用并加载;制造一些真实流量——counter 与 histogram 至少需要一个事件后才会输出序列行。 - 401 / 未授权:端点要求 Gateway operator 作用域(
auth: "gateway"+trusted-operator表面),使用与其他 Gateway operator 路由相同的 token 或凭据;不存在公开的免认证模式。 openclaw_prometheus_series_dropped_total持续增长:某属性突破了 2048 序列上限。检查近期指标中意外高基数的标签并在源头修复;导出器刻意丢弃新序列而不是静默改写标签。- 重启后出现陈旧序列:插件状态完全在内存中。Gateway 重启后 counter 归零、gauge 从下一次上报值重新开始;PromQL 中用
rate()/increase()即可正确处理重置。
另外可从源码推断一个行为细节:store.reset() 在 stop() 中调用(service.ts L1063-L1079),因此插件被禁用或 Gateway 重启后,指标状态不会残留,这与上述"重启后归零"的排障结论一致。插件行为另有单测与安装运行时 e2e 测试覆盖,可参考 service.test.ts 与 install-runtime.e2e.test.ts。
参考路径
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00