首页
/ OpenClaw Gateway 诊断导出(Diagnostics Export)完全指南:构建安全、可分享的 Bug 报告包

OpenClaw Gateway 诊断导出(Diagnostics Export)完全指南:构建安全、可分享的 Bug 报告包

2026-09-09 18:14:23作者:范垣楠Rhoda

本文基于 docs/gateway/diagnostics.md 展开,系统讲解 OpenClaw Gateway 的诊断导出机制:如何用一行命令生成脱敏后的本地 .zip 诊断包、如何在聊天中通过 /diagnostics 命令快速触发导出、导出包内包含哪些文件与字段、隐私与红action模型如何运作,以及稳定性记录器(Stability Recorder)如何为崩溃、重启、内存压力等疑难问题保留现场证据。读完本文,你将能够在 30 秒内产出一份既包含足够技术细节、又不会泄露任何敏感内容的可分享支持报告。

为什么需要诊断导出

OpenClaw Gateway 是一个长期运行的守护进程,承载着渠道连接、会话管理、Agent 执行、WebSocket 传输与 SQLite 写入等大量异步工作。当它出现崩溃、反复重启、内存压力或超大负载时,单靠口头描述往往难以定位问题。OpenClaw 为此内置了一套诊断导出工具:它可以把 Gateway 的状态、健康快照、日志摘要、配置形态以及最近一段无负载(payload-free)的稳定性事件打包成一个本地 .zip 文件,直接用于 Bug 报告或支持请求。

需要特别强调的是,诊断包的处理原则是"像对待机密文件一样对待诊断包":负载(payload)与凭据在设计上会被红action,但包内仍然汇总了本地 Gateway 日志与主机级运行时状态,因此在分享前应自行审阅。

快速开始:一分钟导出诊断包

基础导出

在任意终端中运行:

openclaw gateway diagnostics export

命令会打印写出的 zip 路径。默认输出位置为 $OPENCLAW_STATE_DIR/logs/support/openclaw-diagnostics-<timestamp>-<pid>.zip,其中 <timestamp> 使用诊断文件名时间戳格式,<pid> 是执行导出进程的进程号。

指定输出路径

openclaw gateway diagnostics export --output openclaw-diagnostics.zip

--output 既可以是具体的 zip 文件路径,也可以是一个目录(此时文件会被写入该目录)。

面向自动化

openclaw gateway diagnostics export --json

--json 模式会输出机器可读的导出元数据(如 zip 路径、manifest 摘要等),适合 CI、脚本或 Agent 后续解析。

聊天内导出:/diagnostics 命令

对于不方便打开终端的使用场景,会话所有者(Owner)可以在任意对话中直接发送 /diagnostics 命令,OpenClaw 会把它加工成一份可直接复制粘贴的支持报告。完整流程如下:

  1. 发送 /diagnostics,可附带一句简短说明,例如 /diagnostics bad tool choice。该说明会成为导出记录的上下文备注。
  2. OpenClaw 先发送一段前置说明(preamble),然后请求一次显式的 exec 审批,审批通过后执行 openclaw gateway diagnostics export --json。官方明确建议:不要用 allow-all 规则来批准诊断导出,应逐次审阅。
  3. 审批通过后,OpenClaw 回复本地 bundle 路径、manifest 摘要、隐私说明以及相关的 session id。

群聊中的行为

在群聊里,Owner 依然可以运行 /diagnostics,但导出结果、审批提示以及 Codex 会话/线程明细都会私密发送给 Owner。群内成员只能看到简短的状态提示:审批中(approval pending)、私密投递确认(private delivery confirmed)、投递中(delivery pending)或投递被抑制(delivery suppressed)。需要注意:

  • "投递中"状态不会触发另一次私密发送,避免重复骚扰 Owner;
  • 如果不存在可用的私密 Owner 路由,命令会提示 Owner 改从 DM(私聊)运行。

Codex Harness 会话的特殊行为

当当前活动会话使用原生 OpenAI Codex harness 时,同一次 exec 审批还会同时覆盖一次 OpenAI 反馈上传(针对 OpenClaw 已知的 Codex 线程)。这一点与原文档一致,值得注意的细节包括:

  • 该上传与本地 Gateway zip 是两回事,且仅发生在 Codex harness 会话中;
  • 审批提示会明确说明"批准同时也意味着发送 Codex 反馈",但不会列出 Codex 会话或线程 id;
  • 审批完成后,回复会列出已发送给 OpenAI 的渠道、OpenClaw 会话 id、Codex 线程 id,以及这些线程的本地恢复命令(codex resume <thread-id>);
  • 拒绝或忽略审批会一并跳过导出、Codex 反馈上传和 Codex id 列表。

由此形成的调试闭环非常短:在渠道中观察到异常行为 → 运行 /diagnostics → 一次性批准 → 分享报告 → 如想亲自检查线程,本地执行回复中打印的 codex resume <thread-id> 即可。线程检查的完整说明见 Codex harness 命令文档

导出包内包含什么

导出的 zip 包由以下几部分组成:

文件/内容 说明
summary.md 面向支持人员的人类可读概览
diagnostics.json 机器可读的配置、日志、状态、健康与稳定性数据摘要
manifest.json 导出元数据与文件清单
脱敏配置形态 配置结构与非敏感配置细节
脱敏日志摘要 最近的日志行(已红action)
尽力而为的状态/健康快照 Gateway status 与 health 的即时抓取
stability/latest.json 最近一次持久化的稳定性 bundle(如存在)

关键在于:即使 Gateway 处于不健康状态,导出仍然有价值。如果 status/health 请求失败,本地日志、配置形态和最近的稳定性 bundle 仍会在可用时被收集进包内——这保证了"Gateway 已经崩了"这种最需要诊断的场景也能拿到尽可能多的现场证据。

隐私模型:保留什么、红action什么

保留的数据(Kept)

  • 子系统名称、插件 id、provider id、渠道 id、已配置的模式
  • 状态码、耗时、字节数、队列状态、内存读数
  • 脱敏后的日志元数据、红action后的运维消息
  • 配置形态与非敏感的功能开关设置

省略或红action的数据(Omitted / Redacted)

  • 聊天文本、提示词、指令、webhook 请求体、工具输出
  • 凭据、API key、token、cookie、密钥值
  • 原始请求/响应体、账号 id、消息 id、原始会话 id
  • 主机名、本地用户名

特别地:当一条日志消息看起来像是用户、聊天、提示词或工具负载文本时,导出只会保留"该消息被省略"这一事实及其字节数,绝不保留内容本身。

从源码实现来看,这一红action模型贯穿于稳定性记录与导出的底层。在 src/logging/diagnostic-stability-bundle.ts 中可以看到:

  • 错误消息在写入前会经过 redactSensitiveText(message, { mode: "tools" }) 处理(见 readErrorMessageL181-L196);
  • 持久化 bundle 中的 host.hostname 恒为常量 REDACTED_HOSTNAME(即 "<redacted-hostname>"L31),读取与写入两侧都强制覆盖;
  • 会话文件路径会被消毒:agents/<agent>/sessions/<session>.jsonl 这类路径会被规范化为 agents/<agent>/sessions/<session>.jsonl 的脱敏形式(见 sanitizeSessionEvidencePathL780-L802);
  • reason 字段只允许匹配 ^[A-Za-z0-9_.:-]{1,120}$ 的安全码,其余一律归一为 "unknown"normalizeReasonL155-L157)。

这些"写入即脱敏"的约束,从实现层面保证了即使 bundle 被意外分享,敏感内容也无法通过构造畸形数据绕过。

WebSocket 断开日志

对于 webchat 与已认证用户连接,默认的 info 级文件日志中会记录断开事件,包含:

  • durationMs:连接生命周期(毫秒)。
  • cause:Gateway 记录的关闭原因(当已知时),否则省略。其中 heartbeat-timeout 表示 Gateway 做出了"错过 pong"的判定。需要清醒认识的是:它不能证明 ping 确实到达了对端,也不能证明是对方造成了传输故障

当发生 heartbeat-timeout 时,记录还会在终止前捕获以下事实:

  • pingWriteStatepending(未观察到写回调)、completed(本地写完成)或 failed(写入出错)。同样地,pending 不代表 ping 一定没发出,completed 也不代表对端已收到。
  • lastPongAgeMs:距离最后一次观察到的 pong 所经过的单调时钟毫秒数;若从未观察到 pong 则省略。
  • bufferedBytes:超时判定时刻的本地 WebSocket 缓冲总量——它是聚合缓冲状态,而非某个单独 ping 的投递状态。

这些字段的设计意图非常明确:把"本地能观测到的事实"与"无法观测的网络对端状态"严格区分开,避免诊断者被误导。

稳定性记录器(Stability Recorder)

环形缓冲区的有界记录流

当诊断功能启用时(默认启用),Gateway 会记录一条有界、无负载的稳定性事件流,只捕获运维事实,不捕获内容。从 src/logging/diagnostic-stability.ts 的源码可以看到其实现骨架:

  • 采用环形缓冲区(ring buffer)设计,默认容量 1000 条事件(DEFAULT_DIAGNOSTIC_STABILITY_CAPACITY = 1000L10);
  • 默认快照上限 50 条(DEFAULT_DIAGNOSTIC_STABILITY_LIMIT = 50),最大可达容量上限 1000
  • 每条事件记录 DiagnosticStabilityEventRecord 都是严格脱敏的结构化字段(L20-L100):包含 seq(序号)、ts(时间戳)、type(事件类型),以及可选的 channelpluginIddurationMsrequestBytesresponseBytescostUsdqueueDepthmemoryusage 等——全部是度量与标识,不含任何聊天内容。

该事件流包含了 Gateway 在运行中产生的一大批诊断事件类型(如 payload.largediagnostic.memory.pressure 等)。对支持与调优场景,可以通过 --type 精确过滤查看。

实时检查记录器

openclaw gateway stability
openclaw gateway stability --type payload.large
openclaw gateway stability --json

对应的 CLI 参数在 docs/cli/gateway.md 中有完整定义:

  • --limit <limit>:最多返回最近的事件数,默认 25,最大 1000
  • --type <type>:按诊断事件类型过滤,例如 payload.largediagnostic.memory.pressure
  • --since-seq <seq>:只返回某个诊断序号之后的事件。

检查最新的持久化 bundle

在致命退出(fatal exit)、关闭超时(shutdown timeout)或重启启动失败(restart startup failure)之后,可以检查最新持久化的 bundle:

openclaw gateway stability --bundle latest

--bundle latest(或裸 --bundle)会选取状态目录下最新的 bundle;也可以直接传一个 bundle JSON 路径。--limit--type--since-seq 同样适用于 bundle 输出。

从最新 bundle 直接生成诊断 zip

openclaw gateway stability --bundle latest --export

这会基于最新持久化 bundle 直接产出一个可分享的支持诊断 zip(可配合 --output 指定输出路径)。

持久化 bundle 的存放位置为 ~/.openclaw/logs/stability/(当有事件时),文件名形如 openclaw-stability-<timestamp>-<pid>-<reason>.json。从 src/logging/diagnostic-stability-bundle.ts 可以看到这一机制的实现细节:

  • bundle 版本号 DIAGNOSTIC_STABILITY_BUNDLE_VERSION = 1L23),读取时对不支持的版本直接拒绝;
  • 单文件上限 MAX_DIAGNOSTIC_STABILITY_BUNDLE_BYTES = 5 * 1024 * 1024(5 MB,L26),防止超大 bundle 被误读;
  • 默认保留最近 20 个 bundle,写入新 bundle 时会自动裁剪更旧的(pruneOldBundlesL872-L903);
  • bundle 通过 replaceFileAtomicSync 原子写入,目录权限 0o700、文件权限 0o600,确保即使包含敏感过程信息也不被其他用户读取;
  • 通过 installDiagnosticStabilityFatalHookL982-L992)注册致命错误钩子,使 fatal exit 时自动落盘 bundle。

心跳采样:事件循环与 CPU 压力告警

同一个心跳机制还会在事件循环或 CPU 看似饱和时采样存活状态(liveness),发出 diagnostic.liveness.warning 事件,携带:

  • 事件循环延迟(event-loop delay)与事件循环利用率(event-loop utilization)
  • CPU 核心占比(CPU-core ratio)
  • 活跃/等待/排队中的会话数(active/waiting/queued session counts)
  • 当前启动/运行阶段(当已知时)与最近的阶段耗时区间
  • 有界的工作标签(bounded work labels)

这些事件何时升级为 Gateway 的 warn 级日志行,有一套明确的判定规则:

  • 有工作处于等待或排队状态时;
  • 活跃工作与持续性的事件循环延迟重叠时;
  • Gateway 报告至少 60 秒的持续劣化时(即使没有跟踪到活跃工作,持续劣化也可能告警)。

其余空闲时的 liveness 采样仅作为诊断事件保留,不升级为告警。

启动阶段计时

启动阶段会发出 diagnostic.phase.completed 事件,携带墙钟时间(wall-clock)与整个进程的 CPU 计时,包括 worker 线程与原生线程。需要注意两点:

慢会话补丁(slow session patch)诊断

当诊断启用时,任何持续至少 1 秒的 sessions.patchsessions.patchMany 调用都会在文件日志中追加一条 info 级的 slow session patch 记录,包含:

  • elapsedMs:总耗时;
  • phaseDurationsMsphaseCounts:区分生命周期准入(lifecycle admission)、快照读取、目录准备、投影(projection)、提交、运行时确认、副作用(effects)与响应工作。

这些记录继承请求的诊断 trace(当可用时),并且只包含固定的阶段名称与数字,绝不包含补丁值或会话键。重复访问同一阶段会计入次数与总量;并行与嵌套阶段可以重叠,因此它们的总量既不是请求时间的排他性分解,也不是 CPU 测量值。

SQLite 会话写入警告的三段式耗时

SQLite 会话写入警告会进一步拆分:

  • queueWaitMs:从请求入队到 writer 开始执行的时间;
  • writerExecutionMs:在 writer 通道内的工作与等待时间;
  • completionDelayMs:writer 执行完毕后到调用方恢复的时间。

需要注意,writer 执行时间不是 SQLite 事务锁的持有时间——原生事务锁的等待与持有告警是独立记录的。在进入 writer 之前就被拒绝的写入会省略这三个字段。这个拆分只出现在文件日志中,不会进入 Gateway RPC 的 Prometheus 聚合直方图。

这些警告还包含 writer 的 pid、Node threadIdisMainThread;回收回调还会记录 reclamationKind,以及在创建了 Worker 时捕获的 workerThreadId。在同一进程生命周期内,可以把警告中的 pid/workerThreadId 与 agent-database-open 警告中的 pid/threadId 匹配,从而识别出被等待的 Worker——这建立的是关联关系,不是 CPU 归因或 Worker 生命周期的分解;缺失 Worker id 也不能证明工作运行在主线程上。

停滞的内嵌运行标记

停滞的内嵌运行(embedded run)诊断会在以下情况标记 terminalProgressStale=true:最后一次 bridge 进度看起来已经终结(例如原始响应项或响应完成事件),但 Gateway 仍认为内嵌运行处于活跃状态。这是识别"进度卡死但进程未结束"类问题的重要信号。

实用选项:完整参数表

组合使用限制日志规模的典型命令:

openclaw gateway diagnostics export \
  --output openclaw-diagnostics.zip \
  --log-lines 5000 \
  --log-bytes 1000000

完整参数表如下(与 docs/cli/gateway.md 一致):

Flag 默认值 说明
--output <path> $OPENCLAW_STATE_DIR/logs/support/openclaw-diagnostics-<timestamp>-<pid>.zip 写入指定的 zip 路径(或目录)
--log-lines <count> 5000 包含的最大脱敏日志行数
--log-bytes <bytes> 1000000 检查的最大日志字节数
--url <url> - 用于状态/健康快照的 Gateway WebSocket URL
--token <token> - 用于状态/健康快照的 Gateway token
--password <password> - 用于状态/健康快照的 Gateway 密码
--timeout <ms> 3000 状态/健康快照超时(毫秒)
--no-stability-bundle off 跳过持久化稳定性 bundle 查找
--json off 输出机器可读的导出元数据

其中 --url/--token/--password 用于在 CLI 与 Gateway 分离部署(例如远程 Gateway)时,让导出命令能够连接到 Gateway 抓取 status/health 快照;--timeout 控制这一抓取的最长等待时间。--log-lines--log-bytes 是一对配合使用的护栏:前者限制写入 zip 的日志行数,后者限制扫描日志文件时读取的最大字节量,两者共同防止超大日志拖垮导出过程。

禁用诊断

诊断功能默认开启。如需关闭稳定性记录器与诊断事件收集,在配置文件中设置:

{
  diagnostics: {
    enabled: false,
  },
}

需要明确的是:禁用诊断只降低 Bug 报告的信息丰富度,不影响正常的 Gateway 日志。普通日志照常输出,只是不再收集稳定性事件流与诊断事件。

另外,内存压力事件会记录 RSS、堆、阈值与增长事实(rss_thresholdheap_thresholdrss_growth),但不会执行文件系统扫描,也不会在 OOM 前写入快照——这是有意的设计取舍,避免在内存紧张的临界状态下再引入额外的 IO 开销。相关实现可见 src/logging/diagnostic-stability-bundle.tsevidence.memoryPressure 的结构(L70-L82)。

典型排查工作流

综合以上机制,一个面向崩溃/重启/内存压力问题的标准排查流程可以这样组织:

  1. 现场直接导出:在问题可复现时,立即运行 openclaw gateway diagnostics export --json,拿到完整现场包。
  2. 检查稳定性记录:运行 openclaw gateway stability --type diagnostic.memory.pressure(或按需换成其他类型),查看最近的内存压力/负载事件,确认是否存在 rss_growthqueueDepth 增长等先兆。
  3. 利用崩溃现场:如果 Gateway 已 fatal exit,直接 openclaw gateway stability --bundle latest 读取崩溃瞬间自动落盘的 bundle,再 --export 转为可分享 zip。
  4. 核对健康与日志:结合 Gateway 健康检查 中的事件循环/CPU 压力指标,以及 日志 中的慢会话补丁、SQLite 写入警告字段,交叉定位瓶颈。
  5. 分享前自检:打开 summary.mdmanifest.json,确认没有意外的原始会话 id 或主机名后再外发。

相关文档导航

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525