Files
Unlucky-Launcher/docs/logs-location.md
T
worker-logplace 8c5bebf3e3 fix(m188): r1 复审 P2-1——后端启动失败的具名原因进 launcher.log
复审结论 p2-1/1 item + fix-then-merge:主线成立,但「启动器自己因 GPU / 渲染后端起不来」的
事故原因仍只进 stderr —— 双击启动没有 stderr,那条路径上等于没有日志。

- renderer/mod.rs::report_failure 的两行(`[gpu] <backend> 初始化失败(具名)` /
  `[gpu] 失败详情(具名)`)改走 diag!;
- renderer/log_bridge.rs 转出的 wgpu 日志(含 `…Selected: AdapterInfo…`,GPU 真生效的唯一证据
  行)改走 diag!;
- renderer/preflight.rs 的 `[gpu-preflight]`(ULL_PREFLIGHT=1)改走 diag!;
- probe.rs::apply_with_preflight 的三行 `[probe]` 改走 diag!。
- app/diag.rs 模块文档 + docs/logs-location.md §3 的判据改准:
  「逐帧度量不接;显式取证开关与一次性事故行可接」,并修掉 `[corner]` 两处自相矛盾
  (唯一打印点在 app/update/appearance.rs,走 diag! ⇒ 进日志;corner.rs 只 format_line)。
- 新守门 renderer::tests::a_backend_startup_failure_lands_in_the_launcher_log:
  断言那两行真的落进 launcher.log;变异(改回纯 eprintln)→ 红。
- README 两语的 launcher.log 行补上「渲染后端起不来的具名原因」。
2026-11-09 01:05:40 +08:00

95 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 日志在哪(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 | 只进 stderr |
|---|---|
| 启动编排:`[probe]`(`request=… -> ICED_BACKEND=…`、降级重开、探测耗时)、`[font]`、`[theme]`、`[appearance]`、`[gpu]` 的降级与拒绝降级、`[boot]`(含后端 request/effective)、`[shot]` 的通道提示 | 验收/出图矩阵的**逐帧度量**:`[window]` / `[perf]` / `[caps]` / `[theme] source=…`(`renderer::acceptance/**`,一次启动上百行,会冲掉事故现场) |
| **一次性事故行**:`[gpu] <backend> 初始化失败(具名)` 与 `[gpu] 失败详情(具名)`(`renderer::report_failure`,复审 P2-1)、`[gpu] <target>: …Selected: AdapterInfo…`(`renderer/log_bridge.rs` 转出的 wgpu 日志)、`[gpu-preflight]`(`ULL_PREFLIGHT=1`) | 组件几何探针的断言输出(`components/**` 的 `[feedback-probe]`、gallery 页面里的 `[gallery]`) |
| 用户动作的结果:`[logs]`(打开日志文件夹成功/失败)、`[settings]` 写盘失败、`[i18n]` 语言没落盘、`[update]` 的忽略/重启、`[agent]` / `[content]` / `[page]` 的落点提示 | 每条日志行的正文里再套的括号(不是标签) |
| 显式开关下的一次性行:`[tick]`(`ULL_TICK_TRACE=1`,≈1 行/秒,约 4.8 小时才滚一次)、`[corner]`(`app/update/appearance.rs` 打,`platform/win32/corner.rs` 只负责 `format_line`)、`[appearance]` / `[theme]` 的切换 | — |
`[corner]` 到底在哪一侧,看**打印点**:唯一打印点是 `app/update/appearance.rs`(走 `diag!`),
`platform/win32/corner.rs::format_line` 只拼字符串、不打印 ⇒ 它**进** launcher.log。
## 3.1 还没接进日志的行(本 mission 之外)
- `renderer::acceptance/**` 的 `[window]` / `[perf]` / `[caps]`:逐帧/矩阵取证,按上面的判据**故意不接**。
- `components/**` 的几何探针(`[feedback-probe]` / `[gallery]`):测试通道,不进产品日志。
(`renderer/mod.rs` 的 `report_failure`、`renderer/log_bridge.rs`、`renderer/preflight.rs`、
`probe.rs:apply_with_preflight` 已在 M188 复审后接上。)
## 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),此时设置页显示的路径仍然正确,
但文件不存在。