Files
verify-invoice-default/development/LOGGING.md

16 KiB
Raw Blame History

日志规范

本文件是 skill 日志规范的权威入口,面向技术人员与 AI 编程代理。涉及长任务、RPA、外部系统对接的技能,必须在实现前通读本文。

自动 hard policy(POLICY-LOGGING-001~008)只保证底线;阶段是否够细仍须对照本文事件词表做 review。复制技能后可用 tests/samples/test_logging_contract.py.sample 做契约断言。


0. 验收铁律(先读)

通道 给谁看 能否单独当排障依据
统一文件日志 jiangchang.log 运维 / 离线打包 必须能单独定位到失败阶段与 error_code
Activity / 任务中心 emit / finish 用户进度与终态 不能替代文件日志
print / stdout CLI 一眼结果 禁止作为唯一失败记录
业务表 用户可见业务结果 有业务才建;不是默认排障通道

硬规定:

  1. 没有关键节点文件日志 = 客户现场不可排障。
  2. emit ≠ 文件日志:任务中心有进度,而 jiangchang.log 只有 cli_start,视为交付不合格。
  3. 失败出口必须先写文件日志,再 print / finish:凡 print(...ERROR:...)、finish(status=failed|partial)、队列 mark_failed,同一出口须有 log.warning / log.exception(含 error_code= 或 task_failed)。
  4. 域模块也要打点:scripts/service/<domain>/、*_flow.py、*_driver.py 等业务文件不得零日志(见 POLICY-LOGGING-006)。

1. 为什么日志是必需的

OpenClaw 技能常在客户电脑上异步执行,且大量依赖 RPA、浏览器、ERP、微信等外部系统。这类任务具备以下特征:

  • 耗时长:单次 run 可能数分钟甚至更久,stdout 长时间无输出不代表卡死。
  • 失败点多:网络抖动、页面改版、登录态失效、验证码、U 盾等都会导致中途失败。
  • 环境差异大:客户 OS、浏览器版本、代理、杀毒软件、屏幕分辨率各不相同,无法复现开发机行为。
  • 必须离线排查:技术支持往往无法远程登录客户电脑,只能依赖本地落盘的日志与 artifacts。

日志用于定位:

维度 说明
失败阶段 任务停在鉴权、取号、打开页面、提交还是等待结果
输入范围 task_type、target_id、input_id、batch_id
外部系统状态 HTTP 状态、RPA 步骤、兄弟技能返回码
耗时 elapsed_ms、批量 current/total
重试与人工介入 第几次重试、是否等待验证码 / U 盾
存证路径 截图、录屏、video_log、失败 artifacts

2. 日志分层

技能日志分三层,职责互不替代:

2.1 统一文件日志(开发 / 运维排查)

来源:jiangchang_skill_core.unified_logging(技能内通过 util.logging_config 薄封装 import)。

API 用途
setup_skill_logging CLI 入口启动时初始化(cli/app.py 的 main())
get_skill_logger 获取带 skill_slug 的 logger
subprocess_env_with_trace 子进程 / 兄弟技能调用时传递 trace_id

路径:

{JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/logs/jiangchang.log

特征:每行带 trace_id、skill_slug;适合 grep、离线打包发给技术支持。

2.2 Activity / Run Journal(宿主 UI 与用户可见进度)

来源:jiangchang_skill_core.activity

API 用途
emit 推送用户可读进度(不写 stdout);进入步骤前自动步骤闸门(SRCP)
step 结构化步骤
finish 任务结束;唯一写单行 result JSON 到 stdout 的场景
job_context 包裹 cmd_run;未捕获异常 / JobStopped 时自动 finish
rpa_step RPA 专用步骤:闸门 + ▶/✓ emit
interruptible_sleep RPA 等待(替代裸 asyncio.sleep),可暂停/停止
checkpoint 长循环内 consult control(一般由 kit 自动调用)

路径:

{JIANGCHANG_DATA_ROOT}/.jiangchang/runs/{job_id}.jsonl

约定:

  • emit 不写 stdout;长任务应持续 emit,避免用户以为卡死。
  • finish 才输出单行 result JSON 供宿主解析。
  • RPA 类技能:RpaVideoSession.add_step 会自动同步 activity(无需重复手写每步 emit)。
  • 禁止自建 scripts/util/progress.py 或向 stdout 打印 type:progress JSON;进度只走 Run Journal。
  • 宿主通过 {job_id}.control.json 下发暂停/继续/停止;技能侧由 platform-kit 在步骤闸门自动处理(见 §2.5)。

2.5 步骤控制(SRCP v1,platform-kit >= 1.2.0)

权威行为定义在本文;platform-kit README 为实现细节参考。

通道 方向 载体
进度 技能 → 宿主 Run Journal(emit / rpa_step / add_step)
结果 技能 → 宿主 finish() → Journal 终态 + stdout 一行 result
控制 宿主 → 技能 {JIANGCHANG_DATA_ROOT}/.jiangchang/runs/{job_id}.control.json

control.json 的 command 只认:none | pause | resume | stop。

技能作者三件事:

  1. cmd_run 外包 with job_context(skill=SKILL_SLUG):
  2. 关键步骤 emit(...) 或 @rpa_step / video.add_step
  3. 每个出口 finish(status=..., message=..., skill=SKILL_SLUG, **fields) — 不要手写多行 JSON 结果

单内核多入口:execute_single_* 不含 job_context;仅 cmd_run / cmd_run_pick 包裹。批量 pick 循环内 checkpoint() + emit(..., progress=...);部分失败用 finish(status="partial")。完整范式见 SKILL_ACTION_RUNTIME.md。

RPA 等待用 interruptible_sleep,不要裸 asyncio.sleep(否则暂停响应滞后)。

暂停在步骤边界生效(当前 @rpa_step / emit 执行完后、下一步开始前),与影刀「当前指令完成后暂停」一致。

Journal 会写入 type: lifecycle 事件(paused / resumed / stopping),供宿主任务中心显示状态。

2.3 可观测性三分法(禁止 task_logs)

信息类型 去哪里 技能怎么做
过程(步骤、异常栈、排查) jiangchang.log / 宿主「运行日志」 log.info / log.exception,关键节点见 §3
进度 / 终态(任务中心) Run Journal:emit / finish job_context + finish(status=...)
业务结果 业务表字段(status、产物路径、统计等) repository 回写;见 WORK_ITEM_STATUS.md

模板默认不建 task_logs 等通用任务审计表。不要用业务表冒充任务进度,也不要用任务表代替业务状态机。

2.4 RPA video step / artifacts(用户可见动作与存证)

来源:RpaVideoSession、rpa-artifacts/ 目录

  • video artifact 是标准可启用能力,不保证默认每次生成 MP4(模板默认 OPENCLAW_RECORD_VIDEO=0)。
  • OPENCLAW_RECORD_VIDEO=0:不生成最终录屏,但 RPA / 长任务仍须保留 RpaVideoSession、video.add_step 与 Activity 进度同步。
  • OPENCLAW_RECORD_VIDEO=1:finish() 字段应包含 video_path、raw_video、video_log、video_warnings 等;CLI 可打印录屏路径与诊断。
  • 用户可见的中文步骤(「打开登录页」「点击提交」)。
  • 失败截图:{数据目录}/rpa-artifacts/{batch_id}/...(受 OPENCLAW_ARTIFACTS_ON_FAILURE 控制,默认开)

详见 RPA.md §5 存证与录屏规范。


3. 固定事件词表(生产代码须出现)

日志消息推荐 key=value。下列事件名字符串须出现在 log.info / log.warning / log.exception 的消息中(可用 f-string / %s,但事件名本身须可 grep)。

3.1 长任务通用最低集(所有业务 skill)

事件名 级别 说明
cli_start info CLI 入口(模板已提供)
task_start info 主任务开始(含 task_type=)
entitlement_ok / entitlement_failed info / warning 鉴权结果
item_start / item_done info 批量逐条时;单条可用 task_start/task_success 代替
task_success 或 task_failed info / warning|exception 终态;失败须含 error_code=

3.2 RPA / 桌面 / 浏览器额外最低集

当 scripts/service/ 使用 RpaVideoSession / uiautomation / playwright / @rpa_step 时,额外要求:

事件名 说明
rpa_start / rpa_done 或 rpa_failed RPA 段起止(可与 task_* 同条合并,但事件名须可 grep)
stage= 至少 3 个不同阶段里程碑(如 open_window / locate_control / submit / wait_result)
risk_blocked 若有配额/工作时段/熔断等前置拦截

不要要求每个 Click 一行日志;要求的是阶段里程碑 + 全部失败出口。

3.3 其它常见节点(按业务选用)

阶段 建议事件
adapter 选择 adapter_selected adapter=...
账号 / lease account_acquired / account_released
外部 API external_call_start / external_call_done(含 elapsed_ms= / status=)
兄弟技能 sibling_call_start / sibling_call_done
重试 / 跳过 / 人工 retry_attempt / skipped / human_intervention
存证 artifact_saved / video_path=

3.4 最低可验收日志串(示例)

mock 或真实跑完一条主路径后,jiangchang.log(或宿主「运行日志」)应能 grep 到类似:

cli_start argv=...
task_start task_type=add-one target_id=...
entitlement_ok task_type=add-one
rpa_start stage=open_window
rpa_start stage=locate_control
rpa_start stage=submit
task_failed error_code=ELEMENT_NOT_FOUND ...

成功路径则出现 task_success 而非 task_failed。若只有 cli_start → 不合格。


3.5 必打节点与 Activity 对照

以下节点除文件日志外,长任务仍应 emit / video.add_step(用户可见),但不能只 emit 不打文件日志。

阶段 文件日志 Activity
任务开始 task_start emit("开始…")
RPA 步骤 stage=... add_step / @rpa_step
批量进度 item_start / batch_progress emit(..., progress=)
失败 task_failed error_code= finish(failed|partial)

4. 字段规范

推荐在 log.info 等消息中使用 key=value 结构化字段,便于 grep:

字段 含义
task_type 任务类型
target_id 目标标识(平台、店铺、报表类型等)
input_id 输入记录 ID
batch_id 批次 / 录屏批次
stage 阶段:auth / run / cleanup
system 外部系统名:erp / wechat / 1688
operation 操作名:submit_order / fetch_report
adapter adapter 档位:mock / simulator_api / real_api
elapsed_ms 耗时毫秒
status ok / failed / timeout / skipped
error_code 业务错误码(非 Python 异常名)
artifact_path 截图 / 附件路径
video_path 录屏成品路径

示例:

external_call_done system=erp operation=download_report elapsed_ms=4523 status=ok
batch_progress current=7 total=20 target_id=store-001

5. 日志级别规范

级别 使用场景
info 关键阶段、成功路径、外部调用开始/结束、批量进度
warning 可恢复问题、重试、跳过、人工介入、部分失败、鉴权失败(业务可预期)
exception 异常路径;必须用 log.exception(...) 保留 traceback
debug 低频诊断;默认不依赖 debug 才能排查问题

原则:生产排障应主要靠 info + warning + exception,不要把 debug 当作唯一线索。


6. 敏感信息红线

禁止记录原始值

以下字段不得以明文出现在日志、Activity、finish() 字段、stdout:

  • password、token、cookie、secret、api_key、authorization
  • 验证码、动态口令全文
  • 身份证、银行卡、手机号完整值

建议记录的安全替代

替代字段 示例
credential_ref vault / account-manager 引用 ID
account_id 账号表主键
masked_user 138****8000
domain erp.example.com
last4 卡号后四位
hash / short_id 内容摘要

变量名可以叫 token,但日志里不能出现 token=eyJhbG... 或 f-string 拼接明文。


7. 推荐代码示例(service 层)

from util.logging_config import get_skill_logger
from jiangchang_skill_core.activity import emit, finish, job_context, rpa_step, interruptible_sleep

from util.constants import SKILL_SLUG

log = get_skill_logger()

def cmd_run(target=None, input_id=None):
    task_type = "your_task"
    with job_context(skill=SKILL_SLUG):
        log.info(
            "task_start task_type=%s target_id=%s input_id=%s",
            task_type, target, input_id,
        )
        emit("开始处理任务", skill=SKILL_SLUG, stage="run")
        try:
            ok, reason = check_entitlement(SKILL_SLUG)
            if not ok:
                log.warning("entitlement_failed task_type=%s reason=%s", task_type, reason)
                finish(status="failed", message=reason, skill=SKILL_SLUG, error_code="ENTITLEMENT_DENIED")
                return 1

            t0 = time.monotonic()
            # ... 外部调用 / RPA:@rpa_step 或 video.add_step;等待用 interruptible_sleep ...
            elapsed_ms = int((time.monotonic() - t0) * 1000)
            log.info(
                "external_call_done system=%s operation=%s elapsed_ms=%d status=%s",
                "erp", "submit", elapsed_ms, "ok",
            )

            finish(status="success", message="任务完成", skill=SKILL_SLUG)
            return 0
        except Exception:
            log.exception(
                "task_failed task_type=%s target_id=%s input_id=%s",
                task_type, target, input_id,
            )
            emit("任务失败,已记录诊断信息", type="warn", skill=SKILL_SLUG, stage="run")
            finish(status="failed", message="任务执行异常", skill=SKILL_SLUG)
            return 1

模板示范见 scripts/service/task_service.py 的 cmd_run。


8. 错误排查顺序

客户现场或测试机排障,建议按以下顺序(由快到慢、由用户可见到运维细节):

  1. CLI stdout — 是否有 ERROR:<CODE>:、HINT:、模板提示文案。
  2. 任务中心 / Run Journal — {JIANGCHANG_DATA_ROOT}/.jiangchang/runs/{job_id}.jsonl(进度与 finish 终态)。
  3. 统一日志文件 — {JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/logs/jiangchang.log(grep trace_id、task_failed)。
  4. 业务表 — 宿主数据管理中该技能自己的业务结果(有才建)。
  5. RPA artifacts — rpa-artifacts/ 失败截图;若 OPENCLAW_RECORD_VIDEO=1 还有录屏 MP4、video_log。未开启录屏时可能只有截图或日志,需要完整录屏请在用户 .env 中设置 OPENCLAW_RECORD_VIDEO=1。

长时间无 stdout 不代表卡死;先看 Run Journal / Activity,再看统一日志。


9. 与现有文档关系

文档 关系
RUNTIME.md 统一日志能力来源、util.logging_config 薄封装、数据根约定
TESTING.md 日志相关 hard policy 测试(test_development_policy_guard.py)
RPA.md RPA step、RpaVideoSession、video / artifacts 标准
SCHEMA.md 业务表结构与展示元数据
CLI.md 最小命令与手工排查入口
CONFIG.md 敏感配置不进日志;.env 边界
DEVELOPMENT.md service/ 层日志职责与发布前检查清单
SKILL_ACTION_RUNTIME.md 任务中心 / async Job 与 job_context 边界
POLICY_MATRIX.md 可自动检测的 logging hard policy 索引