适用于Unity的日志增强模块
前言
最近在捣鼓Unity的各种小轮子,用来扩展自己的框架吧~
这次介绍一下用于Unity的日志增强系统
功能介绍
这个东西想加入现有的项目非常容易,单个cs文件复制即用,在游戏启动时初始化一次即可。
保存的日志文件位于Application.persistentDataPath
路径的/GameLog
目录中,以日志文件创建时间命名,方便后期查阅。
当然实现的功能暂时也很简单,基本上只有同步输出到文件, 之后会准备一个工具来实时监控这个日志文件
实现方法
首先创建工具类LoggingUtils
,将其设计为单例模式,包含3个方法:
类型 | 名称 | 说明 |
---|---|---|
方法 | public void Init | 游戏启动时初始化的工作 |
方法 | private void OnLogMessage | 捕获到系统Log时的回调函数 |
方法 | public void Update | 定期更新,暂定为FixedUpdate |
字段 | Queue<LogItem> m_vLogs | 存储单条日志的队列 |
字段 | FileInfo m_logFileInfo | 要写入的外部文件 |
其中,LogItem是存储单条日志信息的数据结构,代码如下
1 | public struct LogItem |
初始化
先来看Init方法
签名:public void Init()
在游戏启动时调用,如果有多个场景可以用一个MonoBehavior
在其Awake
方法中调用,一次运行中仅第一次调用会生效,重复调用不会出问题。
1 | public void Init() |
核心在于“注册回调”这一步,Unity提供了一个方法用于用户自己扩展日志系统,注册完这个回调后,使用Debug.Log
之类的方法输出日志时,Unity会同时调用用户自定义的其他方法。
这是Unity5.x的写法,在老版本中写法略有差异,想要兼容老版本Unity的话需要加判断Unity版本的宏,不过我们这个就不考虑老版本了。
回调方法
当Unity输出日志信息时,会调用OnLogMessage
这个方法。
签名:private void OnLogMessage(string condition, string stackTrace, LogType type)
其中condition
是日志信息本体的字符串。
stackTrace
是调用Debug.Log
之类方法代码位置的调用栈信息。
type
顾名思义是这条日志的类型,分为Log,Warning,Error等
1 | private void OnLogMessage(string condition, string stackTrace, LogType type) |
我们这里还加入了时间戳信息
输出到文件
本来是想把这个步骤直接写进上一个方法里的,不过有时候写入文件这个操作是会产生异常的,所以我就把这个步骤改成了类似异步的写法,OnLogMessage
中只是把日志项加入队列,然后定时检查这个队列,把队列最前的一条信息写入文件,如果产生异常则这次Update不做任何操作,日志项也不会被移除,直到成功写入文件
1 | public void Update(float dt) |
可能产生的异常其实就是文件锁,当另外一个进程(比如说之后要做的一个实时日志查看器)已经在读写某个文件时,第二个进程就不能再次打开进行操作了。
使用方法
这里就不提供完整的文件了,自行把上面几个片段拼起来再改成单例模式就能用~
准备一个继承自MonoBehavior的脚本,挂载到每个场景的任意GameObject上(推荐用一个专用初始化的空GO吧)。
脚本的Awake方法中调用初始化方法:
1 | void Awake() |
然后在FixUpdate里加入更新用的代码:
1 | void FixedUpdate() |
然后运行游戏,就算什么也不做的话,已经可以在日志文件中至少看到两条日志啦
1 | 17:13:06.42-[Log]日志系统已启动 |
日志文件的位置可以在Unity Console的第一条Log里找到
可以做的更好。。
还有很多想法没有实现,比如我们还没有用到调用栈信息,可以考虑当收到了一条Error级别的日志时,同时把调用栈也追加输出到文件中