16 KiB
日志规范
本文件是 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 一眼结果 | 禁止作为唯一失败记录 |
| 业务表 | 用户可见业务结果 | 有业务才建;不是默认排障通道 |
硬规定:
- 没有关键节点文件日志 = 客户现场不可排障。
emit≠ 文件日志:任务中心有进度,而jiangchang.log只有cli_start,视为交付不合格。- 失败出口必须先写文件日志,再
print/finish:凡print(...ERROR:...)、finish(status=failed|partial)、队列mark_failed,同一出口须有log.warning/log.exception(含error_code=或task_failed)。 - 域模块也要打点:
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:progressJSON;进度只走 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。
技能作者三件事:
cmd_run外包with job_context(skill=SKILL_SLUG):- 关键步骤
emit(...)或@rpa_step/video.add_step - 每个出口
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. 错误排查顺序
客户现场或测试机排障,建议按以下顺序(由快到慢、由用户可见到运维细节):
- CLI stdout — 是否有
ERROR:<CODE>:、HINT:、模板提示文案。 - 任务中心 / Run Journal —
{JIANGCHANG_DATA_ROOT}/.jiangchang/runs/{job_id}.jsonl(进度与finish终态)。 - 统一日志文件 —
{JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/logs/jiangchang.log(greptrace_id、task_failed)。 - 业务表 — 宿主数据管理中该技能自己的业务结果(有才建)。
- 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 索引 |