模塊代碼整理自 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的地方。
