unity Console 封装

17 篇文章 0 订阅
16 篇文章 0 订阅

作者原文 https://www.iteye.com/blog/dsqiu-2263664

思路(Unity5.3):

   1.记录通过封装日志工具的函数调用栈信息 StackFrame。
   2.添加UnityEditor.Callbacks.OnOpenAssetAttribute(0)的回调方法,处理从ConsoleWindow双击跳转
   3.利用反射获取ConsoleWindow 的 ListeViewState 的 row(当前双击的行)和总行数
   4.利用3得到行数反射获取LogEntry信息进行匹配获得对应StackFrame
   5.调用AssetDatabase.OpenAsset()即可。

更新到Unity5.3发现,他提供Logger这个类,本来还以为可以实现这些功能,不过简单测试下来发现是不行的,我就还不清楚Unity构造一个Logger类是干嘛的,搞得我把下面的类名改成LoggerUtility。


完整的代码:

/* 
 * File: Assets/Scripts/Game/Utility/LoggerUtility.cs 
 * Project: **** 
 * Company: Lucky 
 * Code Porter: D.S.Qiu  
 * Create Date: 10/9/2015 10:11:53 PM 
 */  
  
using System;  
using System.Collections.Generic;  
using System.Diagnostics;  
using System.IO;  
using System.Text;  
#if UNITY_EDITOR  
using System.Reflection;  
using UnityEditor;  
using UnityEditor.Callbacks;  
#endif  
using UnityEngine;  
using Debug = UnityEngine.Debug;  
  
namespace Utility  
{  
    public class LogUtility  
    {  
        public enum LogLevel : byte  
        {  
            None = 0,  
            Exception = 1,  
            Error = 2,  
            Warning = 3,  
            Info = 4,  
        }  
  
        public static LogLevel logLevel = LogLevel.Info;  
        public static string infoColor = "#909090";  
        public static string warningColor = "orange";  
        public static string errorColor = "red";  
  
        public static void LogBreak(object message, UnityEngine.Object sender = null)  
        {  
            LogInfo(message, sender);  
            Debug.Break();  
        }  
  
        public static void LogFormat(string format, UnityEngine.Object sender, params object[] message)  
        {  
            if (logLevel >= LogLevel.Info)  
                LogLevelFormat(LogLevel.Info, string.Format(format, message), sender);  
        }  
  
        public static void LogFormat(string format, params object[] message)  
        {  
            if (logLevel >= LogLevel.Info)  
                LogLevelFormat(LogLevel.Info, string.Format(format, message), null);  
        }  
  
        public static void LogInfo(object message, UnityEngine.Object sender = null)  
        {  
            if(logLevel >= LogLevel.Info)  
                LogLevelFormat(LogLevel.Info,message,sender);  
        }  
  
        public static void LogWarning(object message, UnityEngine.Object sender = null)  
        {  
            if (logLevel >= LogLevel.Warning)  
                LogLevelFormat(LogLevel.Warning, message,  sender);  
        }  
  
        public static void LogError(object message, UnityEngine.Object sender = null)  
        {  
            if (logLevel >= LogLevel.Error)  
            {  
                LogLevelFormat(LogLevel.Error, message, sender);  
            }  
        }  
  
        public static void LogException(Exception exption, UnityEngine.Object sender = null)  
        {  
            if (logLevel >= LogLevel.Exception)  
            {  
                LogLevelFormat(LogLevel.Exception, exption, sender);  
            }  
        }  
  
        private static void LogLevelFormat(LogLevel level, object message, UnityEngine.Object sender)  
        {  
            string levelFormat =  level.ToString().ToUpper();  
            StackTrace stackTrace = new StackTrace(true);  
            var stackFrame = stackTrace.GetFrame(2);  
#if UNITY_EDITOR  
            s_LogStackFrameList.Add(stackFrame);  
#endif  
            string stackMessageFormat = Path.GetFileName(stackFrame.GetFileName()) + ":" + stackFrame.GetMethod().Name + "():at line " + stackFrame.GetFileLineNumber();  
            string timeFormat = "Frame:" + Time.frameCount + "," + DateTime.Now.Millisecond + "ms";  
            string objectName = string.Empty;  
            string colorFormat = infoColor;  
            if (level == LogLevel.Warning)  
                colorFormat = warningColor;  
            else if (level == LogLevel.Error)  
                colorFormat = errorColor;  
            StringBuilder sb = new StringBuilder();  
            sb.AppendFormat("<color={3}>[{0}][{4}][{1}]{2}</color>", levelFormat, timeFormat, message, colorFormat, stackMessageFormat);  
            Debug.Log(sb,sender);  
        }  
 
#if UNITY_EDITOR  
        private static int s_InstanceID;  
        private static int s_Line = 104;  
        private static List<StackFrame> s_LogStackFrameList = new List<StackFrame>();  
        //ConsoleWindow  
        private static object s_ConsoleWindow;  
        private static object s_LogListView;  
        private static FieldInfo s_LogListViewTotalRows;  
        private static FieldInfo s_LogListViewCurrentRow;  
        //LogEntry  
        private static MethodInfo s_LogEntriesGetEntry;  
        private static object s_LogEntry;  
        //instanceId 非UnityEngine.Object的运行时 InstanceID 为零所以只能用 LogEntry.Condition 判断  
        private static FieldInfo s_LogEntryInstanceId;  
        private static FieldInfo s_LogEntryLine;  
        private static FieldInfo s_LogEntryCondition;  
        static LogUtility()  
        {  
            s_InstanceID = AssetDatabase.LoadAssetAtPath<MonoScript>("Assets/Scripts/Game/Utility/LoggerUtility.cs").GetInstanceID();  
            s_LogStackFrameList.Clear();  
  
            GetConsoleWindowListView();  
        }  
  
        private static void GetConsoleWindowListView()  
        {  
            if (s_LogListView == null)  
            {  
                Assembly unityEditorAssembly = Assembly.GetAssembly(typeof(EditorWindow));  
                Type consoleWindowType = unityEditorAssembly.GetType("UnityEditor.ConsoleWindow");  
                FieldInfo fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);  
                s_ConsoleWindow = fieldInfo.GetValue(null);  
                FieldInfo listViewFieldInfo = consoleWindowType.GetField("m_ListView", BindingFlags.Instance | BindingFlags.NonPublic);  
                s_LogListView = listViewFieldInfo.GetValue(s_ConsoleWindow);  
                s_LogListViewTotalRows = listViewFieldInfo.FieldType.GetField("totalRows", BindingFlags.Instance | BindingFlags.Public);  
                s_LogListViewCurrentRow = listViewFieldInfo.FieldType.GetField("row", BindingFlags.Instance | BindingFlags.Public);  
                //LogEntries  
                Type logEntriesType = unityEditorAssembly.GetType("UnityEditorInternal.LogEntries");  
                s_LogEntriesGetEntry = logEntriesType.GetMethod("GetEntryInternal", BindingFlags.Static | BindingFlags.Public);  
                Type logEntryType = unityEditorAssembly.GetType("UnityEditorInternal.LogEntry");  
                s_LogEntry = Activator.CreateInstance(logEntryType);  
                s_LogEntryInstanceId = logEntryType.GetField("instanceID", BindingFlags.Instance | BindingFlags.Public);  
                s_LogEntryLine = logEntryType.GetField("line", BindingFlags.Instance | BindingFlags.Public);  
                s_LogEntryCondition = logEntryType.GetField("condition", BindingFlags.Instance | BindingFlags.Public);  
            }  
        }  
        private static StackFrame GetListViewRowCount()  
        {  
            GetConsoleWindowListView();  
            if (s_LogListView == null)  
                return null;  
            else  
            {  
                int totalRows = (int)s_LogListViewTotalRows.GetValue(s_LogListView);  
                int row = (int)s_LogListViewCurrentRow.GetValue(s_LogListView);  
                int logByThisClassCount = 0;  
                for (int i = totalRows - 1; i >= row; i--)  
                {  
                    s_LogEntriesGetEntry.Invoke(null, new object[] { i, s_LogEntry });  
                    string condition = s_LogEntryCondition.GetValue(s_LogEntry) as string;  
                    //判断是否是由LoggerUtility打印的日志  
                    if (condition.Contains("][") && condition.Contains("Frame"))  
                        logByThisClassCount++;  
                }  
  
                //同步日志列表,ConsoleWindow 点击Clear 会清理  
                while (s_LogStackFrameList.Count > totalRows)  
                    s_LogStackFrameList.RemoveAt(0);  
                if (s_LogStackFrameList.Count >= logByThisClassCount)  
                    return s_LogStackFrameList[s_LogStackFrameList.Count - logByThisClassCount];  
                return null;  
            }  
        }  
  
        [UnityEditor.Callbacks.OnOpenAssetAttribute(0)]  
        public static bool OnOpenAsset(int instanceID, int line)  
        {  
            if (instanceID == s_InstanceID && s_Line == line)  
            {  
                var stackFrame = GetListViewRowCount();  
                if (stackFrame != null)  
                {  
                    string fileName = stackFrame.GetFileName();  
                    string fileAssetPath = fileName.Substring(fileName.IndexOf("Assets"));  
                    AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<MonoScript>(fileAssetPath), stackFrame.GetFileLineNumber());  
                    return true;  
                }  
            }  
             
            return false;  
        }  
#endif  
    }  
  
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值