Unity的日志事件
Unity提供了兩個日志回調API,這兩個回調函數的參數都是一樣的,通過這個API可以在真機上把Debug.Log/LogWarning/LogError 日志輸出到文件中保存,我建議使用Application.logMessageReceivedThreaded
Application.logMessageReceivedThreaded
Application.logMessageReceived
OnLogCallback(string condition, string stackTrace, LogType type) //回調函數
Application.logMessageReceived
此事件僅在主線程上觸發。如果你的處理程序需要訪問限制到主線線程的Unity API的一部分,或者由於其他原因你的處理程序不是線程安全的,就使用它
Application.logMessageReceivedThreaded
無論消息是否在主線程上傳入,此事件都將被觸發。這意味着處理程序代碼必須是線程安全的。它可以從不同的線程調用,也可以並行調用。確保僅從允許從主線程以外的線程調用的處理程序中訪問Unity API
注意:不必同時訂閱兩個應用消息:logMessageReceived和 Application.logMessageReceivedThreaded。對於主線程上的消息,也將調用多線程變體。
看到QFramework中提到這一樣一句話:
如果只是使用 Application.logMessageReceived 的時候,在真機上如果發生 Error 或者 Exception 時,收不到堆棧信息。但是使用了 Application.logMessageReceivedThreaded 就可以接收到堆棧信息了,不過在處理 Log 信息的時候要保證線程安全。
因為寫入日志的實現方式我和他是不一樣的,我是在主線程中寫入日志的,而他是再開了一個線程來寫入日志。所以我是沒有遇到他這個問題。
參數解釋
OnLogCallback(string condition, string stackTrace, LogType type)
condition:就是代碼中主動打印的日志
stackTrace:堆棧信息。如果Project Setting中設置的堆棧為ScriptOnly,則除了程序出錯,其它的Log是不會有堆棧信息的,而如果使用:Environment.StackTrace來代替stackTrace,則會有一串很長很長的堆棧。
目前我們的項目在Project Setting中也是設置的Script Only
Exception也可捕捉到
在程序中拋出異常,在日志回調中也可以捕捉到,比如在斷言中拋出異常
public static void Assert(object obj, string msg, params object[] args)
{
if (obj==null)
{
string formatMsg = $"[Error]{DateTime.Now.ToString("HH:mm:ss.fff")} Assert Failed! {string.Format(msg, args)}";
throw new Exception(formatMsg);
}
}
查看stackTrace
我的測試環境如下:
unity2019.3.7 個人版 打包pc版
設置一:Project Settings中設置的StackTrace全部為ScriptOnly
設置二:Project Settings中設置的StackTrace全部為Full
打的是Mono包而非IL2Cpp,設置為.NET 4.x或 .NET Stand都嘗試過,結果是一樣。
堆棧設置為ScriptOnly
測試代碼如下,在日志中不會打印調用堆棧,對於error也沒有堆棧,只有真正的exception發生才會有出錯堆棧
void OnClickBtn1()
{
Debug.Log("test log");
Debug.LogWarning("test log warn");
Debug.LogError("test log error");
//text1是不存在的,特意讓程序出錯,查看輸出堆棧
text1.text = "text";
}
[2020-11-27 14:54:35][Log]test log
[2020-11-27 14:54:35][Warning]test log warn
[2020-11-27 14:54:35][Error]test log error
[2020-11-27 14:54:35][Exception]NullReferenceException: Object reference not set to an instance of an object
TestLogStackTrace.OnClickBtn2 () (at
UnityEngine.Events.InvokableCall.Invoke () (at <73b499366e5241bda47e5da76897738b>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <73b499366e5241bda47e5da76897738b>:0)
UnityEngine.UI.Button.Press () (at
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at
UnityEngine.EventSystems.EventSystem:Update()
把堆棧打印出來
而在某些情況下,我們希望把函數的調用者打印出來,可以通過StackTrace
測試代碼如下:
void OnClickBtn1()
{
Debug.Log(this.name + "click stacktrace:\n" + new StackTrace(true) + "\n");
}
輸出結果如下:
[2020-11-27 17:43:45]Canvasclick stacktrace:
at TestLogStackTrace.OnClickBtn1 () [0x00000] in <3010e64894cc4fd9b62b8f33b1cc1f8a>:0
at UnityEngine.Events.InvokableCall.Invoke () [0x00000] in <73b499366e5241bda47e5da76897738b>:0
at UnityEngine.Events.UnityEvent.Invoke () [0x00000] in <73b499366e5241bda47e5da76897738b>:0
at UnityEngine.EventSystems.EventSystem.Update () [0x00000] in <3fe6533ed4534466954fc02559cdbfd7>:0
堆棧設置為Full
設置為Full之后,在日志文件中,對於Debug.Log ~ Debug.LogError都會有非常非常長的一串Unity的調用堆棧
[2020-11-27 14:58:47][Log]test log
0x00007FFCA6DB060C (UnityPlayer)
0x00007FFCA6DB3933 (UnityPlayer)
0x00007FFCA6DA32CD (UnityPlayer)
0x00007FFCA7646A9E (UnityPlayer) UnityMain
0x00007FFCA71B9011 (UnityPlayer) UnityMain
0x000001C7AAEDF6EE (Mono JIT Code) (wrapper managed-to-native) UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object)
0x000001C7AAEDF3FB (Mono JIT Code) UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
0x000001C7AAEDF0D0 (Mono JIT Code) UnityEngine.Logger:Log (UnityEngine.LogType,object)
0x000001C7AAEDEE4A (Mono JIT Code) UnityEngine.Debug:Log (object)
0x000001C7AAF2F693 (Mono JIT Code) TestLogStackTrace:OnClickBtn2 ()
0x000001C7AAF2F649 (Mono JIT Code) UnityEngine.Events.InvokableCall:Invoke ()
0x000001C7AAF2F39B (Mono JIT Code) UnityEngine.Events.UnityEvent:Invoke ()
0x000001C7AAF2F123 (Mono JIT Code) UnityEngine.UI.Button:Press ()
0x000001C7AAF2F063 (Mono JIT Code) UnityEngine.UI.Button:OnPointerClick (UnityEngine.EventSystems.PointerEventData)
0x000001C7AAF2F009 (Mono JIT Code) UnityEngine.EventSystems.ExecuteEvents:Execute (UnityEngine.EventSystems.IPointerClickHandler,UnityEngine.EventSystems.BaseEventData)
0x000001C7AAF2A8F2 (Mono JIT Code) UnityEngine.EventSystems.ExecuteEvents:Execute<T_REF> (UnityEngine.GameObject,UnityEngine.EventSystems.BaseEventData,UnityEngine.EventSystems.ExecuteEvents/EventFunction`1<T_REF>)
0x000001C7AAF2ED0B (Mono JIT Code) UnityEngine.EventSystems.StandaloneInputModule:ReleaseMouse (UnityEngine.EventSystems.PointerEventData,UnityEngine.GameObject)
0x000001C7AAF25773 (Mono JIT Code) UnityEngine.EventSystems.StandaloneInputModule:ProcessMousePress (UnityEngine.EventSystems.PointerInputModule/MouseButtonEventData)
0x000001C7AAEFFD73 (Mono JIT Code) UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent (int)
0x000001C7AAF0FF8B (Mono JIT Code) UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent ()
0x000001C7AAF1FEA3 (Mono JIT Code) UnityEngine.EventSystems.StandaloneInputModule:Process ()
0x000001C7AAF04AFF (Mono JIT Code) UnityEngine.EventSystems.EventSystem:Update ()
0x000001C7677FAA20 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007FFCAF2FCBA0 (mono-2.0-bdwgc) mono_get_runtime_build_info
0x00007FFCAF282112 (mono-2.0-bdwgc) mono_perfcounters_init
0x00007FFCAF28B10F (mono-2.0-bdwgc) mono_runtime_invoke
0x00007FFCA71554DD (UnityPlayer) UnityMain
0x00007FFCA71528B3 (UnityPlayer) UnityMain
0x00007FFCA713BBD3 (UnityPlayer) UnityMain
0x00007FFCA713BC8D (UnityPlayer) UnityMain
0x00007FFCA6ED1D30 (UnityPlayer) UnityMain
0x00007FFCA701A717 (UnityPlayer) UnityMain
0x00007FFCA701A7B3 (UnityPlayer) UnityMain
0x00007FFCA701CBBB (UnityPlayer) UnityMain
0x00007FFCA6DD7E5E (UnityPlayer)
0x00007FFCA6DD6BBA (UnityPlayer)
0x00007FFCA6DDAA7C (UnityPlayer)
0x00007FFCA6DDE56B (UnityPlayer) UnityMain
0x00007FF6FC6211F2 (UGUIDemo)
0x00007FFD26047974 (KERNEL32) BaseThreadInitThunk
0x00007FFD2694A0B1 (ntdll) RtlUserThreadStart
測試結果文件
結果文件我上傳在 我的github
