npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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 指标采集:通过 /metrics HTTP 端点暴露指标(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 会自动读取该文件。

  • 静态密钥模式(默认):需要 secretIdsecretKeyendpointmetricTopicId 可选)
  • CVM 角色临时密钥模式:需要 endpointroleName,无需 secretIdsecretKeymetricTopicId 可选)

也可以通过命令行参数直接传入,命令行参数优先级高于配置文件中的值。

运行安装命令

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 会自动根据 endpointmetricTopicId 生成 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.jsonplugins.entries["openclaw-diagnostics-metrics-cls"].config 下,分为 clsprometheustrace 三个子对象。

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 角色名称,仅在 credentialModecvmRole 时有效 | | credentialRefreshIntervalMs | number | 300000 | CVM 角色临时密钥刷新间隔(毫秒),仅在 credentialModecvmRole 时有效,最小值 60000 | | secretId | string | — | static 模式必填。腾讯云 API 密钥 SecretId(cvmRole 模式下无需配置) | | secretKey | string | — | static 模式必填。腾讯云 API 密钥 SecretKey(cvmRole 模式下无需配置) | | endpoint | string | — | 必填。CLS 接入点域名,例如 ap-guangzhou.cls.tencentcs.comap-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_idcvm_instance_namecvm_instance_intra_ipcvm_instance_internet_ipcvm_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 会自动根据 endpointmetricTopicId 生成 Remote Write URL(格式为 https://<endpoint>/prometheus/<metricTopicId>/api/v1/write)。静态密钥模式下使用 secretId:secretKey 的 Basic Auth 进行鉴权;CVM 角色临时密钥模式下由插件运行时动态获取凭证进行鉴权。无需手动配置 remote_writeheaders


Trace 配置(可选)

Trace 功能通过插件的 config.trace 配置项控制,与 clsprometheus 配置并列放在 plugins.entries["openclaw-diagnostics-metrics-cls"].config 下。

Trace 模块复用 cls 配置中的 secretId / secretKey / endpoint 凭证,只需在 trace 中独立配置 enabledtraceTopicId

~/.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 配置不完整时(缺少 traceTopicIdcls 凭证不完整),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 配置项追加全局标签(如 jobinstance 等)
  • 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 | 接口/类型定义(TraceConfigTraceContextPendingToolCall 等) | ~130 | | trace-utils.ts | 工具函数(加密安全 ID 生成、消息格式化、inbound metadata 剥离) | ~470 | | trace-sender.ts | ClsSpanSender 类(Span → OTLP JSON → CLS LogItem 转换与发送) | ~370 | | trace-config.ts | 配置解析(resolveTraceConfigreadTraceHotConfigFromDisk) | ~130 | | shared-credential.ts | 共享凭证管理器:trace 和指标服务共用同一份临时密钥,统一管理获取、缓存、定时刷新和事件通知 | ~290 |

对外 API 不变trace-service.ts 通过 re-export 保持了所有对外导出(createTraceServiceresolveTraceConfigstripInboundMetadataTraceConfigLOG_PREFIX),现有调用方无需修改导入路径。

核心设计理念

  • 完整的调用树:所有 Span 共享同一个 traceId,通过显式的 parentSpanId 串联成一棵调用树
  • Resource 全局属性:每个 Span 自动注入 service.namehost.nameservice.instance.idtelemetry.sdk.language 等 OTel Resource 属性,以及 cvm_instance_idcvm_instance_name 等 CVM 实例元数据(字段名格式与指标服务一致)
  • 长生命周期 Span:Entry Span 和 Agent Span 在请求开始时创建,在请求结束时关闭,确保完整的时间跨度
  • 分段式 LLM Span:通过 before_message_write hook 实现分段导出,每次 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_receivedllm_inputbefore_message_writeagent_end 四个关键 hook 以及 ensureEntrySpanensureAgentSpanexportPendingLlmSpanendSpanById(Agent/Entry)、flush 等关键操作始终输出诊断日志(不依赖 debug 标志),记录 hook 触发状态、Span 创建/关闭/导出/刷新的完整链路,便于排查 trace 数据丢失问题
  • ACP 模式自动适配:当 OpenClaw 运行在 ACP(Agent Control Plane)模式下时,框架不会触发 llm_inputllm_outputbefore_agent_startagent_endbefore_message_writebefore_tool_call/after_tool_call 等 hook。插件通过 acpFallbackPending 标记自动检测 ACP 模式:在 message_received 中设置标记,如果后续 llm_inputbefore_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_inputllm_outputbefore_agent_startagent_endbefore_message_writebefore_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 由 ClsSpanSendersendRecordCore() 方法构建:将 Span 数据构建为标准的 OTLP Trace JSON 结构(resourceSpans → scopeSpans → spans 三层嵌套),序列化为 JSON 字符串后作为 CLS LogItem 的 content 字段写入。同时保留 traceIdspanIdspanName 作为顶层索引字段,便于 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.endTimeendSpanById()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.serviceNamebasename(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.tsos.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.fromevent.metadata?.senderIdhookCtx.trigger"unknown" | 标识发起请求的用户 | | openclaw.message.role | string | 消息角色 | message_received 中为 "user"llm_input 中为 hookCtx.trigger"system" | 区分消息来源角色 | | openclaw.message.from | string | 消息来源标识 | event.fromllm_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.durationMs0 | 衡量 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_writellm_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 | 标识使用的模型提供商(如 anthropicopenai) | | 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_writellm_output) | 统计单次 LLM 调用的输入 Token | | gen_ai.usage.output_tokens | number | 输出 Token 数 | event.usage.output | 统计单次 LLM 调用的输出 Token | | gen_ai.usage.total_tokens | number | 总 Token 数 | event.usage.totalinput + 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.llmPendingInputMessagesllmLastInputMessages,由 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.durationMsDate.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.idopenclaw.run.idopenclaw.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.sessionKeyevent.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.messagesgen_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 形成完整的调用树:

  1. 多维上下文管理:通过 contextByChannelIdcontextByRunIdcontextsByChannelIdactiveContextByAgentChannel 四个维度管理上下文
  2. 跨通道链接:agent 通道(agent/xxx)自动链接到最近的用户通道上下文,确保 agent 内部的 Span 与用户请求共享同一个 traceId
  3. runId 重绑定:临时 runId(__temp_run_前缀)在收到真实 runId 后自动重绑定,更新所有关联的 Span 属性
  4. 并发隔离:同一通道的多个并发请求通过 contextsByChannelId 集合隔离
  5. 上下文轮转:新消息到达时自动创建新的 trace,避免与旧 trace 混淆
  6. 任务队列:通过 traceTaskQueueByTraceId 保证同一 trace 的操作按顺序执行

分段式 LLM Span 导出

与传统的 llm_inputllm_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_idcvm_instance_namecvm_instance_intra_ipcvm_instance_internet_ipcvm_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> | 凭证模式:staticcvmRole | ✅ 需要重启网关 | | --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,无需重启 |

注意credentialModeroleName 等凭证模式相关字段,以及 prometheusEnabledpushIntervalMsexternalLabels 等 Prometheus 配置字段变更后需要重启网关才能生效。可通过 UpdateParameter 命令更新,CLI 会自动判断是否需要重启。


密钥加密存储

为避免 secretIdsecretKey 以明文形式暴露在 openclaw.json 配置文件中,插件采用 AES-256-CBC + 加盐 的方式对密钥进行加密存储。

工作原理

  1. CLI 安装时自动加密:通过 npx clawpro-diagnostics-metrics-cls-onboard-cli-test install 安装时,CLI 会自动将 secretIdsecretKey 加密后写入配置文件
  2. 插件启动时自动解密:插件在初始化读取配置时,自动检测并解密密钥,对业务逻辑完全透明
  3. 自动加密明文:若配置文件中存在明文密钥(手动编辑场景),插件启动时会自动将其加密后回写
  4. 向下兼容:如果配置中的密钥是明文(旧版本配置),插件会直接使用,不会报错

加密格式

加密后的值以 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 模式时,配置文件中不会存储 secretIdsecretKey,密钥加密存储功能不适用

CVM 角色临时密钥

对于部署在腾讯云 CVM 上的实例,插件支持通过 CVM 角色(CAM Role)自动获取临时密钥,无需在配置文件中存储静态的 secretId / secretKey,提升安全性。

工作原理

  1. 元数据接口获取凭证:插件通过腾讯云 CVM 元数据接口(http://metadata.tencentyun.com/latest/meta-data/cam/security-credentials/<roleName>)获取绑定了 CAM 角色的临时密钥(TmpSecretId / TmpSecretKey / Token
  2. 自动缓存与刷新:首次获取后缓存凭证,过期前自动重新获取,对业务完全透明
  3. 并发安全:相同 roleName 共享同一个 Provider 实例,并发调用时只发起一次元数据请求
  4. 自愈机制:凭证刷新失败时暂停 Remote Write 推送,下次刷新成功后自动恢复
  5. Prometheus Remote Write 鉴权:使用 secretId 作为 username,secretKey#token 作为 password 的 Basic Auth 方式进行鉴权
  6. 共享凭证管理:trace 和指标(Prometheus Remote Write)服务通过 SharedCredentialManager 共用同一份临时密钥,避免各自独立获取导致的重复元数据请求和凭证状态不一致。管理器统一负责定时刷新和事件通知,两个服务通过订阅机制自动同步最新凭证

前置条件

  1. 实例必须部署在腾讯云 CVM 上,且能访问元数据接口
  2. CVM 实例需要绑定 CAM 角色,角色需要拥有 CLS 写入权限
  3. 必须通过 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.jsoncls 配置中设置:

{
  "cls": {
    "credentialMode": "cvmRole",
    "roleName": "CVM",
    "metricTopicId": "your-metric-topic-id",
    "endpoint": "ap-guangzhou.cls.tencentcs.com"
  }
}

注意事项

  • CVM 角色模式仅适用于腾讯云 CVM 环境,非 CVM 环境下无法访问元数据接口
  • 使用 CVM 角色模式时,配置文件中不会存储 secretIdsecretKey,CLI 安装时会自动清除已有的静态密钥
  • cvmRole 模式下 roleName 为必填参数,必须通过命令行参数或配置文件提供
  • Prometheus Remote Write 鉴权:静态密钥模式下 CLI 会自动生成 Basic Auth 头;CVM 角色模式下由插件运行时动态获取凭证进行鉴权

验证插件状态

查看插件列表

openclaw plugins list

输出示例:

Name                  Status    Version
Diagnostics Metrics   loaded    2026.3.2

Statusloaded 表示插件已成功加载。

验证 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 卸载命令会按以下顺序自动执行:

  1. 环境检查:检测 OpenClaw CLI 是否可用
  2. 配置修复:修复可能损坏的配置文件,防止清理操作丢失其他插件配置
  3. 幂等性检查:如果插件当前未安装,提前告知用户并退出
  4. 交互式确认:提示用户确认卸载操作(--force 可跳过)
  5. 备份:备份当前配置文件和插件安装文件到临时目录,用于失败时回滚
  6. 执行 openclaw plugins uninstall:通过 OpenClaw CLI 正式卸载插件,清理内部注册表
  7. 清理配置:从 openclaw.json 中移除插件配置(plugins.entriesplugins.allow),并在无其他插件依赖时将 diagnostics.enabled 还原为 false
  8. 清理文件:删除插件安装目录及所有相关文件
  9. 重启网关:自动重启 OpenClaw 网关使变更生效
  10. 验证结果:检查插件是否已完全清理

输出示例

🗑️  正在卸载 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,执行以下操作:

  1. plugins.entries 中删除 clawpro-diagnostics-metrics-cls-test 条目
  2. plugins.allow 数组中移除 "clawpro-diagnostics-metrics-cls-test"
  3. 如果没有其他插件依赖诊断功能,将 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.secretIdcls.secretKeycls.endpoint 均已填写;CVM 角色模式下确认 cls.endpointcls.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"

secretIdsecretKey 支持热加载,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.enableReportfalse

{
  "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,并写入 credentialModeroleName

注意credentialModeroleName 不支持热加载,CLI 会自动重启网关使配置生效。

Q:UpdateParameterinstall 命令有什么区别?

| 对比项 | 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"
          }
        }
      }
    }
  }
}

注意:上述 secretIdsecretKey 的值以 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