RUNTIME OBSERVABILITY · RELEASE PERFORMANCE
ZMDebugKit
为 Unity 商业项目打造的一体化日志与运行时调试工具箱
统一日志输出、子线程文件落盘、Android / iOS 真机查看、FPS 监控、开发者归属标识、ProtoBuf 可视化与发布版本日志剔除,让调试能力从开发环境延伸到真实设备,同时保持上线包足够轻量。
异步落盘 · 移动端可视化 · 编译期剔除 · 团队日志治理
框架定位
ZMDebugKit 不是单一的 Debug.Log 包装器,而是一条覆盖开发、联调、真机测试和正式发布的日志管线:开发期提供更清晰的颜色与归属信息;运行期收集日志并通过后台线程写入文件;移动端提供内置查看面板;发布前通过条件编译从产物中移除业务日志调用。
-
可靠留档
使用线程安全队列接收 Unity 日志,由
ZMLogFileWriter后台线程写入 UTF-8 文件,保留日志等级、时间、正文与堆栈。 -
真机诊断
Reporter 面板可在 Android、iOS 运行时查看、过滤、复制和保存日志,并辅助观察场景、内存与 FPS。
-
性能可控
OPEN_LOG关闭后,标记了Conditional的日志调用不会进入编译结果,减少正式包的日志开销。 -
协作清晰
将开发者 TAG 与颜色通道绑定,让多人项目中的日志来源一目了然。
运行架构
业务代码
└─ Debuger.Log / LogWarning / LogError / Color Log
├─ Unity Console ── LogRedirection ──> 实际业务调用位置
├─ Reporter ─────────────────────────> Android / iOS 运行时面板
└─ Application.logMessageReceivedThreaded
└─ ConcurrentQueue<LogData>
└─ ZMLogFileWriter ────────> persistentDataPath/*.log
构建阶段
└─ OPEN_LOG 宏 ──> 保留或剔除 Debuger 日志调用点
源码基准
本文档依据 Assets/ZMPackages/ZMDebuger 当前源码编写,示例工程版本为 Unity 2021.3.38f1c1。业务主入口的真实类名是 Debuger。
快速接入
1. 导入完整目录
请保留 Editor、Runtime、Plugins、Unity-Logs-Viewer 与 Samples。框架已附带 Newtonsoft.Json.dll 和 Reporter 预制体。
2. 启用 OPEN_LOG
在 Unity 顶部菜单执行:
该命令会为 Standalone、Android、iOS 添加 OPEN_LOG,并将 Reporter 预制体放入当前场景。建议在应用的首个启动场景执行并保存。
3. 初始化
using UnityEngine;
using ZM.DebugerKit;
public sealed class GameLauncher : MonoBehaviour
{
private void Awake()
{
#if OPEN_LOG
Debuger.InitLog(new LogConfig
{
openLog = true,
logHeadFix = "[GAME]",
openTime = true,
showThreadID = true,
showColorName = true,
logSave = true,
showFPS = true
});
#endif
}
}
初始化时机
请在首条业务日志产生之前调用 Debuger.InitLog,并在一次应用生命周期内只初始化一次。InitLog 自身同样受 OPEN_LOG 控制。
4. 输出第一条日志
Debuger.Log("Game initialized. PlayerId = ", playerId);
Debuger.LogWarning("Network latency: ", latency, " ms");
Debuger.LogError("Login failed. Code = ", errorCode);
Debuger.LogGreen("Resource system is ready.");
Debuger.LogCyan("Protocol response received.");
Debuger.LogRed("Battle state validation failed.");
参数拼接规则
Debuger.Log(string, params object[]) 会按顺序拼接参数,不执行 string.Format。推荐写成 Debuger.Log("HP = ", hp)。
配置参考
LogConfig
命名空间:ZM.DebugerKit
| 成员 | 类型 | 默认值 | 行为 |
|---|---|---|---|
openLog |
bool |
true |
运行时日志总开关 |
logHeadFix |
string |
"###" |
每条日志的统一前缀 |
openTime |
bool |
true |
附加 HH:mm:ss-fff 时间 |
showThreadID |
bool |
true |
附加托管线程 ID |
logSave |
bool |
true |
启用本地日志文件 |
showFPS |
bool |
true |
创建常驻 FPS 显示组件 |
showColorName |
bool |
true |
在日志正文中显示颜色名称 |
logFileSavePath |
string |
Application.persistentDataPath + "/" |
日志目录,只读 |
logFileName |
string |
产品名 + 时间戳 + .log |
本次初始化生成的文件名,只读 |
推荐配置策略
开发包可开启全部能力;性能测试包建议保留日志文件、关闭 FPS 浮层;正式发布包建议移除 OPEN_LOG 并进行一次干净构建。
API 参考
Debuger.InitLog
初始化全局配置。logSave = true 时创建常驻 UnityLogHelper;showFPS = true 时创建常驻 FrameRateDisplay。传入 null 会使用默认 LogConfig。
Debuger.RegisterDeveloper
将开发者 TAG 绑定到指定颜色。之后使用对应颜色方法输出日志时,框架会自动加入 [developerTag]。
Debuger.RegisterDeveloper("铸梦", LogColor.Cyan);
Debuger.RegisterDeveloper("战斗组", LogColor.Green);
Debuger.LogCyan("Socket connected.");
Debuger.LogGreen("Battle world created.");
约束:
- 不能使用
LogColor.None。 - 同一种颜色只能绑定一个开发者 TAG。
- TAG 最大 32 个字符。
- 方括号、尖括号与控制字符会被过滤。
普通、警告与错误日志
| 方法 | 说明 |
|---|---|
Log(object obj) |
输出普通日志,null 会显示为字符串 null |
Log(string message, params object[] args) |
拼接参数并输出普通日志 |
LogWarning(object obj) |
输出警告日志 |
LogWarning(string message, params object[] args) |
拼接参数并输出警告日志 |
LogError(object obj) |
输出错误日志 |
LogError(string message, params object[] args) |
拼接参数并输出错误日志 |
所有方法均受 OPEN_LOG 条件编译和 LogConfig.openLog 运行时开关共同控制。
彩色日志
| 方法 | 颜色 | 典型用途 |
|---|---|---|
LogBlue(object msg) |
Blue | 系统状态 |
LogCyan(object msg) |
Cyan | 网络协议 |
LogGreen(object msg) |
Green | 成功与正常流程 |
LogYellow(object msg) |
Yellow | 需要关注的状态 |
LogOrange(object msg) |
Orange | 风险提示 |
LogMagenta(object msg) |
Magenta | 独立业务通道 |
LogRed(object msg) |
Red | 失败与严重异常 |
LogColor 还定义了 Darkblue、Grey、Purple,当前版本未公开对应的快捷输出方法。
ProtoBuffConvert.ToJson
使用 Newtonsoft.Json 将对象格式化为缩进 JSON,并交由 Debuger.Log 输出:
序列化安全
协议日志可能包含 Token、账号或个人数据。共享日志文件前应进行脱敏,正式环境不建议直接打印完整响应。
子线程日志文件
启用 logSave 后,UnityLogHelper 订阅 Application.logMessageReceivedThreaded,将回调数据压入 ConcurrentQueue<LogData>,再唤醒后台线程执行文件 I/O。
关闭流程会停止接收新日志、唤醒写线程、清空队列、刷新并释放文件流。日志默认保存在:
具体物理路径由运行平台和 Bundle Identifier 决定。可在目标设备上输出该属性以获取准确目录。
Android / iOS 运行时查看
ZMLog/打开日志系统 会把 Reporter.prefab 加入当前场景。运行时面板支持日志、警告、错误筛选,并可展示场景、内存、FPS 等诊断信息。
上线前检查:
- Reporter 是否位于真正的首个启动场景。
- 面板唤起手势是否与业务交互冲突。
- 测试人员是否了解日志导出与脱敏要求。
- 正式包是否确实需要保留运行时面板。
FPS 实时显示
当 LogConfig.showFPS = true 时,框架创建 FrameRateDisplay 并设置为 DontDestroyOnLoad。组件通过平滑后的 Time.deltaTime 计算 FPS,并在屏幕左上角显示红色数值。
Note
FPS 浮层适合开发和测试观察,不应代替 Unity Profiler、ProfilerRecorder 或平台级性能工具进行严谨分析。
发布版本日志剔除
在 Unity 菜单执行:
工具会从 Standalone、Android、iOS 移除 OPEN_LOG,并删除当前场景中名为 Reporter 的对象。重新构建后,Debuger.Log* 和 Debuger.InitLog 的调用点不会被编译进产物。
// OPEN_LOG 存在:调用被保留
// OPEN_LOG 不存在:调用点被 ConditionalAttribute 剔除
Debuger.Log("Expensive diagnostic message: ", diagnosticData);
发布前必须重新构建
修改脚本宏后不要复用旧产物。建议执行一次干净构建,并在目标设备验证 Reporter、FPS 和本地日志均符合发布策略。
Console 日志重定向
编辑器中的 LogRedirection 会解析 Unity Console 当前日志的堆栈。双击由 Debuger 输出的日志时,它会跳过封装文件并打开实际业务调用位置。该能力仅在 Unity Editor 生效。
接入检查清单
- [ ] 已完整导入
Assets/ZMPackages/ZMDebuger - [ ] 首个启动场景已配置 Reporter
- [ ] 已在业务日志前调用
Debuger.InitLog - [ ] 团队已约定颜色或开发者 TAG
- [ ] 真机已验证日志查看和文件导出
- [ ] 敏感协议日志已脱敏
- [ ] 发布构建前已关闭
OPEN_LOG - [ ] 已执行干净构建并完成性能回归
常见问题
调用 Debuger.Log 后为什么没有输出?
检查目标平台是否定义了 OPEN_LOG、是否已经初始化,以及 LogConfig.openLog 是否为 true。
为什么没有生成日志文件?
检查 logSave 是否开启,并查找初始化时由 Unity 输出的 logFilePath。日志文件位于 Application.persistentDataPath。
为什么点击日志没有跳到业务代码?
重定向仅支持 Unity Editor。请确保 Console 窗口处于焦点状态,且日志由 Debuger 接口输出。
ProtoBuffConvert 为什么会报 JSON 序列化异常?
该工具使用 Newtonsoft.Json。请检查循环引用、不可访问成员或需要自定义 Converter 的类型。
继续学习
从日志封装到移动端诊断,完整理解商业项目的调试链路
课程覆盖本地文件写入、颜色日志、Android / iOS 查看工具、FPS 显示、编译期日志剔除、ProtoBuf 转 JSON 与开发者归属日志。