用户投诉原话:「我们的启动日志放在哪?…他找半天没找到崩溃日志」「只有一个安装日志」。 启动器运行日志(.ULL/logs/launcher.log) - presenter 构造 HostEnv 时就登记日志目录:启动早期缓冲的 200 行([probe]/[font]/[theme]) 当场刷盘,不再是「只有开过一局游戏才有日志」。 - app/** 里所有 eprintln! 诊断改走 app::diag::diag!(stderr + 文件双写,行首 [tag] 即 scope), 含 boot/boot::fallback/state/update 各线。 - boot 那一拍补一行后端事实(request/effective/fallback)。 - 滚动上限(1 MiB → launcher.1.log,只留一份)写进 README 与 docs/logs-location.md。 会话日志搬家:data/agent/sessions → logs - LauncherLayout: sessions_root()/game_logs() 新增,agent_sessions() 降级为只读兼容。 - host/logs 与 cli/commands/sessions 两个根合并(同 id 新根优先),event_path 回落旧家。 - 不搬不删;日志目录写一份 session-log-location.json 记录(moved=0, policy=read-only-compat)。 入口与文案 - 设置页「通用」新增「日志文件夹」行:路径 + 打开目录 + 复制路径(i18n 中英)。 - 日志页页头的「打开目录」不再是占位:走 M187 的 open_dir,失败文本带路径并送进剪贴板。 - README.md / README.zh-CN.md 新增「日志在哪」章节(含 crash-reports 只在游戏走到那一步才有), docs/logs-location.md 给出上限、双写判据、迁移策略与没验的部分。 守门(每条都有变异证明,见报告) - 旧家会话仍列得出/打不开 ⇒ 只读新根变红;新会话写 logs/game ⇒ 只读旧根、写回旧家都变红。 - launcher.log 滚动 ⇒ 干掉 rename 变红。 - 打开日志文件夹指向真实目录 ⇒ 换成 cache/ 或去掉 create_dir_all 都变红。 - 日志根随三模式变化 ⇒ 把 HostEnv::logs_dir 写死成便携落点变红。
6.4 KiB
日志在哪(M188)
一句话:启动器自己写的东西全在 <数据根>/logs/ 一个目录里,游戏自己的东西在实例运行目录里。
设置页那行「日志文件夹」显示的就是前者的绝对路径,旁边有 打开文件夹 与 复制路径;日志页页头
也有 打开文件夹。两个入口走同一个落点(crates/app-iced/src/app/logs_folder.rs),失败时输出的
文本带完整路径。
1. 三个数据模式下的绝对路径
<数据根> 由 core::platform::data_dir 的三模式解析(便携 / 标准 / 自定义):
| 模式 | 启动器数据目录(= <数据根>) |
日志根 |
|---|---|---|
| portable | <exe 目录>/.ULL |
<exe 目录>/.ULL/logs |
| standard | Windows %APPDATA%\ULL · macOS ~/Library/Application Support/ULL · Linux $XDG_DATA_HOME/ULL(缺省 ~/.local/share/ULL) |
<上者>/logs |
| custom | <自定义根>/.ULL |
<自定义根>/.ULL/logs |
GUI 的 --data-dir <dir> 是 custom 模式的一种入口:那时日志根是 <dir>/.ULL/logs。设置页显示的
路径与 launcher.log 的实际落点取的是同一份解析结果(SettingsBridge → <home>/config/launcher.json
→ <home>),所以两者不会各说各话。
2. 目录里有什么
| 路径 | 写者 | 是什么 |
|---|---|---|
logs/launcher.log |
core::launch::launcher_log |
启动器自己的运行日志:启动拍(主题 / 语言 / 路由 / 窗口)、后端探测与降级、字体链、每一次启动的命令行事实 / spawn 结果 / 退出码、打开日志目录等用户动作的结果。 |
logs/launcher.1.log |
同上(滚动) | 上一份日志。只留一份历史。 |
logs/game/<session-id>.jsonl |
core::launch::session |
每次启动一份 JSONL 事件流(命令行已脱敏、每行 stdout/stderr、退出、诊断)。 |
logs/game/index.jsonl |
core::launch::session_index |
一会话一行摘要的索引,日志页左栏读它。 |
logs/install.log |
presenter::host::install_journal |
安装流水,每阶段一行。 |
logs/session-log-location.json |
presenter::host::logs::note_location |
会话日志现在在哪 / 以前在哪 / 搬没搬(moved: 0),每次启动重写。 |
data/agent/sessions/game/… |
旧版本 | 只读兼容,见 §4。 |
上限与滚动
- 单文件上限
launcher_log::MAX_BYTES = 1 MiB;每次追加前检查,超过就把launcher.log改名成launcher.1.log(旧的那份被替换),新文件从 0 开始。 - 保留份数:1。所以
logs/里启动器日志的稳态占用 ≤ 约 2 MiB(+ 同目录的会话 jsonl)。 - 为什么不做按日期滚动:事故复现往往在「刚刚那一次」,份数比历史长度更重要;而无限份数会让「导出 诊断包」变成搬砖。
3. 哪些行进 launcher.log、哪些只进 stderr
判据只有一条:事故之后还要不要看它。实现是 crates/app-iced/src/app/diag.rs 的 diag! 宏
(stderr + 文件双写,行首 [tag] 就是日志里的 scope)。
进 launcher.log(crates/app-iced/src/app/** 里打的行) |
只进 stderr(本 mission scope 之外的行) |
|---|---|
启动编排:[probe](降级重开 / 探测耗时)、[font]、[theme]、[appearance]、[gpu] 的降级与拒绝降级、[boot](含后端 request/effective)、[shot] 的通道提示 |
renderer::acceptance 的验收度量:[window] / [perf] / [caps] / [theme] source=… |
用户动作的结果:[logs](打开日志文件夹成功/失败)、[settings] 写盘失败、[i18n] 语言没落盘、[update] 的忽略/重启、[agent] / [content] / [page] 的落点提示 |
renderer 自己的 [gpu] …初始化失败、[gpu] iced_wgpu: Selected、[probe] request=…(probe.rs)、[corner](platform/win32/corner.rs) |
| 一次性、量很小的诊断(每次启动几行到几十行) | 组件几何探针与测试:[feedback-probe] / [gallery] / [probe] divider… |
不允许把高频行接进来:1 MiB 的上限就是为了保住「事故现场」,逐帧写会把它冲掉。
已知边界(M188 没做,已登记):renderer/**、probe.rs、platform/win32/corner.rs 里的行
仍然只走 stderr——它们各自属于别的 mission 的 scope。要全线接通,得把这些文件的 eprintln!
也换成 crate::app::diag::diag!(或把 emit 提成 lib 级函数)。
4. 会话日志搬家:策略是不搬
M188 把新会话从 data/agent/sessions/game/ 挪到 logs/game/(目录名里的 agent 是历史遗留,
它从来只装游戏会话)。旧目录的处理方式:
- 原样保留、继续读:
presenter::host::logs与cli的会话读取都是两个根合并,同一个session_id同时存在时以logs/那条为准; - 不搬、不删:搬运用户已有数据是不可逆动作,中途失败会留下半份会话,崩溃弹窗里的会话关联也会断;
- 留记录:
logs/session-log-location.json写明两个根、旧根在不在、旧根里几个文件、moved: 0、policy: "read-only-compat"。
5. 游戏自己的日志(不归启动器写)
在实例的运行目录里(隔离实例是 <游戏目录>/versions/<隔离名>/…,共享实例直接是 .minecraft):
logs/latest.log、logs/<日期>-<序号>.log.gz—— 游戏自己的日志;crash-reports/crash-*.txt—— 只在 JVM 活到崩溃处理器那一步时才有;hs_err_pid*.log—— JVM 自己崩(native crash)时才写。
模组 / 缺库 / Java 选错把游戏弄死在 Minecraft 初始化之前时,上面三个都不会出现——那不是启动器
丢了日志,而是游戏没机会写。那种时候的证据是 logs/game/<session-id>.jsonl 与 logs/launcher.log。
6. 没验的部分
- 真机「双击启动后日志确实在」:本轮只在开发机上用
cargo test与本地进程验证,Windows 桌面 双击启动需要用户实测。 - macOS / Linux 的日志根:路径由同一条解析链给出(
standard_launcher_home有单测覆盖三个平台), 但「Mac 上点打开文件夹真的会开 Finder」「Linux 上没有xdg-open时会怎样」没有真机验证。 - 只读数据目录:日志写不进去时按设计静默放过(best-effort),此时设置页显示的路径仍然正确, 但文件不存在。