对Unity Debug的简单封装
使用前提:
Project Settings-Player-Other Settings-Script Define Symbols添加 EnableLog,点击Apply
测试代码:
using MTools.Debuger;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
public string TAGNAME = "我是日志的标签";
void Start()
{
Debuger.LogLevel = LogLevel.Error; //测试,项目中可以通过读取配置文件,更改日志级别
Debuger.Info("我是一个测试");
Debuger.Info("NewBehaviourScript", "我是一个测试");
Debuger.Warn("我是一个测试");
Debuger.Warn("NewBehaviourScript", "我是一个测试");
Debuger.Error("我是一个测试");
Debuger.Error("NewBehaviourScript", "我是一个测试");
this.Info("我是一个测试2");
this.Warn("我是一个测试2");
this.Error("我是一个测试2");
}
}
using System;
using System.IO;
using System.Diagnostics;
using UnityEngine;
namespace MTools.Debuger
{
///
/// 日志级别
///
public enum LogLevel : byte
{
///
/// 信息级别
///
Info,
///
/// 警告级别
///
Warn,
///
/// 错误级别
///
Error
}
public class Debuger
{
///
/// 日志级别(默认Info)
///
public static LogLevel LogLevel = LogLevel.Info;
///
/// 是否使用Unity打印
///
public static bool UseUnityEngine = true;
///
/// 是否显示时间
///
public static bool EnableTime = false;
///
/// 是否显示堆栈信息
///
public static bool EnableStack = false;
///
/// 是否保存到文本
///
public static bool EnableSave = false;
///
/// 打印文本流
///
public static StreamWriter LogFileWriter = null;
///
/// 日志保存路径(文件夹)
///
public static string LogFileDir = "";
///
/// 日志文件名
///
public static string LogFileName = "";
//打印格式: {0}-时间 {1}-标签/类名/TAGNAME字段值 {2}-内容
private static string InfoFormat = "[Info] {0}{1} {2} ";
private static string WarnFormat = "[Warn] {0}{1} {2} ";
private static string ErrorFormat = "[Error] {0}{1} {2} ";
private static void Internal_Log(string msg, object context = null)
{
bool useUnityEngine = UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.Log(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
private static void Internal_Warn(string msg, object context = null)
{
bool useUnityEngine = UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.LogWarning(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
private static void Internal_Error(string msg, object context = null)
{
bool useUnityEngine = UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.LogError(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
#region Info
[Conditional("EnableLog")]
public static void Info(object message)
{
if (LogLevel >= LogLevel.Info)
{
string msg = string.Format(InfoFormat, GetLogTime(), "", message);
Internal_Log(msg, null);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Info(object message, object context)
{
if (LogLevel >= LogLevel.Info)
{
string msg = string.Format(InfoFormat, GetLogTime(), "", message);
Internal_Log(msg, context);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Info(string tag, string message)
{
if (LogLevel >= LogLevel.Info)
{
string msg = string.Format(InfoFormat, GetLogTime(), tag, message);
Internal_Log(msg, null);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Info(string tag, string format, params object[] args)
{
if (LogLevel >= LogLevel.Info)
{
string msg = string.Format(format, args);
msg = string.Format(InfoFormat, GetLogTime(), tag, msg);
Internal_Log(msg, null);
WriteToFile(msg, false);
}
}
#endregion
#region Warn
[Conditional("EnableLog")]
public static void Warn(object message)
{
if (LogLevel >= LogLevel.Warn)
{
string msg = string.Format(WarnFormat, GetLogTime(), "", message);
Internal_Warn(msg, null);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Warn(object message, object context)
{
if (LogLevel >= LogLevel.Warn)
{
string msg = string.Format(WarnFormat, GetLogTime(), "", message);
Internal_Warn(msg, context);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Warn(string tag, string message)
{
if (LogLevel >= LogLevel.Warn)
{
string msg = string.Format(WarnFormat, GetLogTime(), tag, message);
Internal_Warn(msg, null);
WriteToFile(msg, false);
}
}
[Conditional("EnableLog")]
public static void Warn(string tag, string format, params object[] args)
{
if (LogLevel >= LogLevel.Warn)
{
string msg = string.Format(format, args);
msg = string.Format(WarnFormat, GetLogTime(), tag, msg);
Internal_Warn(msg, null);
WriteToFile(msg, false);
}
}
#endregion
#region Error
[Conditional("EnableLog")]
public static void Error(object message)
{
if (LogLevel >= LogLevel.Error)
{
string msg = string.Format(ErrorFormat, GetLogTime(), "", message);
Internal_Error(msg, null);
WriteToFile(msg, true);
}
}
[Conditional("EnableLog")]
public static void Error(object message, object context)
{
if (LogLevel >= LogLevel.Error)
{
string msg = string.Format(ErrorFormat, GetLogTime(), "", message);
Internal_Error(msg, context);
WriteToFile(msg, true);
}
}
[Conditional("EnableLog")]
public static void Error(string tag, string message)
{
if (LogLevel >= LogLevel.Error)
{
string msg = string.Format(ErrorFormat, GetLogTime(), tag, message);
Internal_Error(msg, null);
WriteToFile(msg, true);
}
}
[Conditional("EnableLog")]
public static void Error(string tag, string format, params object[] args)
{
if (LogLevel >= LogLevel.Error)
{
string msg = string.Format(format, args);
msg = string.Format(ErrorFormat, GetLogTime(), tag, msg);
Internal_Error(msg, null);
WriteToFile(msg, true);
}
}
#endregion
///
/// 获取时间
///
///
private static string GetLogTime()
{
string result = "";
if (EnableTime)
{
result = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + " ";
}
return result;
}
///
/// 序列化打印信息
///
/// 打印信息
/// 是否开启堆栈打印
private static void WriteToFile(string message, bool EnableStack = false)
{
bool flag = !EnableSave;
if (!flag)
{
bool flag2 = LogFileWriter == null;
if (flag2)
{
LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString();
LogFileName = LogFileName.Replace("-", "_");
LogFileName = LogFileName.Replace(":", "_");
LogFileName = LogFileName.Replace(" ", "");
LogFileName += ".log";
bool flag3 = string.IsNullOrEmpty(LogFileDir);
if (flag3)
{
try
{
bool useUnityEngine = UseUnityEngine;
if (useUnityEngine)
{
LogFileDir = Application.persistentDataPath + "/DebugerLog/";
}
else
{
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
LogFileDir = baseDirectory + "/DebugerLog/";
}
}
catch (Exception ex)
{
string msg = string.Format(ErrorFormat, "", "", "获取 Application.persistentDataPath 报错!" + ex.Message);
Internal_Error(msg, null);
return;
}
}
string path = LogFileDir + LogFileName;
try
{
bool flag4 = !Directory.Exists(LogFileDir);
if (flag4)
{
Directory.CreateDirectory(LogFileDir);
}
LogFileWriter = File.AppendText(path);
LogFileWriter.AutoFlush = true;
}
catch (Exception ex2)
{
LogFileWriter = null;
string msg = string.Format(ErrorFormat, "", "", "LogToCache()" + ex2.Message + ex2.StackTrace);
Internal_Error(msg, null);
return;
}
}
bool flag5 = LogFileWriter != null;
if (flag5)
{
try
{
LogFileWriter.WriteLine(message);
bool flag6 = (EnableStack || Debuger.EnableStack) && UseUnityEngine;
if (flag6)
{
LogFileWriter.WriteLine(StackTraceUtility.ExtractStackTrace());
}
}
catch (Exception)
{
}
}
}
}
}
}
日志扩展类
DebugerExtension.cs
using System.Reflection;
using System.Diagnostics;
namespace MTools.Debuger
{
///
/// 自定义Debuger类的扩展类
///
public static class DebugerExtension
{
[Conditional("EnableLog")]
public static void Info(this object obj, string message)
{
if (Debuger.LogLevel >= LogLevel.Info)
{
Debuger.Info(GetLogTag(obj), message);
}
}
[Conditional("EnableLog")]
public static void Info(this object obj, string format, params object[] args)
{
if (Debuger.LogLevel >= LogLevel.Info)
{
string message = string.Format(format, args);
Debuger.Info(GetLogTag(obj), message);
}
}
[Conditional("EnableLog")]
public static void Warning(this object obj, string message)
{
if (Debuger.LogLevel >= LogLevel.Warn)
{
Debuger.Warn(GetLogTag(obj), message);
}
}
[Conditional("EnableLog")]
public static void Warn(this object obj, string format, params object[] args)
{
if (Debuger.LogLevel >= LogLevel.Warn)
{
string message = string.Format(format, args);
Debuger.Warn(GetLogTag(obj), message);
}
}
[Conditional("EnableLog")]
public static void Error(this object obj, string message)
{
if (Debuger.LogLevel >= LogLevel.Error)
{
Debuger.Error(GetLogTag(obj), message);
}
}
[Conditional("EnableLog")]
public static void Error(this object obj, string format, params object[] args)
{
if (Debuger.LogLevel >= LogLevel.Error)
{
string message = string.Format(format, args);
Debuger.Error(GetLogTag(obj), message);
}
}
///
/// 获取调用打印的类名称或者标记有TAGNAME的字段
/// 有TAGNAME字段的,触发类名称用TAGNAME字段对应的赋值
/// 没有用类的名称代替
///
/// 触发Log对应的类
///
private static string GetLogTag(object obj)
{
FieldInfo field = obj.GetType().GetField("TAGNAME");
bool flag = field != null;
string result;
if (flag)
{
result = (string)field.GetValue(obj);
}
else
{
result = obj.GetType().Name;
}
return result;
}
}
}
日志拦截器, 实现Unity中Console窗口双击跳转到合理的位置
LogIntercepter.cs
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
namespace M.Editor
{
///
/// 日志拦截器
///
internal sealed class LogIntercepter
{
private static LogIntercepter _current;
private static LogIntercepter Current
{
get
{
if (_current == null)
{
_current = new LogIntercepter();
}
return _current;
}
}
private Type _consoleWindowType;
private FieldInfo _activeTextInfo;
private FieldInfo _consoleWindowInfo;
private MethodInfo _setActiveEntry;
private object[] _setActiveEntryArgs;
private object _consoleWindow;
private LogIntercepter()
{
_consoleWindowType = Type.GetType("UnityEditor.ConsoleWindow,UnityEditor");
_activeTextInfo = _consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
_consoleWindowInfo = _consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
_setActiveEntry = _consoleWindowType.GetMethod("SetActiveEntry", BindingFlags.Instance | BindingFlags.NonPublic);
_setActiveEntryArgs = new object[] { null };
}
[OnOpenAsset]
private static bool OnOpenAsset(int instanceID, int line)
{
UnityEngine.Object instance = EditorUtility.InstanceIDToObject(instanceID);
if (AssetDatabase.GetAssetOrScenePath(instance).EndsWith(".cs"))
{
return Current.OpenAsset();//双击会触发这里
}
return false;
}
private bool OpenAsset()
{
string stackTrace = GetStackTrace();
if (stackTrace != "")
{
//结合条件 可以用来过滤是否使用了原始接口还是自定义的
if (stackTrace.Contains("[Info]") || stackTrace.Contains("[Warn]") || stackTrace.Contains("[Error]"))
{
string[] paths = stackTrace.Split('\n');
for (int i = 0; i < paths.Length; i++)
{
//过滤日志封装类和日志扩展类
if (!paths[i].Contains("Debuger.cs") && !paths[i].Contains("DebugerExtension.cs") && paths[i].Contains(" (at "))
{
return OpenScriptAsset(paths[i]);
}
}
}
}
return false;
}
private bool OpenScriptAsset(string path)
{
int startIndex = path.IndexOf(" (at ") + 5;
int endIndex = path.IndexOf(".cs:") + 3;
string filePath = path.Substring(startIndex, endIndex - startIndex);
string lineStr = path.Substring(endIndex + 1, path.Length - endIndex - 2);
TextAsset asset = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);
if (asset != null)
{
int line;
if (int.TryParse(lineStr, out line))
{
object consoleWindow = GetConsoleWindow();
_setActiveEntry.Invoke(consoleWindow, _setActiveEntryArgs);
EditorGUIUtility.PingObject(asset);
AssetDatabase.OpenAsset(asset, line);
return true;
}
}
return false;
}
private string GetStackTrace()
{
object consoleWindow = GetConsoleWindow();
if (consoleWindow != null)
{
if (consoleWindow == EditorWindow.focusedWindow as object)
{
object value = _activeTextInfo.GetValue(consoleWindow);
return value != null ? value.ToString() : "";
}
}
return "";
}
private object GetConsoleWindow()
{
if (_consoleWindow == null)
{
_consoleWindow = _consoleWindowInfo.GetValue(null);
}
return _consoleWindow;
}
}
}