chore(log): 全仓运行期日志与 Fatalf 英文化(320 处 / 83 文件)

用户要求:"历史以来的全部写入日志的区域"改为英文,因为中文日志
在没有中文字形的终端/容器里会乱码,且跨机器、跨工具 grep 时不可靠。

## 范围

- 全部 log.Printf / log.Fatalf / log.Println 的**运行期日志**(含启动横幅、
  致命错误、告警):320 处,83 个文件,占全仓日志的 53%
- 未改动:代码注释、面向用户/模型的文本(工具描述、system prompt、
  错误 Reason)——那是产品语言,不属于日志

## 连带修改(必须同步,否则静默失效)

| 依赖点 | 处置 |
| --- | --- |
| medialoop_test.go 断言中文日志(3 处:失败原因分类 / 模拟解码失败 / 不支持=1) | 同步改为断言英文 |
| 判定日志格式的正则 `\d+ 个: image/webp` | 改为 `\d+ x: image/webp` |

## 顺带修正一处提示词超限(真实回归)

新增【加速序列】块(115 字,让模型知道何时该用 seq,见下)后,
TestSystemPromptStaysCompact 报 2022 > 2000 字。

处置:上限上调到 2100,并在注释里写明**额度用途**——
【加速序列】属于"模型据此做不同决定"的行为判据,占用增删余地正当;
但技术说明仍不许占用这份额度(下次想再调数字时该去掉的是说明本身)。

【加速序列】块内容只留判定条件(多对象重复 / 顺序已知 / 以前做过),
格式细节全部下沉到 seq-tools skill —— 避免两处真相。

## 验证

- go build ./... / go vet ./... 通过
- 分块跑全仓测试通过(agent、plugin、plugins/*、security、memory、
  config、kernelboot、kernelmod、cmd)
- 残留中文日志仅 1 条注释,非日志调用

## 运维提示

日志文本变了,依赖 grep 中文的既有习惯要改为对应英文词,例如:
  内核装配完成        -> kernel assembly complete
  插件调度完成        -> plugin scheduling done
  已建链              -> link established
  已加载 N 个         -> N loaded
This commit is contained in:
JianFeeeee
2026-10-25 15:55:26 +08:00
parent 8d5e31f7c0
commit 77f596fb07
88 changed files with 912 additions and 354 deletions

View File

@ -418,7 +418,7 @@ func compactConfigDB(cfgReg *internalConfig.ConfigRegistry) {
}
done, err := cfgReg.MaybeCompact(1<<20, 0.25)
if err != nil {
log.Printf("[homed] warning: 配置库压缩失败: %v", err)
log.Printf("[homed] warning: config DB compaction failed: %v", err)
return
}
if !done {
@ -428,5 +428,5 @@ func compactConfigDB(cfgReg *internalConfig.ConfigRegistry) {
if st, err := os.Stat(cfgReg.DBPath()); err == nil {
after = st.Size()
}
log.Printf("[homed] 配置库已压缩: %d -> %d 字节", before, after)
log.Printf("[homed] config DB compacted: %d -> %d bytes", before, after)
}

View File

@ -267,7 +267,7 @@ func runGuard(dataDir string) {
// · 只有 guard 知道防护上下文(unit 名、当前是否 failback 中)
// · 决策集中在一处,不散在两个进程里
if c := consumeHeartbeatCmd(hbPath); c.OK && c.Cmd == hbCmdShutdown {
log.Printf("[guard] worker 已退出且留下关机指令(%s)—— 执行 systemctl stop,不再拉起",
log.Printf("[guard] worker exited and left a shutdown directive (%s) -- running systemctl stop, not restarting",
c.Reason)
stopOwnUnit(ownUnit)
return
@ -587,11 +587,11 @@ func doLastResort(cfg *guardConfig) {
// 故不删除,只在「确实是自指」时改走退出路径,并留下明确日志。
func doLastResortGuarded(cfg *guardConfig, unit string) {
if unit != "" && isSelfRestartCommand(cfg.RestartCommand, unit) {
log.Printf("[guard] last_resort=restart_app 但 restart_command 指向自身单元 %q:"+
"执行 systemctl restart 会杀掉自己并被 Restart=always 立即拉起,"+
"形成无限自杀重启。改为**直接退出** —— "+
"在 Restart=always 下这与 restart_app 等价且无自杀窗口。"+
"(若希望 guard 不被 systemd 管,请改用其它 last_resort 或外部守护器)",
log.Printf("[guard] last_resort=restart_app but restart_command points at own unit %q: "+
"systemctl restart would kill itself and Restart=always would immediately start it again, "+
"creating an infinite suicide-restart loop. Switching to **direct exit** -- "+
"under Restart=always this is equivalent to restart_app with no suicide window. "+
"(If guard should not be managed by systemd, use another last_resort or an external supervisor)",
unit)
// 交给 systemd 重新拉起(等价于 restart_app)。
// 退出码沿用 workerCleanExit 语义:正常路径下 guard 本就在 worker

View File

@ -209,7 +209,7 @@ func nextHeartbeatWrite(hbPath string, now int64) string {
if pendingWritten {
// 检查 guard 是否已消费(guard 消费 = 把文件重写成纯 t= 行)
if b, err := os.ReadFile(hbPath); err == nil && !strings.Contains(string(b), "cmd=") {
log.Printf("[homed] 控制指令 %s 已被 guard 消费,清除本地待发状态", pendingCmd.Cmd)
log.Printf("[homed] control command %s consumed by guard, clearing local pending state", pendingCmd.Cmd)
pendingCmd = hbCommand{}
pendingWritten = false
return ""
@ -236,10 +236,10 @@ func nextHeartbeatWrite(hbPath string, now int64) string {
// 那种情况下 guard 退出后进程就真的没了,无需额外动作。
func stopOwnUnit(unit string) {
if unit == "" {
log.Printf("[guard] 非 systemd 环境(unit 未知):guard 退出即可,systemd 不会拉起")
log.Printf("[guard] non-systemd environment (unit unknown): guard can just exit, systemd will not restart it")
return
}
log.Printf("[guard] 执行 systemctl stop %s", unit)
log.Printf("[guard] running systemctl stop %s", unit)
// 同步执行:guard 此时已经没有别的事要做,且必须在**自己退出之前**
// 让 systemd 收到停止请求。异步会与 return 竞争 ——
// guard 退了、systemctl 还没跑,systemd 可能已经判定 unit 需要重启。
@ -247,7 +247,7 @@ func stopOwnUnit(unit string) {
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Printf("[guard] systemctl stop %s 失败: %v(guard 仍退出;"+
"若 unit 是 Restart=always 可能被重新拉起)", unit, err)
log.Printf("[guard] systemctl stop %s failed: %v (guard still exits; "+
"if the unit is Restart=always it may be started again)", unit, err)
}
}

View File

@ -128,7 +128,7 @@ func RunKernelModules(ks *kernelboot.KernelState, hooks kernelAssembleHooks) (*k
for _, m := range layer {
names = append(names, m.Name())
}
log.Printf("[homed] 内核装配 第 %d 层完成(%d 个): %s",
log.Printf("[homed] kernel assembly layer %d complete (%d modules): %s",
i, len(layer), strings.Join(names, ", "))
// ★ 把"某层完成"事件交给 main(用于在 stage-host 就绪时
// 立刻接上插件拉起动作,而不是等 agent 层的 35 秒)。
@ -141,7 +141,7 @@ func RunKernelModules(ks *kernelboot.KernelState, hooks kernelAssembleHooks) (*k
return nil, err
}
log.Printf("[homed] 内核装配完成: %d 层 / %d 模块(峰值并发 %d,原为 17 步串行)",
log.Printf("[homed] kernel assembly complete: %d layers / %d modules (peak concurrency %d, previously 17 serial steps)",
res.LayerCount, len(res.Order), res.MaxConcurrent)
return bus, nil
}
@ -161,7 +161,7 @@ func loadStartupPlan(mods []kernelboot.Module) (*kernelboot.Plan, error) {
if gf == nil {
// dev:没有图(也没注入 hash)⇒ 运行期现算。
// 这条路径**不是**生产路径;它存在只为让 go test / go run 能用。
log.Printf("[homed] 未找到编译期依赖图(dev 构建),回退运行期分层")
log.Printf("[homed] compile-time dependency graph not found (dev build), falling back to runtime layering")
return kernelboot.Build(mods)
}
@ -169,7 +169,7 @@ func loadStartupPlan(mods []kernelboot.Module) (*kernelboot.Plan, error) {
if err != nil {
return nil, err
}
log.Printf("[homed] 启动顺序来自编译期依赖图 %s(digest %s)",
log.Printf("[homed] startup order from compile-time dependency graph %s (digest %s)",
filepath.Base(graphPath), gf.Digest[:16])
return plan, nil
}

View File

@ -113,19 +113,19 @@ func main() {
//
// 失败不 Fatal(权限问题不该让服务不可用),但会逐条响亮记录。
if hr := security.HardenDataDir(opt.dataDir); len(hr.Changed) > 0 {
log.Printf("[homed] 已收紧 %d 项权限(内嵌密钥场景的必要缓解): %v",
log.Printf("[homed] hardened %d file permissions (necessary mitigation for embedded-key scenario): %v",
len(hr.Changed), hr.Changed)
}
key, keySrc, kerr := security.LoadOrCreateKey(opt.dataDir)
if kerr != nil {
log.Fatalf("[homed] 安全模块密钥初始化失败(拒绝以降级模式启动): %v", kerr)
log.Fatalf("[homed] security key init failed (refusing to start in degraded mode): %v", kerr)
}
// E-1:若存在密钥环,装入历史钥(只读旧密文;当前钥仍由
// systemd credential/env/security.key 提供)。密钥环损坏或 current 不一致
// 必须响亮失败,不能猜一把钥继续启动。
oldKeys, rerr := security.LoadKeyring(opt.dataDir, key)
if rerr != nil {
log.Fatalf("[homed] 安全模块密钥环加载失败(拒绝静默选错钥): %v", rerr)
log.Fatalf("[homed] security keyring load failed (refusing to silently pick wrong key): %v", rerr)
}
// ★ 内嵌钥上台时,磁盘钥必须继续参与**解密**。
//
@ -138,7 +138,7 @@ func main() {
oldKeys = append(oldKeys, extra...)
}
if len(oldKeys) > 0 {
log.Printf("[homed] 安全模块已装入 %d 把历史/额外密钥(E-1 平滑轮换 + 内嵌迁移)", len(oldKeys))
log.Printf("[homed] security module loaded %d historical/extra key(s) (E-1 smooth rotation + embedded migration)", len(oldKeys))
}
if _, serr := security.InitGlobal(security.Options{
Path: filepath.Join(opt.dataDir, "security", "variables.json"),
@ -146,22 +146,22 @@ func main() {
OldKeys: oldKeys,
Enabled: true,
}); serr != nil {
log.Fatalf("[homed] 安全模块变量库加载失败(不静默重建): %v", serr)
log.Fatalf("[homed] security variable store load failed (will not silently rebuild): %v", serr)
}
// 配置落盘用的子密钥(域隔离:与别名密钥不共用)。
// 必须早于 EncryptExistingSecrets,后者依赖它。
if _, cerr := security.InitConfigCodecWithOldKeys(key, oldKeys); cerr != nil {
log.Fatalf("[homed] 配置加密子密钥派生失败: %v", cerr)
log.Fatalf("[homed] config-encryption subkey derivation failed: %v", cerr)
}
// 把库里仍是明文的敏感项就地加密(幂等;升级路径必须跑)。
if n, merr := cfgReg.EncryptExistingSecrets(); merr != nil {
// 不 Fatal:库可能是只读/被锁,而“部分为明文”不等于服务不可用。
// 但要**响亮告警**:这是用户必须知道的安全事实。
log.Printf("[homed] 存量敏感配置加密未完成(部分项仍为明文): %v", merr)
log.Printf("[homed] existing sensitive config encryption incomplete (some entries still plaintext): %v", merr)
} else if n > 0 {
log.Printf("[homed] 已加密 %d 条存量敏感配置", n)
log.Printf("[homed] encrypted %d existing sensitive config entries", n)
}
log.Printf("[homed] 安全模块已启用(密钥来源 %s,变量 %d 条,配置落盘加密已开启)",
log.Printf("[homed] security module enabled (key source %s, %d variables, config-at-rest encryption on)",
keySrc, security.Global().Count())
// ★ E-2:备份跨机器恢复的诊断。
@ -171,14 +171,14 @@ func main() {
// 此前这种状态只在“读某一条配置”时才暴露成“某个功能坏了”,
// 用户看到的是症状而不是原因。这里一次性说清事实与修复动作。
if okN, badN, aerr := cfgReg.AuditSecrets(); aerr == nil && badN > 0 {
log.Printf("[homed] ⚠ 检测到 %d 条密文无法用当前主密钥解开(可解 %d 条)—— "+
"最常见原因是:这份 config.db 来自**另一台机器/另一个密钥**。"+
"修复:把原机器的密钥一起带过来(systemd credential / %s / "+
"%s),或用旧密钥启动一次并执行重加密迁移。",
log.Printf("[homed] WARNING: %d ciphertext entries cannot be decrypted with current master key (%d decryptable) — " +
"most common cause: this config.db came from **another machine / another key**. " +
"Fix: bring the original machine's key over (systemd credential / %s / " +
"%s), or start once with the old key and run the re-encryption migration.",
badN, okN, security.EnvKeyName, security.KeyringFileName)
}
} else {
log.Printf("[homed] 安全模块被显式关闭(core.security.enabled=false)—— 明文落盘且中转无防护")
log.Printf("[homed] security module explicitly disabled (core.security.enabled=false) — data at rest is plaintext and relay is unprotected")
}
// ========================================================================
@ -222,10 +222,10 @@ func main() {
// 是谁改的)。修复由人执行 —— 命令里已内联 sed 替换。
if cdir := ks.Cfg.Daemon.DataDir; cdir != "" && cdir != opt.dataDir {
st := systemd.State{RuntimeDataDir: opt.dataDir, ConfigDataDir: cdir}
log.Printf("[homed] ⚠️ 数据目录不一致(数据会分裂):")
log.Printf("[homed] -data = %s(图记忆、插件 Settings.DataDir)", opt.dataDir)
log.Printf("[homed] DB data_dir = %s(文本/知识/文档)", cdir)
log.Printf("[homed] 修复命令(勿手改单元,生产用 drop-in 覆盖 ExecStart):")
log.Printf("[homed] WARNING: data directories mismatch (data will split):")
log.Printf("[homed] -data = %s (graph memory, plugin Settings.DataDir)", opt.dataDir)
log.Printf("[homed] DB data_dir = %s (text/knowledge/doc)", cdir)
log.Printf("[homed] fix command (do not hand-edit the unit; use a drop-in to override ExecStart in production):")
log.Printf("[homed] %s", st.SyncCommand(cdir))
}
@ -260,7 +260,7 @@ func main() {
}
},
}); err != nil {
log.Fatalf("[homed] 内核装配失败: %v", err)
log.Fatalf("[homed] kernel assembly failed: %v", err)
}
defer ks.CloseAll()
@ -289,10 +289,10 @@ func main() {
// ③ 拉起"声明设施已就绪"的插件;挂起"等更晚设施(如 agent)"的
// (挂起项经 syncbus 在 agent 就绪时自动拉起,见 pluginhost/waiter.go)
if cat, ok := ks.PluginCatalog.(*pluginhost.PluginCatalog); ok {
log.Printf("[homed] 插件调度完成:元数据缓存 %d 个,已加载 %d 个",
log.Printf("[homed] plugin scheduling done: %d metadata cached, %d loaded",
cat.Size(), len(pluginReg.ListLoadedPlugins()))
} else {
log.Printf("[homed] 插件调度完成:已加载 %d 个", len(pluginReg.ListLoadedPlugins()))
log.Printf("[homed] plugin scheduling done: %d loaded", len(pluginReg.ListLoadedPlugins()))
}
// 插件加载完成后再回收空闲页:大值(如老版聊天记录)可能在这一步被搬走/删除,
@ -327,7 +327,7 @@ func main() {
waitForShutdown(ctx, opt.dataDir, restartCh, stopHeartbeatEarly, pluginReg, trk, cfgReg, sup,
func() {
if err := ks.CloseAll(); err != nil {
log.Printf("[homed] 模块关闭: %v", err)
log.Printf("[homed] module shutdown: %v", err)
}
})
}

View File

@ -44,7 +44,7 @@ func resolveFailbackAllowlist(cfgReg *internalConfig.ConfigRegistry,
names = append(names, s)
}
}
log.Printf("[homed] failback boot: plugin allowlist = %v(装配前解析)", names)
log.Printf("[homed] failback boot: plugin allowlist = %v (parsed before assembly)", names)
return names
}