Check out what’s new from Firebase@ Google I/O 2021, and join our alpha program for early access to the new Remote Config personalization feature. Learn more

自定義您的 Firebase Crashlytics 崩潰報告

本指南介紹瞭如何使用 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")

目標-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")

目標-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)

目標-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 頁面中的Logs選項卡下。

迅速

使用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參考文檔

目標-C

使用loglogWithFormat幫助查明問題。請注意,如果您想獲得帶有消息的有用日誌輸出,則傳遞給任一方法的對象必須覆蓋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];

有關如何使用loglogWithFormat更多詳細信息,請參閱 Crashlytics參考文檔

設置用戶標識符

要診斷問題,了解哪些用戶遇到了給定的崩潰通常很有幫助。 Crashlytics 包括一種在崩潰報告中匿名識別用戶的方法。

要將用戶 ID 添加到您的報告中,請以 ID 號、令牌或散列值的形式為每個用戶分配一個唯一標識符:

迅速
Crashlytics.crashlytics().setUserID("123456789")
目標-C
[[FIRCrashlytics crashlytics] setUserID:@"123456789"];

如果您在設置後需要清除用戶標識符,請將值重置為空字符串。清除用戶標識符不會刪除現有的 Crashlytics 記錄。如果您需要刪除與用戶 ID 關聯的記錄,請聯繫 Firebase 支持

報告非致命異常

除了自動報告您的應用程序崩潰之外,Crashlytics 還允許您記錄非致命異常並在您的應用程序下次啟動時將它們發送給您。

您可以通過使用recordError方法記錄NSError對象來記錄非致命異常。 recordError通過調用[NSThread callStackReturnAddresses] recordError捕獲線程的調用堆棧。

迅速

Crashlytics.crashlytics().record(error: error)

目標-C

[[FIRCrashlytics crashlytics] recordError:error];

使用recordError方法時,了解NSError結構以及 Crashlytics 如何使用數據對崩潰進行分組很重要。 recordError方法的不正確使用可能會導致不可預測的行為,並可能導致 Crashlytics 限制為您的應用程序記錄錯誤的報告。

NSError對象具有三個參數:

  • domain: String
  • code: Int
  • userInfo: [AnyHashable : Any]? = nil

與通過堆棧跟踪分析分組的致命崩潰不同,記錄的錯誤按domaincode分組。這是致命崩潰和記錄錯誤之間的重要區別。例如:

迅速

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)

目標-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像中包含的數據將轉換為鍵值對並顯示在單個問題的鍵/日誌部分中。

警告:避免在域和代碼字段中使用唯一值,例如用戶 ID、產品 ID 和時間戳。在這些字段中使用唯一值會導致高基數問題,並可能導致 Crashlytics 需要限制應用程序中記錄錯誤的報告。應該將唯一值添加到userInfo字典對像中。

日誌和自定義鍵

就像崩潰報告一樣,您可以嵌入日誌和自定義鍵以向NSError添加上下文。但是,附加到崩潰的日誌與記錄的錯誤的日誌有所不同。當發生崩潰並重新啟動應用程序時,Crashlytics 從磁盤檢索的日誌是在崩潰發生之前寫入的日誌。當您記錄NSError ,應用程序不會立即終止。由於 Crashlytics 僅在下一次應用程序啟動時發送記錄的錯誤報告,並且必須限制為磁盤上的日誌分配的空間量,因此可以在記錄NSError後記錄足夠多的日誌,以便在 Crashlytics 發送時輪換所有相關日誌來自設備的報告。在記錄NSErrors並在您的應用程序中使用日誌和自定義鍵時,請記住這種平衡。

性能注意事項

請記住,記錄NSError可能相當昂貴。在您進行調用時,Crashlytics 使用稱為堆棧展開的過程捕獲當前線程的調用堆棧。此過程可能是 CPU 和 I/O 密集型的,尤其是在支持 DWARF 展開(arm64 和 x86)的體系結構上。展開完成後,信息同步寫入磁盤。如果下一行崩潰,這可以防止數據丟失。

雖然在後台線程上調用此 API 是安全的,但請記住,將此調用分派到另一個隊列會丟失當前堆棧跟踪的上下文。

NSExceptions 呢?

Crashlytics 不提供直接記錄和記錄NSException實例的工具。一般來說,Cocoa 和 Cocoa Touch API 不是異常安全的。這意味著使用@catch可能會在您的過程中產生非常嚴重的意外副作用,即使使用時非常小心。你永遠不應該在你的代碼中使用@catch語句。請參閱Apple關於該主題的文檔

自定義堆棧跟踪

如果您的應用在非原生環境(例如 C++ 或 Unity)中運行,您可以使用異常模型 API 以應用的原生異常格式報告崩潰元數據。報告的異常被標記為非致命的。

迅速

var  ex = ExceptionModel.init(name:"FooException", reason:"There was a foo.")
ex.stackTrace = [
  StackFrame.init(symbol:"makeError" fileName:"handler.js" lineNumber:495),
  StackFrame.init(symbol:"then" fileName:"routes.js" lineNumber:102),
  StackFrame.init(symbol:"main" fileName:"app.js" lineNumber:12),
]

crashlytics.record(exceptionModel:ex)

目標-C

FIRExceptionModel *model =
    [FIRExceptionModel exceptionModelWithName:@"FooException" reason:@"There was a foo."];
model.stackTrace = @[
  [FIRStackFrame stackFrameWithSymbol:@"makeError" fileName:@"handler.js" lineNumber:495],
  [FIRStackFrame stackFrameWithSymbol:@"then" fileName:@"routes.js" lineNumber:102],
  [FIRStackFrame stackFrameWithSymbol:@"main" fileName:@"app.js" lineNumber: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)

目標-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 來啟用選擇加入報告:

  1. 通過向Info.plist文件添加新密鑰來關閉自動收集:

    • 鍵: FirebaseCrashlyticsCollectionEnabled
    • 值: false
  2. 通過在運行時調用 Crashlytics 數據收集覆蓋,為選定用戶啟用收集。覆蓋值在您的應用程序啟動期間保持不變,因此 Crashlytics 可以自動收集報告。要選擇退出自動崩潰報告,請將false作為覆蓋值傳遞。當設置為false ,新值直到應用程序的下一次運行才會應用。

    迅速
    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
    目標-C
    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

管理崩潰洞察數據

Crash Insights 通過將您的匿名堆棧跟踪與來自其他 Firebase 應用的跟踪進行比較,並讓您知道您的問題是否屬於更大趨勢的一部分,從而幫助您解決問題。對於許多問題,Crash Insights 甚至提供資源來幫助您調試崩潰。

Crash Insights 使用匯總的崩潰數據來識別常見的穩定性趨勢。如果您不想共享應用的數據,您可以從Firebase 控制台中Crashlytics 問題列表頂部的Crash Insights菜單中選擇退出 Crash Insights。