1. 程式人生 > 實用技巧 >把Unity的日誌儲存到檔案中

把Unity的日誌儲存到檔案中

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

檢視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 :0)
UnityEngine.Events.InvokableCall.Invoke () (at <73b499366e5241bda47e5da76897738b>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <73b499366e5241bda47e5da76897738b>:0)
UnityEngine.UI.Button.Press () (at :0)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at :0)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at :0)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at :0)
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