5.0 KiB
5.0 KiB
Editor模块 Console面板错误绑定 fallback sink 导致运行时日志不显示
1. 问题定义
当前 editor 底部 Console 面板在 PlayMode 下看不到 C# Debug.Log 输出。
已确认:
Tick正在正常推进,脚本字段计数持续变化Debug.Log已经成功从 C# 进入 native loggereditor/bin/Debug/editor.log中可以看到脚本日志- 但 editor 底部
Console面板仍然为空,或看不到对应运行时日志
这说明问题不在脚本运行时本身,而在 editor 控制台面板读取日志数据的链路。
2. 复现现象
复现方式:
- 给场景对象挂上
project/Assets/Scripts/TickLogProbe.cs - 点击 editor 的
Play - 观察脚本上的计数字段持续递增
- 观察底部
Console面板,没有出现[Project TickLogProbe] Awake/Start/Update/...
同时检查:
editor/bin/Debug/editor.log
可以看到类似日志已经真实写入:
[INFO] [Scripting] [Project TickLogProbe] Awake[INFO] [Scripting] [Project TickLogProbe] Start[INFO] [Scripting] [Project TickLogProbe] Update 1
3. 排查结论
问题不在以下层级:
- 不在
Tick系统 - 不在 C#
Debug.Log - 不在 Mono internal call 注册
- 不在 native
Logger - 不在
FileLogSink
这些链路都已经工作正常。
真正出问题的是:
- editor
ConsolePanel读到的不是 logger 中真实注册的EditorConsoleSink - 它读到的是一个错误的 fallback 实例
4. 根本原因
根因位于:
editor/src/Core/EditorConsoleSink.cpp
当前实现:
ConfigureEditorLogging()启动时会把一个真正的EditorConsoleSink注册到Logger- 后续
ConsolePanel::OnAttach()会调用EditorConsoleSink::GetInstance() GetInstance()内部存在一个static EditorConsoleSink fallbackInstance- 但
EditorConsoleSink的构造函数会无条件执行s_instance = this
这会导致一个严重副作用:
- logger 里原本已经注册好的真实
EditorConsoleSink先成为s_instance - 当
ConsolePanel第一次调用GetInstance()时,fallbackInstance被构造 fallbackInstance构造时又把s_instance覆盖成它自己- 此后
ConsolePanel通过GetInstance()拿到的是 fallback sink - 但 logger 继续写入的仍然是最初注册到
Logger的那一个真实 sink
最终结果就是:
- 文件日志正常
- logger 正常
- 脚本日志正常
- Console 面板读取的是另一份空数据
5. 关键代码位置
相关位置:
editor/src/Core/EditorLoggingSetup.heditor/src/Core/EditorConsoleSink.cppeditor/src/panels/ConsolePanel.cppeditor/src/Application.cpp
关键调用顺序:
Application::Initialize()ConfigureEditorLogging()Logger注册真实EditorConsoleSinkAttachEditorLayer()ConsolePanel::OnAttach()EditorConsoleSink::GetInstance()- fallback 实例构造并错误覆盖
s_instance
6. 影响范围
这个问题的影响不只是 TickLogProbe 看不到日志,而是整个 editor runtime 日志可视化都不可信:
- 任何 C#
Debug.Log - 任何
Scripting分类日志 - 未来 PlayMode 运行时诊断
- 运行时错误追踪
- 面向脚本模块的调试体验
从开发效率上看,这个问题会直接误导判断:
- 容易误以为脚本没执行
- 容易误以为
Debug.Log没打通 - 容易误以为 Tick 没跑
- 实际上只是 Console 面板读错了 sink
7. 修复方向
建议修复方向:
EditorConsoleSink::GetInstance()不应在查询过程中构造会修改全局状态的 fallback 对象EditorConsoleSink构造函数不应无条件覆盖s_instance- 应保证
ConsolePanel永远读取 logger 中真实注册的那一个 sink - 如果确实需要 fallback,也应是只读占位对象,不能污染全局
s_instance
更稳妥的方向包括:
- 明确区分“真实注册实例”和“空对象返回值”
- 让
ConfigureEditorLogging()的注册实例成为唯一权威实例 - 增加 editor 级回归测试,覆盖“logger 已写入但 ConsolePanel 读取为空”的场景
8. 验收标准
修复后至少应满足:
Debug.Log能实时显示在 editor 底部Console面板editor.log与Console面板看到的是同一批日志ConsolePanel读取到的EditorConsoleSink与 logger 注册实例一致- PlayMode 期间
Awake/Start/FixedUpdate/Update/LateUpdate日志都可见 - 不再出现“文件里有日志但面板里没有”的分裂状态
9. 优先级
高。
原因:
- 当前脚本运行时其实已经可用
- 但最基础的可视化调试入口失效
- 会直接阻塞后续对脚本生命周期、PlayMode 行为、运行时异常的验证效率
10. 备注
本问题已经确认不是以下原因导致:
Tick没运行Script没挂载成功Debug.Loginternal call 没注册- logger category 被禁用
editor.log没写入
这是一个纯 editor 层的 Console sink 实例绑定错误问题。