跳转至

RUNTIME OBSERVABILITY · RELEASE PERFORMANCE

ZMDebugKit

为 Unity 商业项目打造的一体化日志与运行时调试工具箱

统一日志输出、子线程文件落盘、Android / iOS 真机查看、FPS 监控、开发者归属标识、ProtoBuf 可视化与发布版本日志剔除,让调试能力从开发环境延伸到真实设备,同时保持上线包足够轻量。

5 分钟接入 API 参考 教学课程

异步落盘 · 移动端可视化 · 编译期剔除 · 团队日志治理

框架定位

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. 导入完整目录

Assets/ZMPackages/ZMDebuger

请保留 EditorRuntimePluginsUnity-Logs-ViewerSamples。框架已附带 Newtonsoft.Json.dll 和 Reporter 预制体。

2. 启用 OPEN_LOG

在 Unity 顶部菜单执行:

ZMLog/打开日志系统

该命令会为 Standalone、Android、iOS 添加 OPEN_LOG,并将 Reporter 预制体放入当前场景。建议在应用的首个启动场景执行并保存。

3. 初始化

GameLauncher.cs
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

[Conditional("OPEN_LOG")]
public static void InitLog(LogConfig config = null)

初始化全局配置。logSave = true 时创建常驻 UnityLogHelpershowFPS = true 时创建常驻 FrameRateDisplay。传入 null 会使用默认 LogConfig

Debuger.RegisterDeveloper

public static void RegisterDeveloper(string developerTag, LogColor color)

将开发者 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 还定义了 DarkblueGreyPurple,当前版本未公开对应的快捷输出方法。

ProtoBuffConvert.ToJson

public static void ToJson<T>(T proto)

使用 Newtonsoft.Json 将对象格式化为缩进 JSON,并交由 Debuger.Log 输出:

LoginResponse response = await loginService.LoginAsync();
ProtoBuffConvert.ToJson(response);

序列化安全

协议日志可能包含 Token、账号或个人数据。共享日志文件前应进行脱敏,正式环境不建议直接打印完整响应。

子线程日志文件

启用 logSave 后,UnityLogHelper 订阅 Application.logMessageReceivedThreaded,将回调数据压入 ConcurrentQueue<LogData>,再唤醒后台线程执行文件 I/O。

Error >>> 2026-07-21 14:32:08.126 [GAME] Login failed. Code = 1001
<stack trace>

关闭流程会停止接收新日志、唤醒写线程、清空队列、刷新并释放文件流。日志默认保存在:

Application.persistentDataPath

具体物理路径由运行平台和 Bundle Identifier 决定。可在目标设备上输出该属性以获取准确目录。

Android / iOS 运行时查看

ZMLog/打开日志系统 会把 Reporter.prefab 加入当前场景。运行时面板支持日志、警告、错误筛选,并可展示场景、内存、FPS 等诊断信息。

上线前检查:

  • Reporter 是否位于真正的首个启动场景。
  • 面板唤起手势是否与业务交互冲突。
  • 测试人员是否了解日志导出与脱敏要求。
  • 正式包是否确实需要保留运行时面板。

FPS 实时显示

LogConfig.showFPS = true 时,框架创建 FrameRateDisplay 并设置为 DontDestroyOnLoad。组件通过平滑后的 Time.deltaTime 计算 FPS,并在屏幕左上角显示红色数值。

Note

FPS 浮层适合开发和测试观察,不应代替 Unity Profiler、ProfilerRecorder 或平台级性能工具进行严谨分析。

发布版本日志剔除

在 Unity 菜单执行:

ZMLog/关闭日志系统

工具会从 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 与开发者归属日志。

进入 ZMDebugKit 教学课程 访问铸梦课程主页