【Unity】通用的Debugger日志模块
模块代码整理自 http://gad.qq.com/lore/catalog/10007
Debugger类。提供打印日志的静态方法。
using System; using System.IO; namespace UnityEngine { /// <summary> /// 系统日志模块 /// </summary> public class Debugger { public static bool EnableLog; // 是否启用日志,仅可控制普通级别的日志的启用与关闭,LogError和LogWarn都是始终启用的。 public static bool EnableTime = true; public static bool EnableSave = false; // 是否允许保存日志,即把日志写入到文件中 public static bool EnableStack = false; public static string LogFileDir = Application.persistentDataPath + "/DebuggerLog/"; public static string LogFileName = ""; public static string Prefix = "> "; // 用于与Unity默认的系统日志做区分。本日志系统输出的日志头部都会带上这个标记。 public static StreamWriter LogFileWriter = null; public static bool UseUnityEngine; private static string GetLogText(string tag, string message) { string str = ""; if (EnableTime) { str = DateTime.Now.ToString("HH:mm:ss.fff") + " "; } return (str + tag + "::" + message); } private static string GetLogTime() { string str = ""; if (EnableTime) { str = DateTime.Now.ToString("HH:mm:ss.fff") + " "; } return str; } public static void Log(object message) { if (!Debugger.EnableLog) return; string str = GetLogTime() + message; Debug.Log(Prefix + str, null); LogToFile("[I]" + str, false); } public static void Log(object message, Object context) { if (!Debugger.EnableLog) return; string str = GetLogTime() + message; Debug.Log(Prefix + str, context); LogToFile("[I]" + str, false); } public static void Log(string tag, string message) { if (!Debugger.EnableLog) return; message = GetLogText(tag, message); Debug.Log(Prefix + message, null); LogToFile("[I]" + message, false); } public static void Log(string tag, string format, params object[] args) { if (!Debugger.EnableLog) return; string logText = GetLogText(tag, string.Format(format, args)); Debug.Log(Prefix + logText, null); LogToFile("[I]" + logText, false); } public static void LogError(object message) { string str = GetLogTime() + message; Debug.Log(Prefix + str, null); LogToFile("[E]" + str, true); } public static void LogError(object message, Object context) { string str = GetLogTime() + message; Debug.Log(Prefix + str, context); LogToFile("[E]" + str, true); } public static void LogError(string tag, string message) { message = GetLogText(tag, message); Debug.Log(Prefix + message, null); LogToFile("[E]" + message, true); } public static void LogError(string tag, string format, params object[] args) { string logText = GetLogText(tag, string.Format(format, args)); Debug.Log(Prefix + logText, null); LogToFile("[E]" + logText, true); } /// <summary> /// 将日志写入到文件中 /// </summary> /// <param name="message"></param> /// <param name="EnableStack"></param> private static void LogToFile(string message, bool EnableStack = false) { if (!Debugger.EnableSave) return; if (LogFileWriter == null) { LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString(); LogFileName = LogFileName.Replace("-", "_"); LogFileName = LogFileName.Replace(":", "_"); LogFileName = LogFileName.Replace(" ", ""); LogFileName = LogFileName + ".log"; if (string.IsNullOrEmpty(LogFileDir)) { try { if (UseUnityEngine) { LogFileDir = Application.persistentDataPath + "/DebuggerLog/"; } else { LogFileDir = AppDomain.CurrentDomain.BaseDirectory + "/DebuggerLog/"; } } catch (Exception exception) { Debug.Log(Prefix + "获取 Application.persistentDataPath 报错!" + exception.Message, null); return; } } string path = LogFileDir + LogFileName; try { if (!Directory.Exists(LogFileDir)) { Directory.CreateDirectory(LogFileDir); } LogFileWriter = File.AppendText(path); LogFileWriter.AutoFlush = true; } catch (Exception exception2) { LogFileWriter = null; Debug.Log("LogToCache() " + exception2.Message + exception2.StackTrace, null); return; } } if (LogFileWriter != null) { try { LogFileWriter.WriteLine(message); if ((EnableStack || Debugger.EnableStack) && UseUnityEngine) { LogFileWriter.WriteLine(StackTraceUtility.ExtractStackTrace()); } } catch (Exception) { } } } public static void LogWarning(object message) { string str = GetLogTime() + message; Debug.Log(Prefix + str, null); LogToFile("[W]" + str, false); } public static void LogWarning(object message, Object context) { string str = GetLogTime() + message; Debug.Log(Prefix + str, context); LogToFile("[W]" + str, false); } public static void LogWarning(string tag, string message) { message = GetLogText(tag, message); Debug.Log(Prefix + message, null); LogToFile("[W]" + message, false); } public static void LogWarning(string tag, string format, params object[] args) { string logText = GetLogText(tag, string.Format(format, args)); Debug.Log(Prefix + logText, null); LogToFile("[W]" + logText, false); } } }
DebuggerExtension类。采用C#的扩展方法特性,使所有System.Object子类获得了打印日志的函数功能。
using System.Diagnostics; using System.Reflection; using UnityEngine; namespace UnityEngine { /// <summary> /// 日志模块的扩展类 /// </summary> public static class DebuggerExtension { /// <summary> /// LogTag是调用打印日志的类中自定义的常量字符串,通常情况下LogTag是类名。 /// 用LogTag可以直观地看出这条日志是哪个类输出的。 /// </summary> /// <param name="obj"></param> /// <returns></returns> private static string GetLogTag(object obj) { FieldInfo field = obj.GetType().GetField("LOG_TAG"); if (field != null) { return (string)field.GetValue(obj); } return obj.GetType().Name; } [Conditional("EnableLog")] public static void Log(this object obj, string message) { if (Debugger.EnableLog) { Debugger.Log(GetLogTag(obj), message); } } [Conditional("EnableLog")] public static void Log(this object obj, string format, params object[] args) { if (Debugger.EnableLog) { string message = string.Format(format, args); Debugger.Log(GetLogTag(obj), message); } } public static void LogError(this object obj, string message) { Debugger.LogError(GetLogTag(obj), message); } public static void LogError(this object obj, string format, params object[] args) { string message = string.Format(format, args); Debugger.LogError(GetLogTag(obj), message); } public static void LogWarning(this object obj, string message) { Debugger.LogWarning(GetLogTag(obj), message); } public static void LogWarning(this object obj, string format, params object[] args) { string message = string.Format(format, args); Debugger.LogWarning(GetLogTag(obj), message); } } }
Example测试日志模块。
using UnityEngine; public class Example_Debugger : MonoBehaviour { void Start() { Debug.Log("这是Unity默认的日志!"); Debugger.EnableLog = true; Debugger.EnableTime = true; Debugger.Log("Debugger.Log"); Debugger.LogWarning("Debugger.LogWarning"); Debugger.LogError("Debugger.LogError"); Debugger.Log("Example_Debugger", "格式化日志: {0}", 123456); Debugger.Log("日志保存路径:", Debugger.LogFileDir); this.Log("日志扩展类中的方法。该方法需要在Unity编辑器中添加宏命令EnableLog才能被编译!"); } }
运行效果:
注意,DebuggerExtension类采用了[Conditional]特性条件编译,被[Conditional]标记的函数需要在Unity编辑器中开启命令宏才能被编译,参考这里。
建议将Debugger类和DebuggerExtension类都编译到Debugger.dll中,再放入Unity工程Asset目录下使用。因为如果将Debuger类放到主工程里,在Unity的日志输出窗口Console中点击日志,会跳转到Debuger类中的代码,而我们真正想要跳转到的是调用了Debuger的地方。