本指南介紹如何使用 Firebase Crashlytics SDK 自定義崩潰報告。默認情況下,Crashlytics 會自動收集應用程序的所有用戶的崩潰報告(您可以關閉自動崩潰報告並為用戶啟用選擇加入報告)。 Crashlytics 提供了四種開箱即用的日誌記錄機制:自定義鍵、自定義日誌、用戶標識符和捕獲的異常。
添加自定義鍵
自定義鍵可幫助您獲取應用程序導致崩潰的特定狀態。您可以將任意鍵/值對與崩潰報告關聯,然後使用自定義鍵在 Firebase 控制台中搜索和過濾崩潰報告。
- 在Crashlytics 儀表板中,您可以搜索與自定義鍵匹配的問題。
- 當您在控制台中查看特定問題時,您可以查看每個事件的關聯自定義鍵( “鍵”子選項卡),甚至可以按自定義鍵過濾事件(頁面頂部的“過濾器”菜單)。
使用setCustomValue
方法設置鍵/值對。例如:
迅速
// Set int_key to 100. Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key") // Set str_key to "hello". Crashlytics.crashlytics().setCustomValue("hello", forKey: "str_key")
Objective-C
設置整數、布爾值或浮點數時,請將值裝箱為@( value )
。
// Set int_key to 100. [[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"]; // Set str_key to "hello". [[FIRCrashlytics crashlytics] setCustomValue:@"hello" forKey:@"str_key"];
您還可以通過調用該鍵並將其設置為不同的值來修改現有鍵的值。例如:
迅速
Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key") // Set int_key to 50 from 100. Crashlytics.crashlytics().setCustomValue(50, forKey: "int_key")
Objective-C
[[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"]; // Set int_key to 50 from 100. [[FIRCrashlytics crashlytics] setCustomValue:@(50) forKey:@"int_key"];
使用setCustomKeysAndValues
方法(將 NSDictionary 作為唯一參數)批量添加鍵/值對:
迅速
let keysAndValues = [ "string key" : "string value", "string key 2" : "string value 2", "boolean key" : true, "boolean key 2" : false, "float key" : 1.01, "float key 2" : 2.02 ] as [String : Any] Crashlytics.crashlytics().setCustomKeysAndValues(keysAndValues)
Objective-C
NSDictionary *keysAndValues = @{@"string key" : @"string value", @"string key 2" : @"string value 2", @"boolean key" : @(YES), @"boolean key 2" : @(NO), @"float key" : @(1.01), @"float key 2" : @(2.02)}; [[FIRCrashlytics crashlytics] setCustomKeysAndValues: keysAndValues];
添加自定義日誌消息
為了給自己提供有關導致崩潰的事件的更多背景信息,您可以將自定義 Crashlytics 日誌添加到您的應用程序中。 Crashlytics 將日誌與崩潰數據相關聯,並將它們顯示在Firebase 控制台的 Crashlytics 頁面的“日誌”選項卡下。
迅速
使用log()
或log(format:, arguments:)
來幫助查明問題。如果您希望獲得包含消息的有用日誌輸出,則傳遞給log()
的對象必須符合CustomStringConvertible
屬性。 log()
返回您為對象定義的描述屬性。例如:
Crashlytics.crashlytics().log("Higgs-Boson detected! Bailing out…, \(attributesDict)")
.log(format:, arguments:)
對調用getVaList()
返回的值進行格式化。例如:
Crashlytics.crashlytics().log(format: "%@, %@", arguments: getVaList(["Higgs-Boson detected! Bailing out…", attributesDict]))
有關如何使用log()
或log(format:, arguments:)
的更多詳細信息,請參閱 Crashlytics參考文檔。
Objective-C
使用log
或logWithFormat
來幫助查明問題。請注意,如果您希望獲得包含消息的有用日誌輸出,則傳遞給任一方法的對象必須覆蓋description
實例屬性。例如:
[[FIRCrashlytics crashlytics] log:@"Simple string message"]; [[FIRCrashlytics crashlytics] logWithFormat:@"Higgs-Boson detected! Bailing out... %@", attributesDict]; [[FIRCrashlytics crashlytics] logWithFormat:@"Logging a variable argument list %@" arguments:va_list_arg];
有關如何使用log
和logWithFormat
的更多詳細信息,請參閱 Crashlytics參考文檔。
設置用戶標識符
要診斷問題,了解哪些用戶遇到了給定的崩潰通常很有幫助。 Crashlytics 包含一種在崩潰報告中匿名識別用戶的方法。
要將用戶 ID 添加到報告中,請為每個用戶分配一個 ID 號、令牌或哈希值形式的唯一標識符:
迅速
Crashlytics.crashlytics().setUserID("123456789")
Objective-C
[[FIRCrashlytics crashlytics] setUserID:@"123456789"];
如果您在設置用戶標識符後需要清除它,請將該值重置為空白字符串。清除用戶標識符不會刪除現有的 Crashlytics 記錄。如果您需要刪除與用戶 ID 關聯的記錄,請聯繫 Firebase 支持。
報告非致命異常
除了自動報告應用程序的崩潰之外,Crashlytics 還允許您記錄非致命異常,並在下次應用程序啟動時將其發送給您。
您可以通過使用recordError
方法記錄NSError
對象來記錄非致命異常。 recordError
通過調用[NSThread callStackReturnAddresses]
捕獲線程的調用堆棧。
迅速
Crashlytics.crashlytics().record(error: error)
Objective-C
[[FIRCrashlytics crashlytics] recordError:error];
使用recordError
方法時,了解NSError
結構以及 Crashlytics 如何使用數據對崩潰進行分組非常重要。錯誤使用recordError
方法可能會導致不可預測的行為,並可能導致 Crashlytics 限制報告您的應用程序記錄的錯誤。
NSError
對像有三個參數:
-
domain: String
-
code: Int
-
userInfo: [AnyHashable : Any]? = nil
與通過堆棧跟踪分析分組的致命崩潰不同,記錄的錯誤按domain
和code
分組。這是致命崩潰和記錄錯誤之間的重要區別。例如:
迅速
let userInfo = [ NSLocalizedDescriptionKey: NSLocalizedString("The request failed.", comment: ""), NSLocalizedFailureReasonErrorKey: NSLocalizedString("The response returned a 404.", comment: ""), NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString("Does this page exist?", comment: ""), "ProductID": "123456", "View": "MainView" ] let error = NSError.init(domain: NSCocoaErrorDomain, code: -1001, userInfo: userInfo)
Objective-C
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The request failed.", nil), NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The response returned a 404.", nil), NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Does this page exist?", nil), @"ProductID": @"123456", @"View": @"MainView", }; NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1001 userInfo:userInfo];
當您記錄上述錯誤時,它會創建一個按NSSomeErrorDomain
和-1001
分組的新問題。使用相同域和代碼值的其他記錄的錯誤被分組在同一問題下。 userInfo
對像中包含的數據將轉換為鍵值對並顯示在單個問題的鍵/日誌部分中。
日誌和自定義鍵
就像崩潰報告一樣,您可以嵌入日誌和自定義鍵以將上下文添加到NSError
。但是,附加到崩潰的日誌與記錄的錯誤的日誌有所不同。當發生崩潰並重新啟動應用程序時,Crashlytics 從磁盤檢索的日誌是截至崩潰時寫入的日誌。當您記錄NSError
時,應用程序不會立即終止。由於 Crashlytics 僅在下一次應用程序啟動時發送記錄的錯誤報告,並且必須限制磁盤上為日誌分配的空間量,因此可以在記錄NSError
後記錄足夠的日誌,以便在 Crashlytics 發送時所有相關日誌都已輪換出來來自設備的報告。在記錄NSErrors
以及在應用程序中使用日誌和自定義鍵時,請記住這種平衡。
性能考慮
請記住,記錄NSError
成本可能相當高。當您進行調用時,Crashlytics 使用稱為堆棧展開的過程捕獲當前線程的調用堆棧。此過程可能是 CPU 和 I/O 密集型的,特別是在支持 DWARF 展開的架構(arm64 和 x86)上。展開完成後,信息同步寫入磁盤。如果下一行崩潰,這可以防止數據丟失。
雖然在後台線程上調用此 API 是安全的,但請記住,將此調用分派到另一個隊列會丟失當前堆棧跟踪的上下文。
NSException 怎麼樣?
Crashlytics 不提供直接記錄和記錄NSException
實例的工具。一般來說,Cocoa 和 Cocoa Touch API 不是異常安全的。這意味著即使非常小心地使用, @catch
的使用也會在您的過程中產生非常嚴重的意外副作用。您永遠不應該在代碼中使用@catch
語句。請參閱有關該主題的 Apple 文檔。
自定義堆棧跟踪
如果您的應用程序在非本機環境(例如 C++ 或 Unity)中運行,您可以使用異常模型 API 以應用程序的本機異常格式報告崩潰元數據。報告的異常被標記為非致命的。
迅速
var ex = ExceptionModel(name:"FooException", reason:"There was a foo.") ex.stackTrace = [ StackFrame(symbol:"makeError", file:"handler.js", line:495), StackFrame(symbol:"then", file:"routes.js", line:102), StackFrame(symbol:"main", file:"app.js", line:12), ] crashlytics.record(exceptionModel:ex)
Objective-C
FIRExceptionModel *model = [FIRExceptionModel exceptionModelWithName:@"FooException" reason:@"There was a foo."]; model.stackTrace = @[ [FIRStackFrame stackFrameWithSymbol:@"makeError" file:@"handler.js" line:495], [FIRStackFrame stackFrameWithSymbol:@"then" file:@"routes.js" line:102], [FIRStackFrame stackFrameWithSymbol:@"main" file:@"app.js" line:12], ]; [[FIRCrashlytics crashlytics] recordExceptionModel:model];
自定義堆棧幀也可以僅使用地址進行初始化:
迅速
var ex = ExceptionModel.init(name:"FooException", reason:"There was a foo.") ex.stackTrace = [ StackFrame(address:0xfa12123), StackFrame(address:12412412), StackFrame(address:194129124), ] crashlytics.record(exceptionModel:ex)
Objective-C
FIRExceptionModel *model = [FIRExceptionModel exceptionModelWithName:@"FooException" reason:@"There was a foo."]; model.stackTrace = @[ [FIRStackFrame stackFrameWithAddress:0xfa12123], [FIRStackFrame stackFrameWithAddress:12412412], [FIRStackFrame stackFrameWithAddress:194129124], ]; [[FIRCrashlytics crashlytics] recordExceptionModel:model];
啟用選擇加入報告
默認情況下,Crashlytics 會自動收集應用程序的所有用戶的崩潰報告。為了讓用戶更好地控制他們發送的數據,您可以通過禁用自動報告來啟用選擇加入報告,並且僅當您在代碼中選擇時才將數據發送到 Crashlytics:
通過向
Info.plist
文件添加新密鑰來關閉自動收集:- 鍵:
FirebaseCrashlyticsCollectionEnabled
- 值:
false
- 鍵:
通過在運行時調用 Crashlytics 數據收集覆蓋來為選定用戶啟用收集。覆蓋值在應用程序啟動時持續存在,因此 Crashlytics 可以自動收集報告。
要選擇退出自動崩潰報告,請傳遞
false
作為覆蓋值。當設置為false
時,新值直到下次運行應用程序時才會應用。迅速
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
Objective-C
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];
管理崩潰洞察數據
Crash Insights 通過將匿名堆棧跟踪與其他 Firebase 應用的跟踪進行比較來幫助您解決問題,並讓您知道您的問題是否屬於更大趨勢的一部分。對於許多問題,Crash Insights 甚至提供資源來幫助您調試崩潰。
崩潰洞察使用聚合的崩潰數據來識別常見的穩定性趨勢。如果您不想共享應用的數據,可以從Firebase 控制台Crashlytics 問題列表頂部的Crash Insights菜單中選擇退出 Crash Insights。