n8n CLI 监控只搜“error”可靠吗?60 次成功/失败对照
固定 n8n 2.30.5 交替执行 30 次成功与 30 次失败:退出码和结构化状态全部正确,通用失败词搜索却把 30 次成功全部误报。这里公开逐次 CSV、工作流和判定口径。
PUBLIC EVIDENCE PACKAGE
不要只读结论,下载原始记录。
问题不是“日志里有没有 error”
很多轻量监控脚本会把 CLI 输出拼成一段文本,只要出现 error、failed 或 failure 就发告警。实现只需一行正则,看起来比解析 JSON 更省事,但它默认了一个未经验证的前提:成功执行的输出里不会出现这些词。
我们用固定版本 n8n 做了 60 次对照。奇数序号必须成功,偶数序号由 Code 节点抛出 EXPECTED_SIGNAL_FAILURE。测试同时记录进程退出码、通用失败词、精确错误令牌与结构化 execution status,逐次结果和输出哈希全部公开。
固定条件和判定真值
| 项目 | 本次设置 |
|---|---|
| n8n 镜像 | n8nio/n8n:2.30.5 |
| 镜像摘要 | sha256:450853cd…a6dc8c6f |
| Docker Server | 28.3.3 |
| 宿主平台 | darwin / arm64 |
| 网络 | network none |
| 执行命令 | n8n execute --id=… --rawOutput |
| 样本 | 60 次,30 次预设成功、30 次预设失败 |
“真值”不是根据日志词猜出来的,而是由公开协议预先确定:奇数成功,偶数失败。运行后再检查结构化结果是否与协议一致。这样可以分别判断每种探测器,而不是拿一个未经验证的探测器校验另一个。
四种探测器怎样工作
第一种只看进程退出码:0 视为成功,非 0 视为失败。第二种在 stdout 与 stderr 合并文本中搜索通用词 error、failed 或 failure。第三种只搜索本实验预先定义的精确令牌 EXPECTED_SIGNAL_FAILURE。第四种先从 rawOutput 中提取完整 execution JSON,再读取顶层 status 与 resultData 中的错误字段。
| 信号 | 正确数 | 准确率 | 成功误报 | 失败漏报 |
|---|---|---|---|---|
| 进程退出码 | 60 / 60 | 100% | 0 | 0 |
| 通用失败词 | 30 / 60 | 50% | 30 | 0 |
| 精确错误令牌 | 60 / 60 | 100% | 0 | 0 |
| 结构化 execution status | 60 / 60 | 100% | 0 | 0 |
这里的 100% 只描述这 60 次固定实验,不代表任何版本和部署方式下都永远正确。它足以否定的,是“通用错误词可以直接当成状态”的做法。
为什么 30 次成功全部被误报
n8n 2.30.5 在这个容器环境启动 CLI 执行时,会输出一条 Python task runner 未启动的提示,其中包含 Failed。工作流随后仍由 JS Task Runner 正常完成,进程退出码为 0,结构化状态为 success。
通用探测器不理解这段文字是在描述一个未使用的运行器,也不知道最终工作流状态。它看到 Failed 就判失败,因此 30 次成功无一幸免。完整原始日志带有大量机器相关噪声,公开包不直接发布;runs.csv 为每段合并输出保存 SHA-256,samples.json 保存一成一败的规范化信号。
精确令牌为什么正确但仍不够
精确令牌在本次实验中 60/60 正确,因为失败由我们控制,而且每一次都抛出同一个明确标记。真实生产依赖不会如此整齐:HTTP 节点、数据库、凭据、内存和自定义节点会返回不同格式,版本升级也可能改变错误文字。
精确令牌适合识别已知错误类别,不能承担总体健康判断。若只维护一张关键词列表,新错误可能漏报,正常数据里出现同名文本也可能误报。更稳妥的分层是:
- 用进程退出码判断这次 CLI 调用是否成功;
- 用结构化 execution status 再确认工作流状态;
- 从 resultData.error 与节点 error 字段读取分类细节;
- 只有在已知错误协议中,才使用精确代码或令牌分组;
- 将未知非零退出和无法解析的 JSON 单独标为 collector_error,不要强行归类。
可直接采用的监控口径
| 层级 | 建议记录 | 不建议 |
|---|---|---|
| CLI 调用 | 退出码、开始/结束时间、命令版本 | 用任意错误词替代退出码 |
| 工作流执行 | execution status、execution ID | 只保存最后一行文本 |
| 错误分类 | 结构化 message、description、节点名 | 对完整 stdout 做模糊搜索 |
| 完整性 | 原始输出哈希、解析器版本 | 解析失败后默认成功 |
| 告警 | 失败类别、执行 ID、下一步动作 | 把启动警告当业务失败 |
若监控器没有提取到完整 JSON,即使进程退出码为 0,也应把证据状态记为“不完整”,而不是生成一个漂亮的成功统计。这是我们在上一项基线中两次中止无效运行后保留的规则。
这项实验没有证明什么
- 没有覆盖 n8n Cloud、队列模式、Webhook 常驻进程或 Worker;
- 没有测试 429、500、真实超时和第三方 API 的错误格式;
- 没有测试日志采集平台对 stdout/stderr 的拆分、截断或重排;
- 没有证明所有 n8n 版本的退出码契约都相同;
- 没有测试自动重试、告警送达或故障恢复。
因此结论不是“退出码永远够用”,而是:在 n8n 2.30.5 的 execute --rawOutput 测试中,退出码适合作为二元健康信号,结构化 JSON 适合状态与根因分类;通用失败词搜索不适合作为状态契约。
如何复核
下载 workflow.json 导入固定镜像,或运行仓库中的实验脚本。manifest.json 记录镜像摘要和起止时间;runs.csv 提供 60 行探测器结果;samples.json 提供一成一败的规范化样本;summary.json 保存混淆计数、结论与限制。
复跑新版本时,不应覆盖这批记录。应新建版本目录并比较退出码、警告文本与 JSON 结构是否变化,只有这样才能知道升级是否改变了监控契约。
来源与核验日期
- AI Brief Note 原始实验摘要:四种探测器的正确数、误报、漏报与限制。 · 已核验 · generated_from_60_recorded_runs_2026-07-23
- n8n 官方 CLI 文档:工作流导入、导出与执行命令。 · 已核验 · official_site_checked_2026-07-23
- n8n 官方执行记录文档:可按 Failed、Running、Success 与 Waiting 状态筛选执行。 · 已核验 · official_site_checked_2026-07-23