6.2 KiB
6.2 KiB
日志系统改进留档
背景与目的
旧日志系统直接订阅 Unity 日志回调,把 Debug.* 输出同步写入文件。这个实现有几个明显问题:
- 每条日志同步
WriteLine,并且AutoFlush = true,移动端写盘成本容易造成卡顿。 - Android 因性能问题被编译条件直接禁用文件日志,真机问题缺少可追踪依据。
- 日志格式只接近“控制台文本转储”,缺少等级、分类、场景、帧号、线程、会话等排查信息。
- 文件按天追加,同一天多次启动会混在一起,不利于定位一次具体测试或玩家反馈。
Application.logMessageReceivedThreaded可能从多线程进入,但旧实现直接操作同一个StreamWriter,线程安全不足。
本次改进目标是建立一套可以在 PC 与 Android 都安全启用的轻量文件日志系统:降低写盘卡顿风险,保留 Unity 日志兼容入口,并为后续业务结构化日志打基础。
已完成内容
核心代码位于 Assets/Scripts/Framework/LogKit/:
-
LogKit.cs- 保留运行时自动初始化入口。
- 继续订阅
Application.logMessageReceivedThreaded,捕获旧有Debug.Log/Warning/Error。 - 新增
GameLog业务日志入口,支持按LogCategory分类输出。 - 新增
LogLevel、LogCategory、LogEntry、LogFormatter,把日志记录转换为结构化文本行。 - 应用失焦和退出时触发 flush,降低日志丢失概率。
-
FileLogger.cs- 从同步写文件改为线程安全队列 + 后台线程批量写入。
- 关闭每条日志
AutoFlush,改为批量 flush。 - 队列满时丢弃低优先级日志,并记录 dropped count。
Error及以上等级优先保留。- 按 session 创建日志文件,并支持大小轮转、总大小/文件数量保留。
- 日志写入器内部异常静默降级,避免日志系统自身递归刷错误。
-
LogSettingsProfiles.cs- 将平台配置从
LogKit.cs中抽离为轻量 C# profile。 - 不使用 JSON、StreamingAssets 或 ScriptableObject,避免额外资源加载和 Unity asset 依赖。
- 当前 profile 包括
Editor、AndroidDevelopment、AndroidRelease、StandaloneDevelopment、StandaloneRelease。
- 将平台配置从
日志文件与格式
日志目录仍使用 ConstRef.LogFilePath,即 Application.persistentDataPath/LogFile。
文件按启动会话生成,命名格式类似:
20260708_153012_android_v1.2.0_session-abcd1234.log
单行日志包含:
timestamp | level | category | scene | frame | thread | context | message | stack
说明:
timestamp使用 UTC ISO 格式。category可区分 Unity 捕获日志和业务系统日志。- 非主线程日志不会读取 Unity 场景和帧号,避免在线程回调中访问 Unity 主线程 API。
- 普通日志默认不写堆栈;
Error/Exception/Assert写入堆栈。
平台默认配置
当前配置集中在 LogSettingsProfiles.cs。
Editor
- 默认不写文件日志。
- 仍保留 Unity Console 的正常输出。
Android Development
- 文件日志启用。
- 最低等级:
Info。 - 队列容量:
1024。 - 批量写入:
64条。 - Flush 间隔:
1500ms。 - 单文件上限:
5MB。 - 总保留上限:
30MB。 - Session 文件保留:
6个。
Android Release
- 文件日志启用。
- 最低等级:
Warning。 - Console 最低等级:
Warning。 - 其余写入参数与 Android Development 保持一致。
Standalone Development / Release
- 文件日志启用。
- Development 最低等级:
Info,Console 最低等级:Debug。 - Release 最低等级:
Info,Console 最低等级:Info。 - 队列容量:
2048。 - 批量写入:
128条。 - Flush 间隔:
1000ms。 - 单文件上限:
10MB。 - 总保留上限:
100MB。 - Session 文件保留:
20个。
如何使用
旧代码中的 Debug.Log/Warning/Error 不需要立刻迁移,仍会被捕获到文件日志。
新代码或关键链路建议使用 GameLog:
GameLog.Info(LogCategory.Save, "Auto save completed", "slot=0");
GameLog.Warn(LogCategory.Resource, "Addressable load slow", "key=Scene/ClinicOut");
GameLog.Error(LogCategory.Yarn, "Node missing", "node=Start");
优先迁移高价值排查链路,而不是一次性替换全项目日志:
- 存档/读档:
SaveRestoreOrchestrator、SaveSystem - 对话:
DialogController、Yarn node 进入/退出 - 资源:
ResourceSystem、SceneResourceLoader - 场景:
SceneLoader - 维修系统入口:
FixSystemCenter
已验证内容
本次实现后已执行:
git diff --check -- Assembly-CSharp.csproj Assets/Scripts/Framework/LogKit
dotnet build Assembly-CSharp.csproj --no-restore
结果:
- 空白检查通过。
Assembly-CSharp.csproj构建通过,0 个错误。- 构建中的 warning 为项目既有 warning,与日志系统改动无关。
仍需补足
后续建议按优先级补足以下内容:
-
Android 真机压测
- 在 Android Development build 中压测高频
Debug.Log。 - 对比启用日志前后的帧率和卡顿尖刺。
- 验证切后台、返回、退出时日志能正常 flush。
- 在 Android Development build 中压测高频
-
关键业务链路迁移到
GameLog- 先迁移 Save、Resource、Dialog、Scene 这些排查价值最高的系统。
- 不建议批量替换所有旧
Debug.Log,避免制造无意义 diff。
-
重复日志限流
- 当前已有队列满时低等级丢弃机制。
- 仍可补充同一 message 短时间重复出现时的合并策略,减少高频系统刷屏。
-
日志导出入口
- 增加获取当前日志目录或当前 session 日志路径的 API。
- 后续可接入设置界面或测试菜单,方便测试人员导出日志。
-
配置开关扩展
- 当前 profile 是代码内固定配置。
- 如果未来测试需要临时打开 Release
Info日志,可考虑增加启动参数、调试菜单或本地轻量覆盖开关。
-
Unity 工程文件同步
- 本次为了命令行构建验证,手动把
LogSettingsProfiles.cs加入了Assembly-CSharp.csproj。 - Unity 重新生成工程文件时可能覆盖
.csproj,这是 Unity 生成文件的正常行为;源码和.meta才是长期留档重点。
- 本次为了命令行构建验证,手动把