关于 o11y-logging
o11y-logging 是 JoelClaw 技能,用于在系统、Worker 和 Gateway 代码中添加及排查结构化可观测性。它规定事件约定、发送路径和验证步骤,以减少静默故障与重放噪声。
主要功能
- 01规范化结构化事件契约
- 02Worker 和 Gateway 发送模式
- 03事件字段与严重级别约定
- 04OTEL 投递与冒烟检查
- 05Inngest 重放与挂起排查
适用场景
- 01为 Worker 或 Gateway 改动添加遥测
- 02检查可观测性数据的接收端投递
- 03排查 Inngest 重放后的重复事件
- 04诊断卡住或失败的持久化运行
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ joelhooks/ joelclaw --skill o11y-logging安装后在 Claude Code 中输入/o11y-logging确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/small-logo.svgreferences/implementation-checklist.mdscripts/otel-smoke.sh详细介绍
JoelClaw 可观测性 + 日志记录
默认防止静默失败。可观测性不是可有可无的润色,而是完成工作的一部分。
不容妥协的规则
- 仅使用规范事件约定。
packages/system-bus/src/observability/otel-event.tspackages/system-bus/src/observability/emit.tspackages/system-bus/src/observability/store.ts
- Worker/Inngest 代码通过
emitOtelEvent或emitMeasuredOtelEvent发出事件。 - Gateway 代码通过
emitGatewayOtel发出事件。 - 内部数据接入通过
POST /observability/emit(packages/system-bus/src/serve.ts)进行,不要临时写入。 - 绝不要将
console.log视为主要可观测性手段。结构化事件才是事实来源。 - 高基数值放在
metadata中,而非维度字段(source、component、level、success)中。 - 失败必须设置
success: false,并提供有意义的error。 - 确认数据已送达当前遥测配置要求的接收端。先检查镜像是否启用;已停用或可选的镜像不会阻碍无关工作。
- 在 Inngest 持久化函数中,任何“仅发出一次”的遥测都必须放在
step.run(...)内,以避免恢复后重放导致重复。
事件约定
source:子系统(worker、gateway、webhook、memory、verification等)component:稳定的模块/服务名称(check-system-health、redis-channel、observe)action:稳定的点分隔操作名称(system.health.checked、events.immediate_telegram)metadata:请求 ID、部署 ID、函数 ID、会话 ID、负载标识符duration_ms:定时操作需包含此字段
采用每跳一个事件的方式(宽事件风格):每个主要边界/操作发出一个包含丰富上下文的事件,而不是散落的字符串日志。
实施工作流
- 确定要更改的边界。
- Inngest 函数、gateway 通道、webhook 路由、API 路由、后台任务、同步步骤。
- 添加成功和失败事件封装。
- 长任务添加开始和完成事件;短任务添加单个完成事件。
- 在
metadata中包含运维和业务上下文。- 示例:函数 ID、事件 ID、提供方、队列深度、受影响的资源 ID。
- 保持严重级别有实际意义。
- 正常活动使用
debug/info;可恢复的降级情况使用warn;失败使用error/fatal。
- 正常活动使用
- 完成前运行验证关卡。
完整清单和命令示例请参阅 references/implementation-checklist.md。
快速模式
Worker / Inngest 定时操作
import { emitMeasuredOtelEvent } from "../../observability/emit";
await emitMeasuredOtelEvent(
{
level: "info",
source: "worker",
component: "content-sync",
action: "content_sync.run",
metadata: { trigger: event.name },
},
async () => {
await runSync();
}
);
Gateway 发出事件
import { emitGatewayOtel } from "../observability";
await emitGatewayOtel({
level: "error",
component: "redis-channel",
action: "events.immediate_telegram",
success: false,
error: "telegram_send_failed",
metadata: { sessionId, queueDepth },
});
CLI 发出事件
使用 --metadata 提供 JSON 上下文。没有 --attributes 标志。
joelclaw otel emit "task.completed" \
--source system \
--component skills \
--success true \
--metadata '{"session":"NimbleBadger","task":"install wzrrd-publish skill"}'
完成定义
- 已为更改的路径添加结构化 OTEL 事件。
- 不直接向 Typesense/Convex 写入功能级可观测性数据。
- 冒烟探测通过(
scripts/otel-smoke.sh)。 joelclaw otel list和joelclaw otel stats显示预期行为。- 可通过
source、component和action查询新的失败模式。
Inngest 重放 + 挂起问题排查
当步骤代码看似已运行,但运行状态仍为 RUNNING/CANCELLED 且出现 Finalization 错误时,请按此操作。
- 先检查运行跟踪。
joelclaw run <run-id>
查找包含 Unable to reach SDK URL 的 errors.Finalization.stack。
- 确认问题是实际的网络连通性故障,还是 worker 侧阻塞。
joelclaw inngest status
joelclaw logs worker --lines 200
joelclaw logs errors --lines 200
- 检查 OTEL 中是否存在重放噪声。
如果某个本应只发出一次的操作(例如 manifest.archive.prereqs-passed)在一次运行窗口内出现数百次,请将该事件发出操作移入独立的 step.run。
joelclaw otel search "manifest.archive.prereqs-passed" --hours 1
- 将
Unable to reach SDK URL视为含义不明确的症状。
这可能表示入口流量有问题,但实际上也可能是函数处理程序被本地 IO/依赖项阻塞过久,导致无法完成最终处理。
辅助脚本
使用 scripts/otel-smoke.sh 快速执行端到端探测:
./skills/o11y-logging/scripts/otel-smoke.sh verification o11y-skill probe.emit
Key Files
packages/system-bus/src/observability/otel-event.tspackages/system-bus/src/observability/emit.tspackages/system-bus/src/observability/store.tspackages/system-bus/src/serve.tspackages/gateway/src/observability.tspackages/system-bus/src/inngest/functions/check-system-health.tspackages/cli/src/commands/otel.tsapps/web/app/api/otel/route.ts
评论
支持 Markdown