日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Unity日志工具

 kiki的號 2017-03-20

Unity日志工具——封裝,跳轉(zhuǎn)

 

By D.S.Qiu

尊重他人的勞動,支持原創(chuàng),轉(zhuǎn)載請注明出處:http://dsqiu.

       

        好久沒有寫博客分享了,主要有三個原因:1.iteye博客不支持公式等高級特性的支持(不知道iteye的產(chǎn)品經(jīng)理是怎么想的),就一直想自己搭建一個類似stackedit.io編輯器的博客站點,一直沒有憋出來就一直沒繼續(xù)寫了;2.自己想做的事情太多了(比如像寫一個Visual Studio MFC的那種界面一樣的Unity UGUI編輯工具,寫博客花了太多時間了,可是還是沒有憋出來(憂傷啊);3.之前寫的大部分就沒有什么含量,當然是作為自己學(xué)習(xí)的一個途徑吧,所以還是需要大量的積累先!

       

        應(yīng)該所有的團隊都會自己封裝日志工具,除非引擎已經(jīng)集成了,在Unity也不例外,當時之前的同事封裝了一個有一個很大不爽的地方是:從Unity ConsoleWindow 雙擊日志跳轉(zhuǎn)到代碼總是跳轉(zhuǎn)到封裝類中的函數(shù),而不能直接跳轉(zhuǎn)到調(diào)用封裝類被調(diào)用的地方。

 

       切好在準備新項目,我把原來不夠優(yōu)良的地方都進行了改進直至盡可能的完美。之前一直就知道1.利用反射可以獲取Unity的private FieldInfo和 MethodInfo 可以做很多事情,2.可以利用Unity提供的api調(diào)整到指定的代碼中去,3.Unity提供跳轉(zhuǎn)回調(diào)的機制。算是理論只是具備了,今天來公司就把這個給寫出來了,當然還對LogLevel和StackFrame信息進行了優(yōu)化(之前的有點丑,是13年一個前前同事寫的)。

 

其實是很簡單的,直接說下思路吧(Unity5.3):

       1.記錄通過封裝日志工具的函數(shù)調(diào)用棧信息 StackFrame。

       2.添加UnityEditor.Callbacks.OnOpenAssetAttribute(0)的回調(diào)方法,處理從ConsoleWindow雙擊跳轉(zhuǎn)

       3.利用反射獲取ConsoleWindow 的 ListeViewState 的 row(當前雙擊的行)和總行數(shù)

       4.利用3得到行數(shù)反射獲取LogEntry信息進行匹配獲得對應(yīng)StackFrame

       5.調(diào)用AssetDatabase.OpenAsset()即可。

 

 更新到Unity5.3發(fā)現(xiàn),他提供Logger這個類,本來還以為可以實現(xiàn)這些功能,不過簡單測試下來發(fā)現(xiàn)是不行的,我就還不清楚Unity構(gòu)造一個Logger類是干嘛的,搞得我把下面的類名改成LoggerUtility。

 

貼下完整的代碼:

C#代碼 復(fù)制代碼 收藏代碼
  1. /* 
  2.  * File: Assets/Scripts/Game/Utility/LoggerUtility.cs 
  3.  * Project: **** 
  4.  * Company: Lucky 
  5.  * Code Porter: D.S.Qiu  
  6.  * Create Date: 10/9/2015 10:11:53 PM 
  7.  */  
  8.   
  9. using System;  
  10. using System.Collections.Generic;  
  11. using System.Diagnostics;  
  12. using System.IO;  
  13. using System.Text;  
  14. #if UNITY_EDITOR  
  15. using System.Reflection;  
  16. using UnityEditor;  
  17. using UnityEditor.Callbacks;  
  18. #endif  
  19. using UnityEngine;  
  20. using Debug = UnityEngine.Debug;  
  21.   
  22. namespace Utility  
  23. {  
  24.     public class LogUtility  
  25.     {  
  26.         public enum LogLevel : byte  
  27.         {  
  28.             None = 0,  
  29.             Exception = 1,  
  30.             Error = 2,  
  31.             Warning = 3,  
  32.             Info = 4,  
  33.         }  
  34.   
  35.         public static LogLevel logLevel = LogLevel.Info;  
  36.         public static string infoColor = "#909090";  
  37.         public static string warningColor = "orange";  
  38.         public static string errorColor = "red";  
  39.   
  40.         public static void LogBreak(object message, UnityEngine.Object sender = null)  
  41.         {  
  42.             LogInfo(message, sender);  
  43.             Debug.Break();  
  44.         }  
  45.   
  46.         public static void LogFormat(string format, UnityEngine.Object sender, params object[] message)  
  47.         {  
  48.             if (logLevel >= LogLevel.Info)  
  49.                 LogLevelFormat(LogLevel.Info, string.Format(format, message), sender);  
  50.         }  
  51.   
  52.         public static void LogFormat(string format, params object[] message)  
  53.         {  
  54.             if (logLevel >= LogLevel.Info)  
  55.                 LogLevelFormat(LogLevel.Info, string.Format(format, message), null);  
  56.         }  
  57.   
  58.         public static void LogInfo(object message, UnityEngine.Object sender = null)  
  59.         {  
  60.             if(logLevel >= LogLevel.Info)  
  61.                 LogLevelFormat(LogLevel.Info,message,sender);  
  62.         }  
  63.   
  64.         public static void LogWarning(object message, UnityEngine.Object sender = null)  
  65.         {  
  66.             if (logLevel >= LogLevel.Warning)  
  67.                 LogLevelFormat(LogLevel.Warning, message,  sender);  
  68.         }  
  69.   
  70.         public static void LogError(object message, UnityEngine.Object sender = null)  
  71.         {  
  72.             if (logLevel >= LogLevel.Error)  
  73.             {  
  74.                 LogLevelFormat(LogLevel.Error, message, sender);  
  75.             }  
  76.         }  
  77.   
  78.         public static void LogException(Exception exption, UnityEngine.Object sender = null)  
  79.         {  
  80.             if (logLevel >= LogLevel.Exception)  
  81.             {  
  82.                 LogLevelFormat(LogLevel.Exception, exption, sender);  
  83.             }  
  84.         }  
  85.   
  86.         private static void LogLevelFormat(LogLevel level, object message, UnityEngine.Object sender)  
  87.         {  
  88.             string levelFormat =  level.ToString().ToUpper();  
  89.             StackTrace stackTrace = new StackTrace(true);  
  90.             var stackFrame = stackTrace.GetFrame(2);  
  91. #if UNITY_EDITOR  
  92.             s_LogStackFrameList.Add(stackFrame);  
  93. #endif  
  94.             string stackMessageFormat = Path.GetFileName(stackFrame.GetFileName()) + ":" + stackFrame.GetMethod().Name + "():at line " + stackFrame.GetFileLineNumber();  
  95.             string timeFormat = "Frame:" + Time.frameCount + "," + DateTime.Now.Millisecond + "ms";  
  96.             string objectName = string.Empty;  
  97.             string colorFormat = infoColor;  
  98.             if (level == LogLevel.Warning)  
  99.                 colorFormat = warningColor;  
  100.             else if (level == LogLevel.Error)  
  101.                 colorFormat = errorColor;  
  102.             StringBuilder sb = new StringBuilder();  
  103.             sb.AppendFormat("<color={3}>[{0}][{4}][{1}]{2}</color>", levelFormat, timeFormat, message, colorFormat, stackMessageFormat);  
  104.             Debug.Log(sb,sender);  
  105.         }  
  106.  
  107. #if UNITY_EDITOR  
  108.         private static int s_InstanceID;  
  109.         private static int s_Line = 104;  
  110.         private static List<StackFrame> s_LogStackFrameList = new List<StackFrame>();  
  111.         //ConsoleWindow  
  112.         private static object s_ConsoleWindow;  
  113.         private static object s_LogListView;  
  114.         private static FieldInfo s_LogListViewTotalRows;  
  115.         private static FieldInfo s_LogListViewCurrentRow;  
  116.         //LogEntry  
  117.         private static MethodInfo s_LogEntriesGetEntry;  
  118.         private static object s_LogEntry;  
  119.         //instanceId 非UnityEngine.Object的運行時 InstanceID 為零所以只能用 LogEntry.Condition 判斷  
  120.         private static FieldInfo s_LogEntryInstanceId;  
  121.         private static FieldInfo s_LogEntryLine;  
  122.         private static FieldInfo s_LogEntryCondition;  
  123.         static LogUtility()  
  124.         {  
  125.             s_InstanceID = AssetDatabase.LoadAssetAtPath<MonoScript>("Assets/Scripts/Game/Utility/LoggerUtility.cs").GetInstanceID();  
  126.             s_LogStackFrameList.Clear();  
  127.   
  128.             GetConsoleWindowListView();  
  129.         }  
  130.   
  131.         private static void GetConsoleWindowListView()  
  132.         {  
  133.             if (s_LogListView == null)  
  134.             {  
  135.                 Assembly unityEditorAssembly = Assembly.GetAssembly(typeof(EditorWindow));  
  136.                 Type consoleWindowType = unityEditorAssembly.GetType("UnityEditor.ConsoleWindow");  
  137.                 FieldInfo fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);  
  138.                 s_ConsoleWindow = fieldInfo.GetValue(null);  
  139.                 FieldInfo listViewFieldInfo = consoleWindowType.GetField("m_ListView", BindingFlags.Instance | BindingFlags.NonPublic);  
  140.                 s_LogListView = listViewFieldInfo.GetValue(s_ConsoleWindow);  
  141.                 s_LogListViewTotalRows = listViewFieldInfo.FieldType.GetField("totalRows", BindingFlags.Instance | BindingFlags.Public);  
  142.                 s_LogListViewCurrentRow = listViewFieldInfo.FieldType.GetField("row", BindingFlags.Instance | BindingFlags.Public);  
  143.                 //LogEntries  
  144.                 Type logEntriesType = unityEditorAssembly.GetType("UnityEditorInternal.LogEntries");  
  145.                 s_LogEntriesGetEntry = logEntriesType.GetMethod("GetEntryInternal", BindingFlags.Static | BindingFlags.Public);  
  146.                 Type logEntryType = unityEditorAssembly.GetType("UnityEditorInternal.LogEntry");  
  147.                 s_LogEntry = Activator.CreateInstance(logEntryType);  
  148.                 s_LogEntryInstanceId = logEntryType.GetField("instanceID", BindingFlags.Instance | BindingFlags.Public);  
  149.                 s_LogEntryLine = logEntryType.GetField("line", BindingFlags.Instance | BindingFlags.Public);  
  150.                 s_LogEntryCondition = logEntryType.GetField("condition", BindingFlags.Instance | BindingFlags.Public);  
  151.             }  
  152.         }  
  153.         private static StackFrame GetListViewRowCount()  
  154.         {  
  155.             GetConsoleWindowListView();  
  156.             if (s_LogListView == null)  
  157.                 return null;  
  158.             else  
  159.             {  
  160.                 int totalRows = (int)s_LogListViewTotalRows.GetValue(s_LogListView);  
  161.                 int row = (int)s_LogListViewCurrentRow.GetValue(s_LogListView);  
  162.                 int logByThisClassCount = 0;  
  163.                 for (int i = totalRows - 1; i >= row; i--)  
  164.                 {  
  165.                     s_LogEntriesGetEntry.Invoke(nullnew object[] { i, s_LogEntry });  
  166.                     string condition = s_LogEntryCondition.GetValue(s_LogEntry) as string;  
  167.                     //判斷是否是由LoggerUtility打印的日志  
  168.                     if (condition.Contains("][") && condition.Contains("Frame"))  
  169.                         logByThisClassCount++;  
  170.                 }  
  171.   
  172.                 //同步日志列表,ConsoleWindow 點擊Clear 會清理  
  173.                 while (s_LogStackFrameList.Count > totalRows)  
  174.                     s_LogStackFrameList.RemoveAt(0);  
  175.                 if (s_LogStackFrameList.Count >= logByThisClassCount)  
  176.                     return s_LogStackFrameList[s_LogStackFrameList.Count - logByThisClassCount];  
  177.                 return null;  
  178.             }  
  179.         }  
  180.   
  181.         [UnityEditor.Callbacks.OnOpenAssetAttribute(0)]  
  182.         public static bool OnOpenAsset(int instanceID, int line)  
  183.         {  
  184.             if (instanceID == s_InstanceID && s_Line == line)  
  185.             {  
  186.                 var stackFrame = GetListViewRowCount();  
  187.                 if (stackFrame != null)  
  188.                 {  
  189.                     string fileName = stackFrame.GetFileName();  
  190.                     string fileAssetPath = fileName.Substring(fileName.IndexOf("Assets"));  
  191.                     AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<MonoScript>(fileAssetPath), stackFrame.GetFileLineNumber());  
  192.                     return true;  
  193.                 }  
  194.             }  
  195.              
  196.             return false;  
  197.         }  
  198. #endif  
  199.     }  
  200.   
  201. }  

 

 小結(jié):

        其實都沒有什么小結(jié)的,多說幾句:對于這個日志工具我還會進一步增加兩個優(yōu)化:遠程日志和通過字符串反射查詢運行時的值(前端調(diào)試還是沒有后端的來的方便,打斷點太低效了)。雨松MOMO最近分享了很多Editor的小trick,可以去他的博客和微博上找下,這里分享一個他反編譯Unity5.3的Bitbucket代碼 ,不過還不夠完美,反編譯的看不到private的 FieldInfo 和 MethdInfo ,這個也很有用。

 

       歡迎各種不爽,各種噴,寫這個純屬個人愛好,秉持”分享“之德!

 

       如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發(fā)郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。

       轉(zhuǎn)載請在文首注明出處:http://dsqiu./blog/2263664

更多精彩請關(guān)注D.S.Qiu的博客和微博(ID:靜水逐風(fēng))

      

 

 

 

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多