做 #5636 时对 packages/services/service-automation/src/plugin.ts 全文扫同类形态的结果。
#5048 / PR #5572 修了 flow 绑定四+一处,#5575 / PR #5639 修了 fail() 两处,#5636 修了
degradeConnectorInstance 两处;下面三处三单都没覆盖,单开记录。
行号基于 origin/main 5b60b3669。
三处
-
plugin.ts:454 —— manifest 服务不可用(warn):
ctx.logger.warn(
`[Automation] manifest service unavailable; sys_automation_run not registered yet: ${(err as Error).message}`,
);
-
plugin.ts:592-594 —— 启动时读不到 sys_automation_run(error):
ctx.logger.error(
`[Automation] sys_automation_run could not be read at startup — if this persists, suspended runs will NOT ` +
`survive a restart. Check that schema sync ran for this datasource: ${(err as Error).message}`,
);
err 来自 candidate.probe(),即数据源驱动抛出的错误。
-
plugin.ts:931-936 —— 重启后 wait-timer 重新挂载失败(error):
ctx.logger.error(
`[Automation] suspended wait-timer re-arm FAILED after restart — … Cause: ${(err as Error).message}`,
);
err 来自 job 服务。
为什么第 2、3 条值得单独说
这两条的存在理由就是可读性:它们各自的代码注释写明了后果 ——「suspended runs will NOT
survive a restart」、「every wait/approval paused before this restart will hang indefinitely」
—— 并特意选在 error 而不是 warn(第 3 条的注释原文:「so it is reported at error, not
warn」)。一条被搅烂的耐久性告警,恰好是运维最需要能 grep 到、能按字段过滤的那一条。
这就是 #4632 的原则:被搅烂的诊断比没有诊断更贵。
机制与 #5048 / #5575 / #5636 完全相同:ObjectLogger 每次调用只写一条
<ts> <LEVEL> <msg> 记录,带换行的 message 溢出到不带等级头的物理行,文件 sink /
docker logs+journald 送采集 / grep ERROR 都把续行读成无法归属的碎片。第 1 条是 warn
→ stdout,冷启动时还会被 BootLogCapture 直接丢掉续行(#5636 实测:13 行进,保留 1 行,
丢 12 行)。
刻意不含在内的两处(说明理由,免得下一个人重复扫)
可达性(finding 而非 bug)
三处的 err 都来自我们不控制文本的地方(kernel service registry、datasource 驱动、
job 服务),但今天在库内的实现里这些 message 都是单行。第一个包装了多行 SDK 错误的驱动
或 job 服务实现会撞上;第 2 条尤其 —— 数据库驱动的多行错误在生态里很常见。
修法
与前三单同源、零新词汇:复用同包 thrown-cause-diagnostics.ts 的 describeThrownForLog,
message 保持不含换行的自足句子,cause 走 meta。位置按 Logger 契约:warn(message, meta?)
用第二参,error(message, error?, meta?) 用第三参(第二参塞原始 error 会附带完整堆栈)。
新增字段名不得含 key/token/secret/password 子串(ObjectLogger.redactSensitive 按
子串匹配,见 #5573)。
第 2、3 条改完后建议顺手确认 pnpm check:durability-log-level 仍绿 —— 这两处正在它扫的
24 个耐久性 catch 接缝里。
关联
#5636、#5575 / PR #5639、#5048 / PR #5572、#5573、#4632、#4420(耐久性丢失本身)、cloud#971。
做 #5636 时对
packages/services/service-automation/src/plugin.ts全文扫同类形态的结果。#5048 / PR #5572 修了 flow 绑定四+一处,#5575 / PR #5639 修了
fail()两处,#5636 修了degradeConnectorInstance两处;下面三处三单都没覆盖,单开记录。行号基于 origin/main
5b60b3669。三处
plugin.ts:454—— manifest 服务不可用(warn):plugin.ts:592-594—— 启动时读不到sys_automation_run(error):err来自candidate.probe(),即数据源驱动抛出的错误。plugin.ts:931-936—— 重启后 wait-timer 重新挂载失败(error):err来自 job 服务。为什么第 2、3 条值得单独说
这两条的存在理由就是可读性:它们各自的代码注释写明了后果 ——「suspended runs will NOT
survive a restart」、「every wait/approval paused before this restart will hang indefinitely」
—— 并特意选在
error而不是warn(第 3 条的注释原文:「so it is reported aterror, notwarn」)。一条被搅烂的耐久性告警,恰好是运维最需要能grep到、能按字段过滤的那一条。这就是 #4632 的原则:被搅烂的诊断比没有诊断更贵。
机制与 #5048 / #5575 / #5636 完全相同:
ObjectLogger每次调用只写一条<ts> <LEVEL> <msg>记录,带换行的 message 溢出到不带等级头的物理行,文件 sink /docker logs+journald 送采集 /grep ERROR都把续行读成无法归属的碎片。第 1 条是warn→ stdout,冷启动时还会被
BootLogCapture直接丢掉续行(#5636 实测:13 行进,保留 1 行,丢 12 行)。
刻意不含在内的两处(说明理由,免得下一个人重复扫)
plugin.ts:191(package file ref … could not be read: ${err.message})是一个throw,不是日志记录。finding(service-automation): connector 物化失败的fail()也是${err.message}单行插值,同 #5048 的类别、另一个接缝 #5575 已经把这条界线写进thrown-cause-diagnostics.ts:抛出的message 由内核失败通道原样打印,既不需要单行也不需要有界,多行 dump 在终端里本来就好读。
这里应当保持现状。
plugin.ts:729(runAs:user grant resolver not wired)是debug,而且err是内核服务查找失败 —— 是我们自己的单行文本,不是外来值。
可达性(finding 而非 bug)
三处的
err都来自我们不控制文本的地方(kernel service registry、datasource 驱动、job 服务),但今天在库内的实现里这些 message 都是单行。第一个包装了多行 SDK 错误的驱动
或 job 服务实现会撞上;第 2 条尤其 —— 数据库驱动的多行错误在生态里很常见。
修法
与前三单同源、零新词汇:复用同包
thrown-cause-diagnostics.ts的describeThrownForLog,message 保持不含换行的自足句子,cause 走 meta。位置按
Logger契约:warn(message, meta?)用第二参,
error(message, error?, meta?)用第三参(第二参塞原始 error 会附带完整堆栈)。新增字段名不得含
key/token/secret/password子串(ObjectLogger.redactSensitive按子串匹配,见 #5573)。
第 2、3 条改完后建议顺手确认
pnpm check:durability-log-level仍绿 —— 这两处正在它扫的24 个耐久性 catch 接缝里。
关联
#5636、#5575 / PR #5639、#5048 / PR #5572、#5573、#4632、#4420(耐久性丢失本身)、cloud#971。