clawpro-diagnostics-metrics-cls-test
v1.0.2
Published
CLS OpenClaw diagnostics exporter: Prometheus metrics (pull/remote-write) + full-link Trace
Downloads
279
Readme
Diagnostics Metrics CLS 插件
OpenClaw 诊断指标导出插件,提供以下核心能力:
- Prometheus 指标采集:通过
/metricsHTTP 端点暴露指标(Pull 模式),或通过 Prometheus Remote Write 协议主动推送到远端(Push 模式) - 腾讯云 CLS Prometheus Remote Write:通过腾讯云 CLS 的 Prometheus Remote Write 接口推送指标数据
- 全链路 Trace 追踪(v2):将 Agent 执行过程中的 Span 数据直接写入腾讯云日志服务(CLS),支持完整的 Trace Context 传播——所有 Span 共享同一个 traceId,通过显式的父子关系串联成一棵调用树,可以完整看到一次请求的全貌。遵循 OTel GenAI 语义约定,支持分段式 LLM Span、Step 层级、跨通道上下文链接、任务队列等高级特性
目录
快速安装(推荐)
使用 onboard CLI 工具一键完成安装和配置。
前置条件
安装前需确保 ~/.openclaw/openclaw.json 中已包含 CLS 必填配置,CLI 会自动读取该文件。
- 静态密钥模式(默认):需要
secretId、secretKey、endpoint(metricTopicId可选) - CVM 角色临时密钥模式:需要
endpoint、roleName,无需secretId和secretKey(metricTopicId可选)
也可以通过命令行参数直接传入,命令行参数优先级高于配置文件中的值。
运行安装命令
npx --yes clawpro-diagnostics-metrics-cls-onboard-cli-test install命令行参数
所有参数均为可选,未传入时会从 openclaw.json 中读取已有值:
| 参数 | 说明 | 是否必填 |
|------|------|----------|
| --metricTopicId <id> | Prometheus Remote Write 使用的 CLS 日志主题 ID | 可选(可在配置文件中动态更新) |
| --secretId <id> | 腾讯云 API 密钥 SecretId | ✅ static 模式必填(配置文件或参数二选一) |
| --secretKey <key> | 腾讯云 API 密钥 SecretKey | ✅ static 模式必填(配置文件或参数二选一) |
| --endpoint <endpoint> | CLS 接入点(如 ap-guangzhou.cls.tencentcs.com) | ✅ 必填(配置文件或参数二选一) |
| --credentialMode <mode> | 凭证模式:static(静态密钥,默认)或 cvmRole(CVM 角色临时密钥) | 可选,默认 static |
| --roleName <name> | CVM 角色名称 | ✅ cvmRole 模式必填(配置文件或参数二选一) |
| --enableReport <bool> | 是否启用指标推送(true/false,默认 true) | 可选 |
| --prometheusEnabled <bool> | 是否开启 Prometheus 指标上报(true/false) | 可选 |
| --pushIntervalMs <ms> | Prometheus Remote Write 推送间隔(毫秒) | 可选 |
| --externalLabels <labels> | Prometheus 自定义标签(格式:key1=value1,key2=value2) | 可选 |
| --traceEnabled <bool> | 是否启用 Trace 链路追踪功能(true/false,默认 true) | 可选 |
| --traceTopicId <id> | Trace 数据上报使用的 CLS 日志主题 ID | 可选(可在配置文件中动态更新) |
安装示例
从配置文件读取(已预先在 openclaw.json 中配置好 CLS 信息):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install通过命令行参数传入(静态密钥模式):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install \
--metricTopicId "xxxxxxxx-metric-topic-id" \
--secretId "AKIDxxxxxxxx" \
--secretKey "xxxxxxxxxxxxxxxx" \
--endpoint "ap-guangzhou.cls.tencentcs.com" \
--prometheusEnabled true使用 CVM 角色临时密钥模式(无需传入 secretId/secretKey,但必须指定 roleName):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install \
--metricTopicId "xxxxxxxx-metric-topic-id" \
--endpoint "ap-guangzhou.cls.tencentcs.com" \
--credentialMode cvmRole \
--roleName "CVM"使用 CVM 角色临时密钥模式(自定义角色名):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install \
--endpoint "ap-guangzhou.cls.tencentcs.com" \
--credentialMode cvmRole \
--roleName "MyCustomRoleName"同时配置 Trace 链路追踪(指定 Trace 日志主题 ID):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install \
--metricTopicId "xxxxxxxx-metric-topic-id" \
--secretId "AKIDxxxxxxxx" \
--secretKey "xxxxxxxxxxxxxxxx" \
--endpoint "ap-guangzhou.cls.tencentcs.com" \
--prometheusEnabled true \
--traceTopicId "zzzzzzzz-trace-topic-id"安装完成后,CLI 会自动重启网关并输出确认信息:
✅ 安装完成,clawpro-diagnostics-metrics-cls-test 已启用
凭证模式: 静态密钥
CLS 接入点: ap-guangzhou.cls.tencentcs.com
指标日志主题 ID: xxxxxxxx-metric-topic-id
指标推送: 已启用
指标上报: 已开启
Prometheus Remote Write: https://ap-guangzhou.cls.tencentcs.com/prometheus/xxxxxxxx-metric-topic-id/api/v1/write
推送间隔: 15000ms
Trace 链路追踪: 已启用
Trace 日志主题 ID: zzzzzzzz-trace-topic-id
运行以下命令验证插件状态:
openclaw plugins list使用 CVM 角色临时密钥模式时的输出示例:
✅ 安装完成,clawpro-diagnostics-metrics-cls-test 已启用
凭证模式: CVM 角色临时密钥
CVM 角色名称: CVM
CLS 接入点: ap-guangzhou.cls.tencentcs.com
指标日志主题 ID: xxxxxxxx-metric-topic-id
指标推送: 已启用
指标上报: 未开启
Trace 链路追踪: 已启用
Trace 日志主题 ID: (未配置,可通过配置文件 trace.traceTopicId 字段动态注入)
运行以下命令验证插件状态:
openclaw plugins list说明:启用 Prometheus 时,CLI 会自动根据
endpoint和metricTopicId生成 Remote Write URL(格式为https://<endpoint>/prometheus/<metricTopicId>/api/v1/write)。静态密钥模式下使用secretId/secretKey的 Basic Auth 进行鉴权;CVM 角色临时密钥模式下由插件运行时动态获取凭证进行鉴权。
手动安装
第一步:安装插件
openclaw plugins install clawpro-diagnostics-metrics-cls-test第二步:安装插件运行时依赖
在插件安装目录中执行:
cd ~/.openclaw/extensions/clawpro-diagnostics-metrics-cls-test
npm install --omit=dev第三步:编辑配置文件
打开 ~/.openclaw/openclaw.json,添加以下配置:
静态密钥模式(默认):
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": {
"cls": {
"metricTopicId": "your-metric-topic-id",
"secretId": "your-secret-id",
"secretKey": "your-secret-key",
"endpoint": "ap-guangzhou.cls.tencentcs.com"
}
}
}
}
}
}CVM 角色临时密钥模式(适用于腾讯云 CVM 环境):
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": {
"cls": {
"credentialMode": "cvmRole",
"roleName": "CVM",
"metricTopicId": "your-metric-topic-id",
"endpoint": "ap-guangzhou.cls.tencentcs.com"
}
}
}
}
}
}重要:
diagnostics.enabled必须设为true,否则 OpenClaw 不会发出诊断事件,Prometheus 指标将无法采集。使用 CLI 安装时会自动写入此配置。
第四步:重启网关
openclaw gateway restart配置说明
所有配置均位于 ~/.openclaw/openclaw.json 中 plugins.entries["openclaw-diagnostics-metrics-cls"].config 下,分为 cls、prometheus 和 trace 三个子对象。
CLS 配置
CLS 配置用于设置腾讯云 CLS Prometheus Remote Write 的凭证和接入信息。
静态密钥模式(默认):
{
"cls": {
"metricTopicId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"secretId": "AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"secretKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"endpoint": "ap-guangzhou.cls.tencentcs.com",
"enableReport": true
}
}CVM 角色临时密钥模式:
{
"cls": {
"credentialMode": "cvmRole",
"roleName": "CVM",
"metricTopicId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"endpoint": "ap-guangzhou.cls.tencentcs.com",
"enableReport": true
}
}| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| metricTopicId | string | — | 可选。Prometheus Remote Write 使用的 CLS 日志主题 ID,用于构建推送 URL |
| credentialMode | string | "static" | 凭证模式:static(静态密钥)或 cvmRole(CVM 角色临时密钥)。详见 CVM 角色临时密钥 |
| roleName | string | — | cvmRole 模式必填。CVM 角色名称,仅在 credentialMode 为 cvmRole 时有效 |
| credentialRefreshIntervalMs | number | 300000 | CVM 角色临时密钥刷新间隔(毫秒),仅在 credentialMode 为 cvmRole 时有效,最小值 60000 |
| secretId | string | — | static 模式必填。腾讯云 API 密钥 SecretId(cvmRole 模式下无需配置) |
| secretKey | string | — | static 模式必填。腾讯云 API 密钥 SecretKey(cvmRole 模式下无需配置) |
| endpoint | string | — | 必填。CLS 接入点域名,例如 ap-guangzhou.cls.tencentcs.com 或 ap-guangzhou-open.cls.tencentcs.com |
| enableReport | boolean | true | 是否启用指标推送。false 时插件不通过 Remote Write 推送任何指标数据。支持热更新,修改配置文件后约 10 秒内生效,无需重启 |
获取腾讯云密钥:登录 腾讯云控制台 → 访问管理 → API 密钥管理。
获取 CLS Topic ID:登录 日志服务控制台 → 日志主题 → 复制主题 ID。
CLS 接入点列表:参考 CLS 可用地域,格式为
<region>.cls.tencentcs.com(内网)、<region>-open.cls.tencentcs.com(内网开放接口)或<region>.cls.tencentyun.com(外网)。
Prometheus 配置(可选)
Prometheus 功能通过插件的 config.prometheus 配置项控制,与 cls 配置并列放在 plugins.entries["clawpro-diagnostics-metrics-cls-test"].config 下。
在 ~/.openclaw/openclaw.json 中添加:
{
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": {
"prometheus": {
"enabled": true,
"metric_prefix": "openclaw",
"pull": true,
"default_metrics": true,
"external_labels": {
"instance": "my-openclaw-instance",
"env": "production"
},
"remote_write": [
{
"url": "http://prometheus:9090/api/v1/write"
}
],
"push_interval_ms": 15000
}
}
}
}
}
}Prometheus 基础配置
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| enabled | boolean | true | 是否启用 Prometheus 功能 |
| metric_prefix | string | "openclaw" | 所有指标名称的前缀 |
| pull | boolean | true | 是否启用 /metrics HTTP Pull 端点 |
| default_metrics | boolean | true | 是否采集 Node.js 默认指标(GC、事件循环等) |
| external_labels | object | {} | 附加到所有指标的自定义标签 |
| push_interval_ms | number | 15000 | Remote Write 推送间隔(毫秒) |
说明:当部署在腾讯云环境时,插件会自动注入实例元数据作为标签(
cvm_instance_id、cvm_instance_name、cvm_instance_intra_ip、cvm_instance_internet_ip、cvm_instance_region)。若在external_labels中手动配置了同名标签,则以手动配置的值为准。
Remote Write 配置
remote_write 为数组,支持同时配置多个推送目标:
{
"remote_write": [
{
"url": "http://prometheus:9090/api/v1/write",
"headers": {
"Authorization": "Bearer <token>"
},
"queue_config": {
"capacity": 2500,
"max_samples_per_send": 500,
"batch_send_deadline_ms": 5000,
"max_retries": 3
},
"tls_config": {
"insecure_skip_verify": false
}
}
]
}| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| url | string | — | 必填。Remote Write 端点 URL |
| headers | object | — | 自定义 HTTP 请求头(可用于传入 Authorization 等认证头) |
| tls_config.ca_file | string | — | CA 证书文件路径 |
| tls_config.cert_file | string | — | 客户端证书文件路径 |
| tls_config.key_file | string | — | 客户端私钥文件路径 |
| tls_config.insecure_skip_verify | boolean | false | 跳过 TLS 证书验证 |
| queue_config.capacity | number | 2500 | 队列容量(超出后丢弃最旧数据) |
| queue_config.max_samples_per_send | number | 500 | 每批最大发送样本数 |
| queue_config.batch_send_deadline_ms | number | 5000 | 批次最大等待时间(毫秒) |
| queue_config.max_retries | number | 3 | 5xx/429 错误最大重试次数 |
| queue_config.min_backoff_ms | number | 30 | 重试最小退避时间(毫秒) |
| queue_config.max_backoff_ms | number | 5000 | 重试最大退避时间(毫秒) |
使用 CLI 安装时:启用 Prometheus 后,CLI 会自动根据
endpoint和metricTopicId生成 Remote Write URL(格式为https://<endpoint>/prometheus/<metricTopicId>/api/v1/write)。静态密钥模式下使用secretId:secretKey的 Basic Auth 进行鉴权;CVM 角色临时密钥模式下由插件运行时动态获取凭证进行鉴权。无需手动配置remote_write和headers。
Trace 配置(可选)
Trace 功能通过插件的 config.trace 配置项控制,与 cls 和 prometheus 配置并列放在 plugins.entries["openclaw-diagnostics-metrics-cls"].config 下。
Trace 模块复用 cls 配置中的 secretId / secretKey / endpoint 凭证,只需在 trace 中独立配置 enabled 和 traceTopicId。
在 ~/.openclaw/openclaw.json 中添加:
{
"plugins": {
"allow": ["openclaw-diagnostics-metrics-cls"],
"entries": {
"openclaw-diagnostics-metrics-cls": {
"enabled": true,
"config": {
"cls": {
"secretId": "your-secret-id",
"secretKey": "your-secret-key",
"endpoint": "ap-guangzhou.cls.tencentcs.com"
},
"trace": {
"enabled": true,
"traceTopicId": "your-trace-topic-id",
"serviceName": "openclaw-agent",
"debug": false
}
}
}
}
}
}Trace 基础配置
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| enabled | boolean | true | 是否启用 Trace 链路追踪功能 |
| traceTopicId | string | — | 必填。Trace 数据上报使用的 CLS 日志主题 ID |
| serviceName | string | "openclaw-agent" | 服务名称,用于标识 Trace 数据来源,会写入每个 Span 的 service.name 属性 |
| debug | boolean | false | 是否启用 trace 调试日志,开启后会输出详细的 Span 创建/关闭日志 |
| batchSize | number | 10 | Span 缓冲区大小,达到此数量后触发批量发送 |
| flushIntervalMs | number | 5000 | Span 缓冲区最大等待时间(毫秒),超时后强制发送已缓冲的 Span |
| enabledHooks | string[] | — | 可选。指定启用的 hook 列表,未指定时启用所有 hook。支持热更新,修改后约 10 秒内生效。例如 ["message_received", "llm_input", "agent_end"] |
注意:
- Trace 功能复用
cls配置中的secretId/secretKey/endpoint/token,无需在trace中重复配置凭证- Trace 功能使用独立的 CLS 日志主题(
traceTopicId),与 Prometheus 指标使用的日志主题(metricTopicId)分开,便于分别管理和查询- Trace 配置不完整时(缺少
traceTopicId或cls凭证不完整),trace 功能会自动禁用,不影响 Prometheus 指标功能- 热更新恢复:即使初始启动时 trace 配置不完整或
enabled=false,trace 服务仍会被创建并启动热更新轮询。后续在openclaw.json中补全配置后,约 10 秒内自动恢复 trace 功能,无需重启网关
功能说明
Prometheus 指标列表
所有指标名称均以 metric_prefix(默认 openclaw)为前缀。指标的维度标签统一使用 openclaw_ 前缀。
维度(Label)字典
| 维度名 | 说明 | 示例值 |
|--------|------|--------|
| openclaw_type | Token 类型 / 上下文类型 | input, output, cache_read, cache_write, prompt, total, limit, used |
| openclaw_provider | 模型提供商 | qwen, anthropic |
| openclaw_model | 模型名称 | glm-5, claude-3-5-sonnet |
| openclaw_channel | 消息渠道 | feishu, dingtalk, wechat, telegram |
| openclaw_update_type | Webhook 更新类型 | message, callback_query |
| openclaw_source | 消息来源 | user, system |
| openclaw_outcome | 消息处理结果 | success, error, skipped |
| openclaw_lane | 队列通道 | default, priority |
| openclaw_state | 会话状态 | idle, running, waiting |
| openclaw_reason | 状态转换原因 | timeout, completed |
| openclaw_attempt | Agent 运行尝试序号 | 1, 2, 3 |
| openclaw_tool | 工具名称 | web_search, code_exec |
| openclaw_detector | 循环检测器名称 | repetition, token_waste |
| openclaw_level | 检测等级 | warn, critical |
| openclaw_action | 检测后执行的动作 | skip, abort |
Counter 类型指标
| 指标名 | 说明 | 维度 |
|--------|------|------|
| openclaw_tokens_total | 模型 Token 消耗总量 | openclaw_type, openclaw_provider, openclaw_model, openclaw_channel |
| openclaw_cost_usd_total | 模型调用预估费用(USD) | openclaw_provider, openclaw_model, openclaw_channel |
| openclaw_webhook_received_total | 收到的 Webhook 请求数 | openclaw_channel, openclaw_update_type |
| openclaw_webhook_error_total | Webhook 处理错误数 | openclaw_channel, openclaw_update_type |
| openclaw_message_queued_total | 入队消息总数 | openclaw_channel, openclaw_source |
| openclaw_message_processed_total | 已处理消息总数 | openclaw_channel, openclaw_outcome |
| openclaw_queue_lane_enqueue_total | 队列入队事件数 | openclaw_lane |
| openclaw_queue_lane_dequeue_total | 队列出队事件数 | openclaw_lane |
| openclaw_session_state_total | 会话状态转换次数 | openclaw_state, openclaw_reason |
| openclaw_session_stuck_total | 检测到的卡住会话数 | openclaw_state |
| openclaw_run_attempt_total | Agent 运行尝试次数 | openclaw_attempt |
| openclaw_tool_loop_total | 工具循环检测次数 | openclaw_tool, openclaw_detector, openclaw_level, openclaw_action |
Histogram 类型指标
Histogram 类型指标在 Prometheus 中会自动展开为 _bucket(带 le 标签)、_count、_sum 三条子指标。
| 指标名 | 说明 | 维度 | 桶边界(Buckets) |
|--------|------|------|-------------------|
| openclaw_run_duration_ms | Agent 单次运行耗时(ms) | openclaw_provider, openclaw_model, openclaw_channel | 100, 250, 500, 1k, 2.5k, 5k, 10k, 30k, 60k |
| openclaw_context_tokens | 上下文窗口 Token 数量 | openclaw_provider, openclaw_model, openclaw_channel, openclaw_type | 1k, 4k, 8k, 16k, 32k, 64k, 128k, 200k |
| openclaw_webhook_duration_ms | Webhook 处理耗时(ms) | openclaw_channel, openclaw_update_type | 10, 50, 100, 250, 500, 1k, 2.5k, 5k |
| openclaw_message_duration_ms | 消息处理耗时(ms) | openclaw_channel, openclaw_outcome | 100, 500, 1k, 2.5k, 5k, 10k, 30k, 60k |
| openclaw_queue_wait_ms | 队列等待时间(ms) | openclaw_lane | 10, 50, 100, 500, 1k, 5k, 10k |
| openclaw_session_stuck_age_ms | 卡住会话持续时间(ms) | openclaw_state | 1k, 5k, 10k, 30k, 60k, 120k, 300k |
Gauge 类型指标
| 指标名 | 说明 | 维度 |
|--------|------|------|
| openclaw_active_sessions | 当前活跃会话数 | — |
| openclaw_waiting_sessions | 当前等待中的会话数 | — |
| openclaw_queued_messages | 当前队列中的消息总数 | — |
| openclaw_queue_depth | 当前队列深度(按通道分) | openclaw_lane |
其他指标
| 指标名 | 类型 | 说明 |
|--------|------|------|
| openclaw_node_* | 多种 | Node.js 运行时指标(GC、事件循环、内存等,default_metrics: true 时启用) |
注意:
- 所有指标均可通过
external_labels配置项追加全局标签(如job、instance等)- Pull 模式下
job标签由 Prometheus 服务端自动注入- Push 模式下
job标签需通过external_labels手动配置
全链路 Trace 追踪(v2)
插件通过 hook 机制捕获 Agent 执行过程中的关键事件,生成符合 OTel GenAI 语义约定 的 Span 数据,并通过腾讯云 CLS SDK 实时上报。
模块文件结构
Trace 模块按职责拆分为以下子模块,便于维护和测试:
| 文件 | 职责 | 行数 |
|------|------|------|
| trace-service.ts | 主入口:创建 trace 服务实例、注册 hook、热更新轮询 | ~1560 |
| trace-constants.ts | 常量定义(日志前缀、超时阈值、轮询间隔等) | ~60 |
| trace-types.ts | 接口/类型定义(TraceConfig、TraceContext、PendingToolCall 等) | ~130 |
| trace-utils.ts | 工具函数(加密安全 ID 生成、消息格式化、inbound metadata 剥离) | ~470 |
| trace-sender.ts | ClsSpanSender 类(Span → OTLP JSON → CLS LogItem 转换与发送) | ~370 |
| trace-config.ts | 配置解析(resolveTraceConfig、readTraceHotConfigFromDisk) | ~130 |
| shared-credential.ts | 共享凭证管理器:trace 和指标服务共用同一份临时密钥,统一管理获取、缓存、定时刷新和事件通知 | ~290 |
对外 API 不变:
trace-service.ts通过 re-export 保持了所有对外导出(createTraceService、resolveTraceConfig、stripInboundMetadata、TraceConfig、LOG_PREFIX),现有调用方无需修改导入路径。
核心设计理念
- 完整的调用树:所有 Span 共享同一个
traceId,通过显式的parentSpanId串联成一棵调用树 - Resource 全局属性:每个 Span 自动注入
service.name、host.name、service.instance.id、telemetry.sdk.language等 OTel Resource 属性,以及cvm_instance_id、cvm_instance_name等 CVM 实例元数据(字段名格式与指标服务一致) - 长生命周期 Span:Entry Span 和 Agent Span 在请求开始时创建,在请求结束时关闭,确保完整的时间跨度
- 分段式 LLM Span:通过
before_message_writehook 实现分段导出,每次 LLM 响应(包含 tool call)都会生成独立的 LLM Span - Step 层级:每轮 LLM + Tool 调用构成一个 react step,形成清晰的推理循环
- 跨通道上下文链接:agent 通道自动链接到最近的用户通道上下文
- 任务队列:保证同一 trace 的操作按顺序执行,内置上限保护(默认 10000 条),防止异常场景下内存泄漏
- Pending Assistant 缓冲:处理
before_message_write先于llm_input到达的乱序场景 - 热重载安全的 Hook 注册:openclaw 框架在 gateway 热重载(SIGUSR1)时会创建新的 plugin registry,旧 registry 上注册的 hook 不会被新的 hookRunner 识别。因此每次
register()调用都会重新注册 hook 到当前的 api 实例上,确保 hook 始终生效。trace 服务实例通过模块级cachedTracePlugin缓存复用,避免重复创建 Producer 和 sender - 定时器不使用 unref():所有内部定时器(任务超时、上下文清理、热更新轮询、
agent_end延迟关闭等)均不调用unref(),确保 Node.js 进程在定时器回调执行完毕前不会提前退出,避免 Entry/Agent/Step Span 等长生命周期 Span 因进程退出而丢失 - 主动 flush 缓冲区:CLS Producer(
tencentcloud-cls-sdk-nodejs)没有公开的flush()方法,数据通过send()进入内部缓冲区后默认每 2 秒由内部定时器批量发送。ClsSpanSender.flush()通过调用 Producer 的batchSend()方法主动触发缓冲区刷新,确保agent_end关闭 Span 后数据能及时发送到 CLS,而不是等待下一个 2 秒定时器周期 - 关键 Hook 和 Span 诊断日志:
message_received、llm_input、before_message_write、agent_end四个关键 hook 以及ensureEntrySpan、ensureAgentSpan、exportPendingLlmSpan、endSpanById(Agent/Entry)、flush等关键操作始终输出诊断日志(不依赖debug标志),记录 hook 触发状态、Span 创建/关闭/导出/刷新的完整链路,便于排查 trace 数据丢失问题 - ACP 模式自动适配:当 OpenClaw 运行在 ACP(Agent Control Plane)模式下时,框架不会触发
llm_input、llm_output、before_agent_start、agent_end、before_message_write、before_tool_call/after_tool_call等 hook。插件通过acpFallbackPending标记自动检测 ACP 模式:在message_received中设置标记,如果后续llm_input或before_agent_start被触发则清除标记(非 ACP 模式);如果标记未被清除,message_sent中的延迟定时器(2 秒无新消息后触发)会自动结束 Entry Span 并导出,确保 ACP 模式下也能上报完整的对话 trace 数据。ACP 模式下的 Entry Span 会额外携带openclaw.acp_mode=true属性以便区分
Span 层级结构
Entry (enter_openclaw_system) ← 长生命周期,message_received → agent_end
├── Agent (invoke_agent <agentId>) ← 长生命周期,llm_input → agent_end
│ ├── Step (react step round=1) ← 每轮 LLM+Tool 一个 Step
│ │ ├── LLM (chat <model>) ← 分段式导出,before_message_write 触发
│ │ ├── Tool (execute_tool <name>) ← before_tool_call → after_tool_call
│ │ └── Tool (execute_tool <name>)
│ ├── Step (react step round=2) ← tool batch 完成后自动开始新 Step
│ │ └── LLM (chat <model>) ← 最终回复(无 tool call)
│ ├── Compaction (openclaw.compaction) ← 上下文压缩
│ └── Subagent (openclaw.subagent.<key>) ← 子 Agent 调用
├── Session (session_start / session_end) ← 会话生命周期事件
└── Gateway (gateway_start) ← 网关启动事件ACP 模式自动适配
当 OpenClaw 运行在 ACP(Agent Control Plane)模式下时,对话由 ACP 运行时处理,框架不会触发 llm_input、llm_output、before_agent_start、agent_end、before_message_write、before_tool_call/after_tool_call 等 hook。这意味着长生命周期的 Entry Span 无法通过 agent_end 正常关闭。
插件通过 acpFallbackPending 标记 + 延迟定时器 机制自动检测并适配 ACP 模式:
message_received → 设置 acpFallbackPending=true,创建 Entry Span
↓
llm_input / before_agent_start 被触发?
├── 是 → 清除标记(非 ACP 模式),由 agent_end 正常关闭 Entry Span
└── 否 → 标记保持(ACP 模式)
↓
message_sent → 检测到 acpFallbackPending=true
→ 调度延迟定时器(2 秒无新消息后触发)
→ 每次 message_sent 重置定时器(适配流式输出)
↓
定时器到期 → 自动结束 Entry Span 并导出
→ Entry Span 额外携带 openclaw.acp_mode=true 属性
→ 清理上下文,flush 缓冲区ACP 模式下的 Span 层级结构简化为:
Entry (enter_openclaw_system) ← message_received → ACP 回退自动关闭
├── Session (session_start / session_end) ← 会话生命周期事件(如有)
└── Gateway (gateway_start) ← 网关启动事件说明:ACP 模式下不会生成 Agent Span、Step Span、LLM Span、Tool Span 等子 Span,因为框架不触发对应的 hook。Entry Span 仍然包含完整的用户输入(
gen_ai.input.messages)和最终输出(gen_ai.output.messages),可用于基本的对话追踪和延迟分析。
支持的 Hook 事件
| # | Hook 名称 | 对应 Span / 行为 | gen_ai.span.kind | 说明 |
|---|-----------|-----------------|------------------|------|
| 1 | gateway_start | Gateway Span | ENTRY | 网关启动事件 |
| 2 | gateway_stop | — | — | 网关停止,等待所有排队任务完成后清理资源 |
| 3 | session_start | Session Span | SESSION | 会话开始 |
| 4 | session_end | Session Span | SESSION | 会话结束,记录持续时间、消息数和输出内容,清理通道映射 |
| 5 | message_received | Entry Span(长生命周期) | ENTRY | 消息接收,创建 Root Span,记录用户输入 |
| 6 | message_sending | 更新 lastOutput | — | 消息发送中,捕获最终输出 |
| 7 | message_sent | 更新 lastOutput + ACP 回退 | — | 消息发送完成,捕获最终输出;ACP 模式下调度延迟关闭 Entry Span |
| 8 | before_agent_start | Agent Span(长生命周期) | AGENT | 确保 Entry + Agent Span 已创建 |
| 9 | llm_input | 开始 LLM 分段追踪 + Step Span | STEP/LLM | LLM 调用开始,创建 Step Span,记录系统指令和输入消息 |
| 10 | llm_output | 回退 LLM Span 导出 | LLM | LLM 调用结束(仅在 before_message_write 未处理时作为回退) |
| 11 | before_message_write | 分段式 LLM Span 导出 | LLM | 核心:assistant 消息写入前触发,导出分段 LLM Span |
| 12 | before_tool_call | 记录 Pending Tool Call | — | 工具调用开始,缓存到 pendingToolCalls |
| 13 | after_tool_call | Tool Span | TOOL | 工具调用结束,导出 Tool Span,检查 tool batch 完成状态 |
| 14 | before_compaction | 记录开始时间 | — | 上下文压缩开始 |
| 15 | after_compaction | Compaction Span | TOOL | 上下文压缩结束,记录压缩统计 |
| 16 | subagent_spawned | 记录开始时间 | — | 子 Agent 已创建 |
| 17 | subagent_ended | Subagent Span | AGENT | 子 Agent 结束 |
| 18 | agent_end | 结束 Step + Agent + Entry Span | — | Agent 结束,延迟 100ms 关闭(等待 lastOutput 写入),传递 agentUsageCost |
| 19 | before_reset | 在 Root Span 上添加 reset 属性 | — | 会话重置事件 |
Resource 级别全局属性
每个 Span 都会自动注入以下 Resource 级别的全局属性(对齐 OTel Resource 语义约定):
| 属性 | 说明 | 示例值 |
|------|------|--------|
| service.name | 服务名称(默认取 serviceName 配置或当前工作目录名) | openclaw-agent |
| service.instance.id | 服务实例标识(格式:<serviceName>@<hostname>:<pid>) | openclaw-agent@my-host:12345 |
| host.name | 主机名 | my-host |
| telemetry.sdk.language | SDK 语言 | nodejs |
| cvm_instance_id | CVM 实例 ID(动态获取,仅在腾讯云环境下有值) | ins-abc123 |
| cvm_instance_name | CVM 实例名称(动态获取) | my-cvm-instance |
| cvm_instance_intra_ip | CVM 内网 IP(动态获取) | 10.0.0.1 |
| cvm_instance_internet_ip | CVM 公网 IP(动态获取) | 1.2.3.4 |
| cvm_instance_region | CVM 所在地域(动态获取) | ap-guangzhou |
| host_name | 操作系统 hostname(动态获取) | my-host |
说明:
cvm_*和host_name字段由instance-metadata模块通过腾讯云元数据接口动态获取,字段名格式与指标服务(Prometheus Remote Write)的 external labels 保持一致,便于在 CLS 控制台中通过相同字段名关联 trace 和指标数据。trace 模块只负责读取元数据,不负责启动/停止刷新(由指标服务统一管理)。非腾讯云环境下这些字段不会注入。
OTel GenAI 语义约定属性
Trace 数据遵循 OpenTelemetry GenAI Semantic Conventions 规范,包含以下标准属性:
| 属性 | 适用 Span | 说明 |
|------|-----------|------|
| gen_ai.span.kind | 所有 | Span 类型:ENTRY / AGENT / STEP / LLM / TOOL / SESSION |
| gen_ai.operation.name | 所有 | 操作名称:enter / invoke_agent / react / chat / execute_tool 等 |
| gen_ai.provider.name | LLM / Agent | 模型提供商名称 |
| gen_ai.system | LLM | 模型系统标识 |
| gen_ai.request.model | LLM | 请求使用的模型名称 |
| gen_ai.response.model | LLM | 响应返回的模型名称 |
| gen_ai.input.messages | LLM / Agent | 输入消息(OTel GenAI 格式:[{role, parts: [{type, content}]}]) |
| gen_ai.output.messages | LLM / Agent | 输出消息(OTel GenAI 格式) |
| gen_ai.system_instructions | LLM | 系统指令 |
| gen_ai.response.finish_reasons | LLM | 完成原因(如 ["stop"]、["toolUse"]) |
| gen_ai.usage.input_tokens | LLM / Agent | 输入 Token 数 |
| gen_ai.usage.output_tokens | LLM / Agent | 输出 Token 数 |
| gen_ai.usage.total_tokens | LLM / Agent | 总 Token 数 |
| gen_ai.usage.cache_read.input_tokens | LLM | 缓存读取 Token 数 |
| gen_ai.usage.cache_creation.input_tokens | LLM | 缓存创建 Token 数 |
| gen_ai.tool.name | Tool | 工具名称 |
| gen_ai.tool.call.id | Tool | 工具调用 ID |
| gen_ai.tool.call.arguments | Tool | 工具调用参数 |
| gen_ai.tool.call.result | Tool | 工具调用结果 |
| gen_ai.react.round | Step | react 推理轮次 |
| gen_ai.react.finish_reason | Step | Step 结束原因 |
| gen_ai.session.id | 所有 | 会话 ID |
| gen_ai.user.id | Entry | 用户 ID |
| gen_ai.agent.id / gen_ai.agent.name | Agent | Agent 标识 |
OpenClaw 自定义属性
| 属性 | 说明 |
|------|------|
| openclaw.version | OpenClaw 版本 |
| openclaw.session.id | 会话 ID |
| openclaw.run.id | 运行 ID(支持临时 runId → 真实 runId 重绑定) |
| openclaw.turn.id | 轮次 ID |
| openclaw.message.role | 消息角色 |
| openclaw.message.from | 消息来源 |
| openclaw.reset | 是否发生了会话重置 |
| openclaw.sweep | 是否被孤儿清理机制关闭 |
APM 兼容索引属性
Trace 数据中同时包含以下 APM 兼容的索引属性,可在 CLS 控制台中进行搜索和分析:
| 属性前缀 | 说明 |
|----------|------|
| gen_ai.prompt.{i}.role/content | LLM 输入的 prompt 消息(按索引展开) |
| gen_ai.completion.{i}.role/content/finish_reason | LLM 输出的 completion 消息 |
| gen_ai.completion.{i}.tool_calls.{j}.* | LLM 输出中的工具调用信息 |
| gen_ai.usage.* | Token 用量(input/output/cache/total) |
| gen_ai.provider.name / gen_ai.model_name | 模型提供商和模型名称 |
| llm.request.type | LLM 请求类型(chat) |
CLS LogItem 字段声明(完整)
每条 Trace 日志最终以 CLS LogItem 形式上报到腾讯云日志服务。LogItem 由 ClsSpanSender 的 sendRecordCore() 方法构建:将 Span 数据构建为标准的 OTLP Trace JSON 结构(resourceSpans → scopeSpans → spans 三层嵌套),序列化为 JSON 字符串后作为 CLS LogItem 的 content 字段写入。同时保留 traceId、spanId、spanName 作为顶层索引字段,便于 CLS 控制台快速检索。
CLS LogItem 顶层字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| content | string | 完整的 OTLP Trace JSON 字符串 |
| traceId | string | Trace ID(顶层索引字段) |
| spanId | string | Span ID(顶层索引字段) |
| spanName | string | Span 名称(顶层索引字段) |
一、Span 核心字段(所有 Span 共有)
这些字段由 ClsSpanSender.export() / endSpanById() / sendRecordCore() 统一注入,作为 OTLP JSON 中 Span 的结构化字段(非 attributes)。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| traceId | string (32位hex) | 全局唯一的链路追踪 ID,同一次请求的所有 Span 共享此值 | TraceContext.traceId,由 generateId(32) 在 getOrCreateContext() 中生成 | 在 CLS 控制台中通过 traceId 聚合查看一次完整请求的调用树 |
| spanId | string (16位hex) | 当前 Span 的唯一标识 | createSpan() 中由 generateId(16) 生成,或由 ensureEntrySpan/ensureAgentSpan/ensureStepSpan 预分配 | 标识单个 Span,与 parentSpanId 配合构建父子关系 |
| parentSpanId | string (16位hex) | 父 Span ID,空字符串表示根节点 | createSpan() 的 parentSpanId 参数,由 resolveAgentFirstParentSpanId() 或 resolveStepFirstParentSpanId() 解析 | 构建 Span 调用树的父子层级关系 |
| name | string | Span 名称,描述当前操作 | createSpan() 的 name 参数,如 "enter_openclaw_system"、"chat claude-4-sonnet"、"execute_tool search" | CLS 控制台中的 Span 显示名称 |
| kind | number | OTLP SpanKind:2=SERVER (ENTRY), 3=CLIENT (LLM/TOOL), 1=INTERNAL (其他) | 优先取 attributes["gen_ai.span.kind"],否则由 mapSpanKind(type) 映射,再由 mapSpanKindToOtlp() 转换为数值 | 区分 Span 类型,用于 CLS 控制台的分类筛选 |
| status | object | Span 状态对象 | export() 中根据 error/error.type 属性判断:有错误为 {"code":2} (ERROR),否则为 {"code":1} (OK);dispose()/sweepStaleOpenSpans() 强制关闭时为 {"code":0} (UNSET) | 标识 Span 是否成功完成 |
| startTimeUnixNano | string | 开始时间(纳秒级 Unix 时间戳) | spanData.startTime(毫秒时间戳)× 1,000,000 | 精确记录操作开始时间 |
| endTimeUnixNano | string | 结束时间(纳秒级 Unix 时间戳) | spanData.endTime 或 endSpanById() 的 endTime 参数,默认 Date.now(),× 1,000,000 | 精确记录操作结束时间 |
注意:
LogItem.setTime()使用startTime的秒级时间戳(Math.floor(startMs / 1000)),这是 CLS 日志的索引时间。OTLP JSON 中的时间戳为纳秒级。
durationMs字段作为 attribute 保留在 OTLP JSON 的attributes数组中,便于查询。
二、Resource 级别属性(所有 Span 共有)
由 getResourceAttrs() 动态生成,在 sendRecordCore() 中放入 OTLP JSON 的 resourceSpans[0].resource.attributes 中。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| service.name | string | 服务名称 | config.serviceName 或 basename(process.cwd()) 或 "openclaw-agent" | 标识上报数据的服务,多服务环境下区分来源 |
| service.instance.id | string | 服务实例唯一标识 | 格式:<serviceName>@<hostname>:<pid>,如 openclaw-agent@my-host:12345 | 区分同一服务的不同实例(多进程/多机器部署) |
| host.name | string | 主机名 | Node.js os.hostname() | 标识运行主机 |
| telemetry.sdk.language | string | SDK 语言 | 固定值 "nodejs" | OTel 规范要求,标识 SDK 语言 |
| cvm_instance_id | string | CVM 实例 ID | instance-metadata.ts 通过腾讯云 metadata API 获取 instance-id | 关联腾讯云 CVM 实例,与指标服务的 external labels 保持一致 |
| cvm_instance_name | string | CVM 实例名称 | instance-metadata.ts 通过腾讯云 metadata API 获取 instance-name | 在 CLS 控制台中显示可读的实例名称 |
| cvm_instance_intra_ip | string | CVM 内网 IP | instance-metadata.ts 通过腾讯云 metadata API 获取 local-ipv4 | 网络定位和故障排查 |
| cvm_instance_internet_ip | string | CVM 公网 IP | instance-metadata.ts 通过腾讯云 metadata API 获取 public-ipv4 | 网络定位和故障排查 |
| cvm_instance_region | string | CVM 所在地域 | instance-metadata.ts 通过腾讯云 metadata API 获取 placement/region | 标识实例所在地域 |
| host_name | string | 操作系统 hostname | instance-metadata.ts 中 os.hostname() | 与 host.name 类似,字段名格式与指标服务一致 |
说明:
cvm_*和host_name字段仅在腾讯云环境下有值,非腾讯云环境不注入。
三、通用 Span 属性(createSpan() 注入)
每个通过 createSpan() 创建的 Span 都会自动注入以下属性。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| openclaw.version | string | OpenClaw 框架版本号 | api.runtime?.version,在 registerHooks() 中获取 | 版本追踪,排查版本相关问题 |
| openclaw.session.id | string | 会话 ID | TraceContext.sessionId(来自 hook event 的 sessionId),回退到 channelId | 关联同一会话的多次请求 |
| gen_ai.session.id | string | 会话 ID(OTel GenAI 规范) | 与 openclaw.session.id 相同 | OTel GenAI 语义约定的标准字段 |
| openclaw.run.id | string | 运行 ID | TraceContext.runId,来自 hook event 的 runId,支持临时 runId(__temp_run_ 前缀)→ 真实 runId 重绑定 | 关联同一次 Agent 运行的所有 Span |
| openclaw.turn.id | string | 轮次 ID | TraceContext.turnId,由 generateId(16) 在 getOrCreateContext() 中生成 | 区分同一会话中的不同对话轮次 |
四、Entry Span 字段(ensureEntrySpan())
Entry Span 是长生命周期的 Root Span,在 message_received 时创建,在 agent_end 或 ACP 回退时关闭。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "ENTRY" | 硬编码 | 标识为入口 Span |
| gen_ai.operation.name | string | 固定值 "enter" | 硬编码 | 标识操作类型 |
| gen_ai.user.id | string | 用户 ID | event.from 或 event.metadata?.senderId 或 hookCtx.trigger 或 "unknown" | 标识发起请求的用户 |
| openclaw.message.role | string | 消息角色 | message_received 中为 "user";llm_input 中为 hookCtx.trigger 或 "system" | 区分消息来源角色 |
| openclaw.message.from | string | 消息来源标识 | event.from;llm_input 中为 hookCtx.agentId 或 "openclaw" | 标识消息的具体来源 |
| gen_ai.input.messages | string (JSON) | 用户输入消息 | TraceContext.userInput,格式化为 [{role:"user", parts:[{type:"text", content:...}]}] | 记录用户原始输入,便于回溯 |
关闭时追加的属性(agent_end 延迟关闭 / ACP 回退关闭):
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| request.duration_ms | string | 请求总耗时(毫秒) | endTime - rootSpanStartTime | 衡量整个请求的端到端耗时 |
| gen_ai.output.messages | string (JSON) | 最终输出消息 | TraceContext.lastOutput,由 message_sending/message_sent hook 捕获,格式化为 OTel GenAI 格式 | 记录 Agent 最终回复内容 |
| openclaw.acp_mode | boolean | 是否为 ACP 模式 | 仅在 ACP 回退关闭时设为 true | 区分 ACP 模式和正常 Agent 模式的请求 |
五、Agent Span 字段(ensureAgentSpan())
Agent Span 是长生命周期 Span,在 llm_input / before_agent_start 时创建,在 agent_end 时关闭。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "AGENT" | 硬编码 | 标识为 Agent Span |
| gen_ai.operation.name | string | 固定值 "invoke_agent" | 硬编码 | 标识操作类型 |
| gen_ai.provider.name | string | 固定值 "openclaw" | 硬编码 | 标识 Agent 提供商 |
| gen_ai.agent.id | string | Agent 标识 | hookCtx.agentId 或 "openclaw" | 标识具体的 Agent |
| gen_ai.agent.name | string | Agent 名称 | 与 gen_ai.agent.id 相同 | Agent 的可读名称 |
关闭时追加的属性(agent_end):
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| agent.duration_ms | string | Agent 执行耗时 | event.durationMs 或 0 | 衡量 Agent 执行耗时 |
| agent.message_count | string | Agent 处理的消息数 | event.messages.length | 统计 Agent 处理的消息总数 |
| agent.tool_call_count | string | Agent 发起的工具调用数 | countToolCallsFromMessages(event.messages) 统计 | 统计 Agent 使用工具的次数 |
| gen_ai.usage.input_tokens | string | 输入 Token 数 | TraceContext.lastLlmUsage.input | 统计 Agent 整体的 Token 消耗 |
| gen_ai.usage.output_tokens | string | 输出 Token 数 | TraceContext.lastLlmUsage.output | 统计 Agent 整体的 Token 消耗 |
| gen_ai.usage.total_tokens | string | 总 Token 数 | TraceContext.lastLlmUsage.total | 统计 Agent 整体的 Token 消耗 |
| gen_ai.input.messages | string (JSON) | 用户输入消息 | 同 Entry Span | 记录用户原始输入 |
六、Step Span 字段(ensureStepSpan() / endStepSpan())
Step Span 表示一轮 react 推理循环(LLM 调用 + Tool 调用),在 llm_input 时创建,在 tool batch 完成或 agent_end 时关闭。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "STEP" | 硬编码 | 标识为 Step Span |
| gen_ai.operation.name | string | 固定值 "react" | 硬编码 | 标识为 react 推理操作 |
| gen_ai.react.round | number | 推理轮次编号 | TraceContext.stepRoundCounter,每次创建新 Step 时递增 | 标识当前是第几轮推理 |
| gen_ai.react.finish_reason | string | Step 结束原因 | "stop"(正常结束)/ "agent_end"(Agent 结束时强制关闭)/ 其他 | 标识 Step 为何结束 |
七、LLM Span 字段(exportPendingLlmSpan())
LLM Span 是短生命周期 Span(fire-and-forget),由 before_message_write 或 llm_output(回退)触发导出。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "LLM" | 硬编码 | 标识为 LLM Span |
| gen_ai.operation.name | string | 固定值 "chat" | 硬编码 | 标识为 chat 操作 |
| gen_ai.provider.name | string | 模型提供商 | TraceContext.llmProvider,来自 llm_input event 的 event.provider | 标识使用的模型提供商(如 anthropic、openai) |
| gen_ai.system | string | 模型系统标识 | 与 gen_ai.provider.name 相同 | OTel GenAI 规范字段 |
| gen_ai.request.model | string | 请求模型名称 | TraceContext.llmModel,来自 llm_input event 的 event.model | 标识请求使用的模型(如 claude-4-sonnet) |
| gen_ai.response.model | string | 响应模型名称 | 与 gen_ai.request.model 相同 | 标识实际响应的模型 |
| gen_ai.usage.input_tokens | number | 输入 Token 数 | event.usage.input(来自 before_message_write 或 llm_output) | 统计单次 LLM 调用的输入 Token |
| gen_ai.usage.output_tokens | number | 输出 Token 数 | event.usage.output | 统计单次 LLM 调用的输出 Token |
| gen_ai.usage.total_tokens | number | 总 Token 数 | event.usage.total 或 input + output + cacheRead + cacheCreation | 统计单次 LLM 调用的总 Token |
| gen_ai.usage.cache_read.input_tokens | number | 缓存读取 Token 数 | event.usage.cacheRead | 统计 prompt cache 命中的 Token 数 |
| gen_ai.usage.cache_creation.input_tokens | number | 缓存创建 Token 数 | event.usage.cacheWrite | 统计 prompt cache 创建的 Token 数 |
| gen_ai.system_instructions | string (JSON) | 系统指令 | TraceContext.llmPendingSystemInstructions,由 formatSystemInstructions(event.systemPrompt) 格式化为 [{type:"text", content:...}] | 记录 LLM 的系统 prompt |
| gen_ai.input.messages | string (JSON) | 输入消息 | TraceContext.llmPendingInputMessages 或 llmLastInputMessages,由 formatInputMessages() 格式化为 OTel GenAI 格式 | 记录发送给 LLM 的完整输入(含历史消息) |
| gen_ai.output.messages | string (JSON) | 输出消息 | formatAssistantOutputMessages() 格式化 assistant 内容,支持多模态(text / tool_call / reasoning) | 记录 LLM 的完整输出 |
| gen_ai.response.finish_reasons | string (JSON) | 完成原因 | JSON.stringify([stopReason]),如 ["stop"]、["toolUse"]、["end_turn"] | 标识 LLM 为何停止生成 |
| llm.request.type | string | 固定值 "chat" | 硬编码 | APM 兼容字段 |
APM 索引属性(由 setIndexedPromptAttrs() / setIndexedCompletionAttrs() 设置):
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.prompt.{i}.role | string | 第 i 条 prompt 消息的角色 | 解析 gen_ai.input.messages JSON,最多保留 MAX_INDEXED_PROMPT_MESSAGES(20)条 | CLS 控制台中按索引搜索 prompt |
| gen_ai.prompt.{i}.content | string | 第 i 条 prompt 消息的内容 | 同上,截断到 MAX_ATTR_CONTENT_LENGTH(4096)字符 | CLS 控制台中搜索 prompt 内容 |
| gen_ai.completion.{i}.role | string | 第 i 条 completion 的角色 | 解析 assistant 输出 | CLS 控制台中搜索 completion |
| gen_ai.completion.{i}.content | string | 第 i 条 completion 的内容 | 同上,截断到 4096 字符 | CLS 控制台中搜索 completion 内容 |
| gen_ai.completion.{i}.finish_reason | string | 第 i 条 completion 的结束原因 | stopReason;如果包含 tool call 则为 "tool_calls" | 标识 completion 结束原因 |
| gen_ai.completion.{i}.tool_calls.{j}.id | string | 第 j 个 tool call 的 ID | extractToolCallsFromContent() 从 assistant 内容中提取 | 关联 tool call 和 tool result |
| gen_ai.completion.{i}.tool_calls.{j}.name | string | 第 j 个 tool call 的工具名 | 同上 | 标识调用的工具 |
| gen_ai.completion.{i}.tool_calls.{j}.arguments | string | 第 j 个 tool call 的参数 | 同上,截断到 4096 字符 | 记录工具调用参数 |
八、Tool Span 字段(after_tool_call)
Tool Span 是短生命周期 Span,在 after_tool_call hook 中导出。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "TOOL" | 硬编码 | 标识为 Tool Span |
| gen_ai.operation.name | string | 固定值 "execute_tool" | 硬编码 | 标识操作类型 |
| gen_ai.tool.name | string | 工具名称 | event.toolName(来自 before_tool_call) | 标识调用的工具 |
| gen_ai.tool.call.id | string | 工具调用 ID | event.toolCallId 或自动生成 call_<12位hex> | 关联 LLM 的 tool_call 和 tool result |
| gen_ai.tool.type | string | 固定值 "function" | 硬编码 | 标识工具类型 |
| gen_ai.tool.call.arguments | string | 工具调用参数 | event.params,JSON 序列化后截断到 MAX_ATTR_LENGTH(3,200,000)字符 | 记录工具输入参数 |
| gen_ai.tool.call.result | string | 工具调用结果 | event.result,JSON 序列化后截断 | 记录工具返回结果(仅成功时) |
| error.type | string | 错误类型 | event.error(仅工具调用失败时) | 标识工具调用错误 |
| tool.duration_ms | number | 工具执行耗时 | event.durationMs 或 Date.now() - toolStartTime | 衡量工具执行耗时 |
九、Session Span 字段(session_start / session_end)
Session Span 是短生命周期 Span,标记会话的开始和结束。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "SESSION" | 硬编码 | 标识为 Session Span |
| event.type | string | "session_start" | 仅 session_start Span | 区分会话开始事件 |
| session.duration_ms | number | 会话持续时间 | event.durationMs(仅 session_end) | 衡量会话总时长 |
| session.message_count | number | 会话消息数 | event.messageCount(仅 session_end) | 统计会话中的消息总数 |
| session.total_tokens | number | 会话总 Token 数 | TraceContext.lastLlmUsage.total(仅 session_end) | 统计会话的总 Token 消耗 |
| gen_ai.output.messages | string (JSON) | 会话最终输出 | TraceContext.lastOutput(仅 session_end,且有值时) | 记录会话最后的回复内容 |
十、Gateway Span 字段(gateway_start)
Gateway Span 是短生命周期 Span,标记网关启动事件。每次 gateway_start 生成独立的 traceId。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "ENTRY" | 硬编码 | 标识为入口类型 |
| openclaw.version | string | OpenClaw 版本号 | api.runtime?.version | 版本追踪 |
| gateway.port | number | 网关监听端口 | event.port | 记录网关启动的端口号 |
注意:Gateway Span 不通过
createSpan()创建,因此不包含openclaw.session.id、openclaw.run.id、openclaw.turn.id等通用属性。
十一、Compaction Span 字段(after_compaction)
Compaction Span 记录上下文压缩操作。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "TOOL" | 硬编码 | 标识为工具类型 |
| gen_ai.operation.name | string | 固定值 "compaction" | 硬编码 | 标识为压缩操作 |
| openclaw.compaction.messages.after | number | 压缩后消息数 | event.messageCount | 统计压缩后剩余的消息数 |
| openclaw.compaction.tokens.after | number | 压缩后 Token 数 | event.tokenCount | 统计压缩后剩余的 Token 数 |
| openclaw.compaction.compacted_count | number | 被压缩的消息数 | event.compactedCount | 统计本次压缩了多少条消息 |
十二、Subagent Span 字段(subagent_ended)
Subagent Span 记录子 Agent 的调用。
| 字段名 | 类型 | 作用 | 来源 | 用途 |
|--------|------|------|------|------|
| gen_ai.span.kind | string | 固定值 "AGENT" | 硬编码 | 标识为 Agent 类型 |
| gen_ai.operation.name | string | 固定值 "invoke_subagent" | 硬编码 | 标识为子 Agent 调用 |
| openclaw.subagent.session_key | string | 子 Agent 会话标识 | event.sessionKey 或 event.childSessionKey 或 "unknown-child" | 标识具体的子 Agent 实例 |
十三、特殊状态字段
以下字段在特定场景下出现,标记 Span 的异常状态。
| 字段名 | 类型 | 出现场景 | 来源 | 用途 |
|--------|------|----------|------|------|
| openclaw.force_closed | boolean | dispose() 或 sweepStaleOpenSpans() 强制关闭长生命周期 Span 时 | 固定值 true | 标识 Span 非正常关闭 |
| openclaw.force_closed.reason | string | 同上 | "dispose"(进程关闭)或 "stale_sweep"(超时清理) | 标识强制关闭的原因 |
| openclaw.reset | boolean | before_reset hook 触发时 | 固定值 true,通过 patchOpenSpanAttributes() 追加到 Root Span | 标识会话发生了重置 |
| openclaw.reset.reason | string | 同上 | event.reason 或 "user_request" | 标识重置原因 |
| openclaw.acp_mode | boolean | ACP 回退关闭 Entry Span 时 | 固定值 true | 标识当前请求处于 ACP 模式 |
| error | boolean | 工具调用失败时 | true | 标识 Span 存在错误 |
| error.type | string | 工具调用失败时 | event.error | 错误类型描述 |
十四、字段值限制
| 限制项 | 值 | 来源常量 | 说明 |
|--------|-----|----------|------|
| 单个属性值最大长度 | 3,200,000 字符 | MAX_ATTR_LENGTH | truncateAttr() 截断,适用于 gen_ai.input.messages、gen_ai.output.messages 等大字段 |
| APM 索引内容最大长度 | 4,096 字符 | MAX_ATTR_CONTENT_LENGTH | truncate() 截断并添加 ... [truncated, total N chars] 提示 |
| APM 索引最大 prompt 消息数 | 20 条 | MAX_INDEXED_PROMPT_MESSAGES | 超过时保留第 1 条和最后 19 条 |
| traceId 长度 | 32 位十六进制 | generateId(32) | 加密安全随机数(crypto.randomBytes) |
| spanId 长度 | 16 位十六进制 | generateId(16) | 加密安全随机数 |
Trace Context 传播机制
插件实现了完整的 Trace Context 传播,确保一次请求的所有 Span 形成完整的调用树:
- 多维上下文管理:通过
contextByChannelId、contextByRunId、contextsByChannelId、activeContextByAgentChannel四个维度管理上下文 - 跨通道链接:agent 通道(
agent/xxx)自动链接到最近的用户通道上下文,确保 agent 内部的 Span 与用户请求共享同一个 traceId - runId 重绑定:临时 runId(
__temp_run_前缀)在收到真实 runId 后自动重绑定,更新所有关联的 Span 属性 - 并发隔离:同一通道的多个并发请求通过
contextsByChannelId集合隔离 - 上下文轮转:新消息到达时自动创建新的 trace,避免与旧 trace 混淆
- 任务队列:通过
traceTaskQueueByTraceId保证同一 trace 的操作按顺序执行
分段式 LLM Span 导出
与传统的 llm_input → llm_output 一对一模式不同,v2 版本通过 before_message_write hook 实现分段式导出:
llm_input (开始追踪)
→ before_message_write (assistant 消息,含 tool_call) → 导出 LLM Span #1
→ before_tool_call / after_tool_call → 导出 Tool Span
→ 结束 Step #1,开始 Step #2
→ before_message_write (assistant 消息,最终回复) → 导出 LLM Span #2
→ 结束 Step #2
agent_end (结束所有长生命周期 Span)这种方式的优势:
- 每次 LLM 响应都有独立的 Span,包含精确的输入/输出消息
- Tool call 后的下一轮 LLM 输入自动包含 tool result
- Step 层级清晰展示推理循环
孤儿 Span 清理
插件内置孤儿 Span 清理机制,每 60 秒扫描一次,超过 5 分钟未结束的 trace 会被自动关闭并标记 openclaw.sweep=true。
腾讯云实例元数据注入
插件会自动从腾讯云 Metadata 接口获取当前实例的元数据信息,并注入到 Prometheus 指标(Push 模式)中作为 external_labels 自动合并(cvm_instance_id、cvm_instance_name、cvm_instance_intra_ip、cvm_instance_internet_ip、cvm_instance_region)。
获取的元数据字段
| 字段 | Metadata 接口路径 | 说明 |
|------|-------------------|------|
| cvm_instance_id | /latest/meta-data/instance-id | 实例 ID |
| cvm_instance_name | /latest/meta-data/instance-name | 实例名称 |
| cvm_instance_intra_ip | /latest/meta-data/local-ipv4 | 内网 IPv4 地址 |
| cvm_instance_internet_ip | /latest/meta-data/public-ipv4 | 公网 IPv4 地址 |
| cvm_instance_region | /latest/meta-data/placement/region | 所在地域 |
刷新策略
- 启动时立即获取一次元数据(请求超时 2 秒)
- 首次获取失败的字段会在 30 秒后重试,最多重试 3 次
- 成功后每 1 小时自动刷新
- 非腾讯云环境下,元数据字段为空字符串,不影响插件正常运行
更新配置(UpdateParameter)
已安装插件后,如需修改配置参数(如更换密钥、切换凭证模式、调整推送间隔等),可使用 UpdateParameter 命令,无需重新安装插件。
运行更新命令
npx --yes clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter [选项]命令行参数
至少需要传入一个参数,未传入的参数保持当前配置不变:
| 参数 | 说明 | 是否需要重启网关 |
|------|------|------------------|
| --metricTopicId <id> | CLS 指标日志主题 ID | ❌ 热加载(约 10 秒内生效) |
| --secretId <id> | 腾讯云 API 密钥 SecretId | ❌ 热加载(约 10 秒内生效) |
| --secretKey <key> | 腾讯云 API 密钥 SecretKey | ❌ 热加载(约 10 秒内生效) |
| --endpoint <endpoint> | CLS 接入点 | ❌ 热加载(约 10 秒内生效) |
| --enableReport <bool> | 是否启用指标推送(true/false) | ❌ 热加载(约 10 秒内生效) |
| --credentialMode <mode> | 凭证模式:static 或 cvmRole | ✅ 需要重启网关 |
| --roleName <name> | CVM 角色名称 | ✅ 需要重启网关 |
| --prometheusEnabled <bool> | 是否开启 Prometheus 指标上报(true/false) | ✅ 需要重启网关 |
| --pushIntervalMs <ms> | Prometheus Remote Write 推送间隔(毫秒) | ✅ 需要重启网关 |
| --externalLabels <labels> | Prometheus 自定义标签(格式:key1=value1,key2=value2) | ✅ 需要重启网关 |
| --traceEnabled <bool> | 是否启用 Trace 链路追踪功能(true/false) | ❌ 热加载(约 10 秒内生效) |
| --traceTopicId <id> | Trace 数据上报使用的 CLS 日志主题 ID | ❌ 热加载(约 10 秒内生效) |
智能重启判断 智能重启判断:CLI 会自动分析本次更新的参数,如果所有参数均支持热加载,则不会重启网关;如果包含需要重启的参数,CLI 会自动重启网关使配置生效。
更新示例
更换静态密钥(热加载,无需重启):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--secretId "AKIDxxxxxxxx-new" \
--secretKey "xxxxxxxx-new"更换 CLS 接入点和日志主题(热加载,无需重启):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--endpoint "ap-beijing.cls.tencentcs.com" \
--metricTopicId "new-metric-topic-id"临时关闭指标推送(热加载,无需重启):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--enableReport false更新 Trace 日志主题 ID(热加载,无需重启):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--traceTopicId "new-trace-topic-id"关闭 Trace 链路追踪(热加载,无需重启):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--traceEnabled false切换到 CVM 角色临时密钥模式(需要重启网关):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--credentialMode cvmRole \
--roleName "CVM"修改 Prometheus 推送间隔和自定义标签(需要重启网关):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--pushIntervalMs 30000 \
--externalLabels "env=staging,region=ap-beijing"混合更新(热加载 + 需重启参数,CLI 会自动重启网关):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter \
--endpoint "ap-beijing.cls.tencentcs.com" \
--pushIntervalMs 30000输出示例
仅更新热加载参数时:
✅ 已更新 openclaw.json 中的插件配置
✅ 配置更新完成,以下参数支持热加载,无需重启网关: metricTopicId, endpoint
插件将在下一次轮询周期(约 10 秒内)自动应用新配置
📋 更新后的配置:
凭证模式: 静态密钥
CLS 接入点: ap-beijing.cls.tencentcs.com
指标日志主题 ID: new-metric-topic-id
指标推送: 已启用
Prometheus 指标上报: 已开启
Remote Write URL: https://ap-beijing.cls.tencentcs.com/prometheus/new-metric-topic-id/api/v1/write
推送间隔: 15000ms包含需要重启的参数时:
✅ 已更新 openclaw.json 中的插件配置
以下参数需要重启网关才能生效: pushIntervalMs
✅ 配置更新完成,网关已重启
📋 更新后的配置:
凭证模式: 静态密钥
CLS 接入点: ap-guangzhou.cls.tencentcs.com
指标日志主题 ID: xxxxxxxx-metric-topic-id
指标推送: 已启用
Prometheus 指标上报: 已开启
Remote Write URL: https://ap-guangzhou.cls.tencentcs.com/prometheus/xxxxxxxx-metric-topic-id/api/v1/write
推送间隔: 30000ms错误处理
- 插件未安装:如果插件尚未安装,命令会提示先执行
install - 未指定参数:如果未传入任何配置参数,命令会提示可用参数
- 回滚机制:更新过程中发生错误(如网关重启失败),CLI 会自动回滚配置到更新前的状态
- 超时保护:整个更新流程有 5 分钟超时限制,防止进程无限挂起
配置热更新
插件支持以下配置字段的热更新,修改 openclaw.json 后约 10 秒内自动生效,无需重启网关:
| 字段 | 热更新行为 |
|------|-----------|
| cls.metricTopicId | 自动更新 Remote Write URL,切换到新的日志主题 |
| cls.endpoint | 自动更新 Remote Write URL,切换到新的接入点;同时影响 Trace 模块的 CLS 接入点 |
| cls.enableReport | false 时立即停止 Remote Write 指标推送;true 时立即恢复推送 |
| cls.secretId | 自动更新静态密钥(static 模式),新密钥加密后回写配置文件;同时影响 Trace 模块的凭证 |
| cls.secretKey | 自动更新静态密钥(static 模式),新密钥加密后回写配置文件;同时影响 Trace 模块的凭证 |
| cls.token | 自动更新临时 Token(CVM 角色模式),同时影响 Trace 模块的凭证 |
| trace.enabled | 动态启用/禁用 Trace 链路追踪功能。即使初始配置不完整导致 trace 禁用,后续补全配置后也可通过热更新自动恢复 |
| trace.traceTopicId | 自动切换 Trace 数据上报的 CLS 日志主题 |
| trace.debug | 动态开启/关闭 Trace 调试日志,无需重启即可在运行时排查问题 |
| trace.enabledHooks | 动态调整启用的 hook 列表,可在运行时按需启用/禁用特定 hook,无需重启 |
注意:
credentialMode、roleName等凭证模式相关字段,以及prometheusEnabled、pushIntervalMs、externalLabels等 Prometheus 配置字段变更后需要重启网关才能生效。可通过UpdateParameter命令更新,CLI 会自动判断是否需要重启。
密钥加密存储
为避免 secretId 和 secretKey 以明文形式暴露在 openclaw.json 配置文件中,插件采用 AES-256-CBC + 加盐 的方式对密钥进行加密存储。
工作原理
- CLI 安装时自动加密:通过
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install安装时,CLI 会自动将secretId和secretKey加密后写入配置文件 - 插件启动时自动解密:插件在初始化读取配置时,自动检测并解密密钥,对业务逻辑完全透明
- 自动加密明文:若配置文件中存在明文密钥(手动编辑场景),插件启动时会自动将其加密后回写
- 向下兼容:如果配置中的密钥是明文(旧版本配置),插件会直接使用,不会报错
加密格式
加密后的值以 ENC: 前缀标识,格式为:
ENC:<base64(iv + ciphertext)>配置文件中的加密效果示例:
{
"cls": {
"secretId": "ENC:dGhpcyBpcyBhIGJhc2U2NCBleGFtcGxl...",
"secretKey": "ENC:YW5vdGhlciBiYXNlNjQgZXhhbXBsZQ=="
}
}加密方案说明
| 项目 | 说明 |
|------|------|
| 算法 | AES-256-CBC |
| 密钥派生 | SHA-256 哈希固定盐值 |
| IV | 每次加密生成 16 字节随机初始化向量 |
| 编码 | Base64 编码存储 |
| 标识 | ENC: 前缀区分密文与明文 |
⚠️ 安全说明:此方案属于对称加密混淆存储,主要目的是防止配置文件被直接浏览时泄露明文密钥。密钥派生因子内嵌在代码中,并非高安全级别的加密方案。如有更高安全需求,建议:
- 使用腾讯云密钥管理服务(KMS)或密钥保险箱(SSM)
- 限制配置文件读取权限(
chmod 600 openclaw.json)
手动配置时的注意事项
- 使用 CLI 安装:无需关心加密细节,CLI 会自动处理
- 手动编辑配置文件:可以直接写入明文密钥,插件启动时会自动检测并加密后回写
- 重新安装/更新密钥:再次运行 CLI 会自动将新密钥加密后覆盖
- CVM 角色临时密钥模式:使用
cvmRole模式时,配置文件中不会存储secretId和secretKey,密钥加密存储功能不适用
CVM 角色临时密钥
对于部署在腾讯云 CVM 上的实例,插件支持通过 CVM 角色(CAM Role)自动获取临时密钥,无需在配置文件中存储静态的 secretId / secretKey,提升安全性。
工作原理
- 元数据接口获取凭证:插件通过腾讯云 CVM 元数据接口(
http://metadata.tencentyun.com/latest/meta-data/cam/security-credentials/<roleName>)获取绑定了 CAM 角色的临时密钥(TmpSecretId/TmpSecretKey/Token) - 自动缓存与刷新:首次获取后缓存凭证,过期前自动重新获取,对业务完全透明
- 并发安全:相同
roleName共享同一个 Provider 实例,并发调用时只发起一次元数据请求 - 自愈机制:凭证刷新失败时暂停 Remote Write 推送,下次刷新成功后自动恢复
- Prometheus Remote Write 鉴权:使用
secretId作为 username,secretKey#token作为 password 的 Basic Auth 方式进行鉴权 - 共享凭证管理:trace 和指标(Prometheus Remote Write)服务通过
SharedCredentialManager共用同一份临时密钥,避免各自独立获取导致的重复元数据请求和凭证状态不一致。管理器统一负责定时刷新和事件通知,两个服务通过订阅机制自动同步最新凭证
前置条件
- 实例必须部署在腾讯云 CVM 上,且能访问元数据接口
- CVM 实例需要绑定 CAM 角色,角色需要拥有 CLS 写入权限
- 必须通过
roleName参数指定 CVM 角色名称(如CVM)
启用方式
通过 CLI 安装:
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install \
--credentialMode cvmRole \
--roleName "CVM" \
--metricTopicId "your-metric-topic-id" \
--endpoint "ap-guangzhou.cls.tencentcs.com"手动配置:
在 openclaw.json 的 cls 配置中设置:
{
"cls": {
"credentialMode": "cvmRole",
"roleName": "CVM",
"metricTopicId": "your-metric-topic-id",
"endpoint": "ap-guangzhou.cls.tencentcs.com"
}
}注意事项
- CVM 角色模式仅适用于腾讯云 CVM 环境,非 CVM 环境下无法访问元数据接口
- 使用 CVM 角色模式时,配置文件中不会存储
secretId和secretKey,CLI 安装时会自动清除已有的静态密钥 - cvmRole 模式下
roleName为必填参数,必须通过命令行参数或配置文件提供 - Prometheus Remote Write 鉴权:静态密钥模式下 CLI 会自动生成 Basic Auth 头;CVM 角色模式下由插件运行时动态获取凭证进行鉴权
验证插件状态
查看插件列表
openclaw plugins list输出示例:
Name Status Version
Diagnostics Metrics loaded 2026.3.2Status 为 loaded 表示插件已成功加载。
验证 Prometheus 指标端点
curl http://localhost:<openclaw-port>/metrics正常响应示例:
# HELP openclaw_tokens_total Total tokens consumed
# TYPE openclaw_tokens_total counter
openclaw_tokens_total{openclaw_type="input",openclaw_provider="anthropic",openclaw_model="claude-3-5-sonnet",openclaw_channel="telegram"} 1234
...验证 CLS Prometheus Remote Write
查看 OpenClaw 日志中是否有如下日志,表示 Remote Write 推送正常:
diagnostics-metrics/prometheus: remote write enabled for 1 target(s), push interval 15000ms也可在 腾讯云日志服务控制台 的指标日志主题中查看是否有数据写入。
卸载插件
快速卸载(推荐)
使用 onboard CLI 工具一键完成卸载,自动清理配置和安装文件。
运行卸载命令
npx --yes clawpro-diagnostics-metrics-cls-onboard-cli-test uninstall命令行参数
| 参数 | 说明 |
|------|------|
| --force | 跳过交互式确认,直接执行卸载(适用于自动化脚本场景) |
卸载示例
交互式卸载(默认,需手动确认):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test uninstall跳过确认直接卸载(适用于 CI/CD 或自动化脚本):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test uninstall --force卸载流程
CLI 卸载命令会按以下顺序自动执行:
- 环境检查:检测 OpenClaw CLI 是否可用
- 配置修复:修复可能损坏的配置文件,防止清理操作丢失其他插件配置
- 幂等性检查:如果插件当前未安装,提前告知用户并退出
- 交互式确认:提示用户确认卸载操作(
--force可跳过) - 备份:备份当前配置文件和插件安装文件到临时目录,用于失败时回滚
- 执行 openclaw plugins uninstall:通过 OpenClaw CLI 正式卸载插件,清理内部注册表
- 清理配置:从
openclaw.json中移除插件配置(plugins.entries、plugins.allow),并在无其他插件依赖时将diagnostics.enabled还原为false - 清理文件:删除插件安装目录及所有相关文件
- 重启网关:自动重启 OpenClaw 网关使变更生效
- 验证结果:检查插件是否已完全清理
输出示例
🗑️ 正在卸载 clawpro-diagnostics-metrics-cls-test 插件...
✅ 已通过 openclaw plugins uninstall 卸载插件
✅ 已从 openclaw.json 中移除插件配置
✅ 已清理插件安装文件
✅ 卸载完成,clawpro-diagnostics-metrics-cls-test 已禁用
运行以下命令验证插件状态:
openclaw plugins list安全机制
| 机制 | 说明 |
|------|------|
| 配置回滚 | 卸载过程中发生错误时,自动回滚 openclaw.json 到卸载前的状态 |
| 文件恢复 | 插件文件在删除前会备份到临时目录,失败时自动从备份恢复 |
| 超时保护 | 整个卸载流程有 5 分钟超时限制,防止进程无限挂起 |
| 幂等操作 | 重复执行不会产生副作用,插件未安装时会提前退出 |
| 信号处理 | 异常退出(如 Ctrl+C)时也会尝试清理临时备份文件 |
手动卸载
如果 CLI 工具不可用,可按以下步骤手动卸载。
第一步:卸载插件
openclaw plugins uninstall clawpro-diagnostics-metrics-cls-test第二步:清理配置文件
编辑 ~/.openclaw/openclaw.json,执行以下操作:
- 从
plugins.entries中删除clawpro-diagnostics-metrics-cls-test条目 - 从
plugins.allow数组中移除"clawpro-diagnostics-metrics-cls-test" - 如果没有其他插件依赖诊断功能,将
diagnostics.enabled设为false
清理前:
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test", "other-plugin"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": { ... }
},
"other-plugin": { ... }
}
}
}清理后(有其他插件时保留 diagnostics.enabled: true):
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["other-plugin"],
"entries": {
"other-plugin": { ... }
}
}
}清理后(无其他插件时将 diagnostics.enabled 还原为 false):
{
"diagnostics": {
"enabled": false
},
"plugins": {
"allow": [],
"entries": {}
}
}第三步:清理插件安装文件
删除插件安装目录:
rm -rf ~/.openclaw/extensions/clawpro-diagnostics-metrics-cls-test第四步:重启网关
openclaw gateway restart第五步:验证卸载结果
openclaw plugins list确认输出中不再包含 Diagnostics Metrics 插件。
常见问题
Q:插件状态显示 error 而非 loaded?
检查 OpenClaw 日志中是否有 clawpro-diagnostics-metrics-cls-test 相关错误。常见原因:
- 依赖未安装:在插件安装目录执行
npm install --omit=dev - 配置缺失:静态密钥模式下确认
cls.secretId、cls.secretKey、cls.endpoint均已填写;CVM 角色模式下确认cls.endpoint、cls.roleName已填写且cls.credentialMode设为cvmRole diagnostics.enabled未设置为true(使用 CLI 安装可自动写入)
Q:Prometheus Remote Write 推送失败?
- 静态密钥模式:检查
secretId/secretKey是否正确,且对应账号有 CLS 写入权限 - CVM 角色模式:检查 CVM 实例是否绑定了正确的 CAM 角色,角色是否拥有 CLS 写入权限
- 检查
endpoint是否与日志主题所在地域匹配 - 检查网络连通性:
curl https://<endpoint> - 检查
cls.enableReport是否为true(默认为true)
Q:Prometheus /metrics 端点返回 503?
确认插件已正常加载。prometheus.enabled 默认为 true,无需额外设置即可启用。如果之前手动设置为 false,请将 plugins.entries["clawpro-diagnostics-metrics-cls-test"].config.prometheus.enabled 改回 true。
Q:如何只启用 Prometheus Pull 模式,不推送到 CLS?
不配置 cls 节点(或不填写 secretId / secretKey),插件会自动跳过 CLS Remote Write 功能,仅启用 Prometheus /metrics 端点。
Q:如何关闭 Prometheus 端点?
设置 "prometheus": { "enabled": false } 即可关闭 Prometheus 功能(默认启用)。
Q:如何更新 CLS 配置(如更换密钥)?
推荐使用 UpdateParameter 命令(不会重新安装插件,仅更新配置):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter --secretId "新SecretId" --secretKey "新SecretKey"secretId 和 secretKey 支持热加载,CLI 会自动判断无需重启网关,约 10 秒内生效。
也可以通过 install 命令重新安装(会重新安装插件并重启网关):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install --secretId "新SecretId" --secretKey "新SecretKey"两种方式均会读取已有配置作为默认值,只需传入需要更新的字段。
Q:如何临时关闭指标推送?
方式一:使用 UpdateParameter 命令(推荐):
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter --enableReport false恢复推送:
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter --enableReport true方式二:直接修改 openclaw.json 中的 cls.enableReport 为 false:
{
"cls": {
"enableReport": false
}
}两种方式均支持热加载,约 10 秒内自动生效,无需重启网关。恢复推送时将 enableReport 改回 true 即可。
Q:非腾讯云环境下能正常使用吗?
可以。实例元数据获取失败时(超时 2 秒),对应字段为空字符串,不影响 Prometheus 指标采集功能。但注意:CVM 角色临时密钥模式(credentialMode: cvmRole)仅适用于腾讯云 CVM 环境,非 CVM 环境下请使用静态密钥模式。
Q:如何从静态密钥模式切换到 CVM 角色模式?
推荐使用 UpdateParameter 命令:
npx clawpro-diagnostics-metrics-cls-onboard-cli-test UpdateParameter --credentialMode cvmRole --roleName "CVM"也可以通过 install 命令:
npx clawpro-diagnostics-metrics-cls-onboard-cli-test install --credentialMode cvmRole --roleName "CVM"两种方式均会自动清除配置文件中已有的 secretId / secretKey,并写入 credentialMode 和 roleName。
注意:
credentialMode和roleName不支持热加载,CLI 会自动重启网关使配置生效。
Q:UpdateParameter 和 install 命令有什么区别?
| 对比项 | install | UpdateParameter |
|--------|-----------|--------------------|
| 用途 | 首次安装或重新安装插件 | 仅更新已安装插件的配置参数 |
| 插件安装 | ✅ 会重新安装插件(清理旧安装 → 安装新插件 → 安装依赖) | ❌ 不安装插件,仅修改 openclaw.json |
| 网关重启 | ✅ 每次都重启 | 🔄 智能判断:热加载参数不重启,冷参数才重启 |
| 前置条件 | 无(可在未安装时使用) | 插件必须已安装 |
| 适用场景 | 首次部署、版本升级、修复损坏的安装 | 日常配置调整(如更换密钥、修改推送间隔等) |
Q:CVM 角色临时密钥获取失败怎么办?
- 确认 CVM 实例已绑定 CAM 角色,且角色拥有 CLS 写入权限
- 确认实例能访问元数据接口:
curl http://metadata.tencentyun.com/latest/meta-data/cam/security-credentials/CVM - 检查 OpenClaw 日志中是否有
刷新临时密钥失败等错误信息 - 插件具备自愈机制:凭证刷新失败时暂停推送,下次刷新成功后自动恢复
完整配置示例
静态密钥模式
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": {
"prometheus": {
"enabled": true,
"metric_prefix": "openclaw",
"pull": true,
"default_metrics": true,
"external_labels": {
"instance": "prod-01",
"env": "production"
},
"remote_write": [
{
"url": "https://ap-guangzhou.cls.tencentcs.com/prometheus/yyyyyyyy-metric-topic-id/api/v1/write",
"headers": {
"Authorization": "Basic <base64(secretId:secretKey)>"
},
"queue_config": {
"max_samples_per_send": 500,
"batch_send_deadline_ms": 5000
}
}
],
"push_interval_ms": 15000
},
"cls": {
"metricTopicId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"secretId": "ENC:dGhpcyBpcyBhIGJhc2U2NCBleGFtcGxl...",
"secretKey": "ENC:YW5vdGhlciBiYXNlNjQgZXhhbXBsZQ==",
"endpoint": "ap-guangzhou.cls.tencentcs.com",
"enableReport": true
},
"trace": {
"enabled": true,
"traceTopicId": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"
}
}
}
}
}
}注意:上述
secretId和secretKey的值以ENC:前缀标识,表示已加密存储。使用 CLI 安装时会自动加密写入,手动配置时也可直接写入明文(插件启动时会自动加密后回写)。详见 密钥加密存储 章节。Trace 配置说明:
trace配置只需指定traceTopicId,凭证(secretId/secretKey/endpoint)自动复用cls配置中的值。
CVM 角色临时密钥模式
{
"diagnostics": {
"enabled": true
},
"plugins": {
"allow": ["clawpro-diagnostics-metrics-cls-test"],
"entries": {
"clawpro-diagnostics-metrics-cls-test": {
"enabled": true,
"config": {
"prometheus": {
"enabled": true,
"metric_prefix": "openclaw",
"pull": true,
"default_metrics": true,
"external_labels": {
"instance": "prod-01",
"env": "production"
},
"remote_write": [
{
"url": "https://ap-guangzhou.cls.tencentcs.com/prometheus/yyyyyyyy-metric-topic-id/api/v1/write",
"queue_config": {
"max_samples_per_send": 500,
"batch_send_deadline_ms": 5000
}
}
],
"push_interval_ms": 15000
},
"cls": {
"credentialMode": "cvmRole",
"roleName": "CVM",
"metricTopicId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"endpoint": "ap-guangzhou.cls.tencentcs.com",
"enableReport": true
},
"trace": {
"enabled": true,
"traceTopicId": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"
}
}
}
}
}
}注意:CVM 角色模式下无需配置
secretId/secretKey,插件运行时通过 CVM 元数据接口自动获取临时密钥。Prometheus Remote Write 的headers中也不包含Authorization,由插件运行时动态鉴权。详见 CVM 角色临时密钥 章节。Trace 配置说明:
trace配置只需指定traceTopicId,凭证自动复用cls配置。CVM 角色模式下,trace 同样通过cls中的凭证进行鉴权。
开发与构建
本地开发
# 安装依赖
npm install构建
# 编译 TypeScript
npm run build
# 监听模式编译
npm run dev
# 清理构建产物
npm run clean项目结构
diagnostics-metrics-cls/
├── index.ts # 插件入口,注册 service 和 hook
├── openclaw.plugin.json # 插件元数据和配置 schema
├── package.json # NPM 包配置
├── tsconfig.json # TypeScript 编译配置
└── src/
├── cls-service.ts # Prometheus 指标服务(Pull + Remote Write)
├── trace-service.ts # 全链路 Trace 追踪服务(主入口)
├── trace-sender.ts # CLS Span 发送器
├── trace-config.ts # Trace 配置解析与热更新读取
├── trace-types.ts # Trace 类型定义
├── trace-constants.ts # Trace 常量定义
├── trace-utils.ts # Trace 工具函数
├── remote-write.ts # Prometheus Remote Write 客户端
├── protobuf.ts # Protobuf 编码器
├── credential.ts # CVM 角色临时密钥获取
├── shared-credential.ts # 共享凭证管理器
├── shared-constants.ts # 共享常量
├── instance-metadata.ts # 腾讯云实例元数据获取
└── crypto-utils.ts # 加解密工具License
MIT
