自訂 Apple 平台的當機報告

選取平台: iOS+ Android Flutter Unity


您可以在 控制台的「DevOps 與參與度」 > 「Crashlytics 資訊主頁」中,點選問題並取得詳細的事件報表。Firebase您可以自訂這些報表,進一步瞭解應用程式的運作情形,以及向 Crashlytics 回報的事件相關情況。

新增自訂鍵

你可以使用自訂鍵,取得導致當機情況的應用程式特定狀態。您可以將任意鍵/值組合與當機報告建立關聯,然後使用自訂鍵,在 Firebase 控制台的「DevOps & Engagement」 > 「Crashlytics 資訊主頁」中搜尋及篩選當機報告。

  • 您可以搜尋與自訂鍵相符的問題。

  • 在控制台中查看特定問題時,您可以查看每個事件的相關自訂鍵 (「Keys」子分頁),甚至可以依自訂鍵篩選事件 (頁面頂端的「Filter」選單)。

使用 setCustomValue 方法設定鍵/值組合。例如:

Swift

// 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"];

您也可以呼叫現有索引鍵並設定為其他值,藉此修改該索引鍵的值。例如:

Swift

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 做為唯一參數,即可大量新增鍵/值組合:

Swift

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 會將記錄與當機資料建立關聯,並在您查看問題詳細資料時,將記錄顯示在「Logs」分頁中 (如要查看所有問題,請前往 Firebase 控制台的「DevOps & Engagement」 >「Crashlytics dashboard」)。

Swift

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

設定使用者 ID

如要診斷問題,瞭解哪些使用者遇到特定當機情形,通常很有幫助。Crashlytics 提供一種方法,可在當機報告中匿名識別使用者。

如要在報表中加入使用者 ID,請以 ID 號碼、權杖或雜湊值的形式,為每位使用者指派專屬 ID:

Swift

Crashlytics.crashlytics().setUserID("123456789")

Objective-C

[[FIRCrashlytics crashlytics] setUserID:@"123456789"];

如果設定後需要清除使用者 ID,請將值重設為空白字串。清除使用者 ID 不會移除現有的 Crashlytics 記錄。如需刪除與使用者 ID 相關聯的記錄,請聯絡 Firebase 支援團隊。

回報非致命例外狀況

除了自動回報應用程式當機情形外,Crashlytics 還可讓您記錄非致命例外狀況,並在下次啟動應用程式時傳送給您。

您可以使用 recordError 方法記錄 NSError 物件,藉此記錄非致命例外狀況。recordError 會呼叫 [NSThread callStackReturnAddresses],擷取執行緒的呼叫堆疊。

Swift

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 分組。這是嚴重當機和記錄錯誤之間的重要區別。例如:

Swift

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 是安全的,但請注意,將這個呼叫調度到另一個佇列會失去目前堆疊追蹤的背景資訊。

NSExceptions 呢?

Crashlytics 未提供直接記錄 NSException 執行個體的功能。一般來說,Cocoa 和 Cocoa Touch API 並非例外安全。這表示即使您在使用 @catch 時極為謹慎,仍可能在程序中造成非常嚴重的非預期副作用。請勿在程式碼中使用 @catch 陳述式。請參閱 Apple 說明文件。

自訂堆疊追蹤

如果應用程式在非原生環境 (例如 C++ 或 Unity) 中執行,您可以使用 Exception Model API,以應用程式的原生例外狀況格式回報當機中繼資料。回報的例外狀況會標示為非嚴重。

Swift

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];

自訂堆疊框架也可以只用位址初始化:

Swift

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];

取得當機前使用者動作記錄

當機前使用者動作記錄可協助您進一步瞭解使用者在發生當機、非致命錯誤或 ANR 事件前,與應用程式的互動情形。在嘗試重現及偵錯問題時,這些記錄會很有幫助。

當機前使用者動作記錄由 Google Analytics 提供,因此您必須為 Firebase 專案啟用 Google Analytics,並在應用程式中新增 Google Analytics 的 Firebase SDK,才能取得這類記錄。符合這些條件後,當您查看問題詳細資料時,當機前使用者動作記錄就會自動包含在「記錄」分頁的事件資料中 (您可以在 Firebase 控制台的「開發運作和參與度」>「Crashlytics 資訊主頁」中查看所有問題)。

Analytics SDK 會自動記錄 screen_view 事件,讓當機前使用者動作記錄顯示當機、非致命錯誤或 ANR 事件發生前,使用者瀏覽過的畫面清單。screen_view 當機前使用者動作記錄包含 firebase_screen_class 參數。

當機前使用者動作記錄也會填入您在使用者工作階段中手動記錄的任何自訂事件,包括事件的參數資料。這項資料可協助您瞭解導致當機、一般錯誤或 ANR 事件的一連串使用者動作。

請注意,您可以控管 Google Analytics 資料的收集和使用方式,包括填入當機前使用者動作記錄的資料。

啟用選擇加入報表

根據預設,Crashlytics 會自動收集所有應用程式使用者的當機報告。如要讓使用者進一步控管傳送的資料,您可以停用自動回報功能,並在程式碼中選擇僅將資料傳送至 Crashlytics,藉此啟用選擇加入回報功能。

  1. 如要關閉自動收集功能,請在 Info.plist 檔案中新增金鑰:

    • 鍵:FirebaseCrashlyticsCollectionEnabled
    • 值:false
  2. 在執行階段呼叫 Crashlytics 資料收集覆寫,為特定使用者啟用收集功能。覆寫值會在後續所有應用程式啟動時保留,因此 Crashlytics 可以自動收集該使用者的報表。

    Swift

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Objective-C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

    如果使用者之後選擇不收集資料,您可以傳遞 false 做為覆寫值,這會在使用者下次啟動應用程式時套用,並在該使用者之後的所有啟動中持續套用。

管理 Crash Insights 資料

Crash Insights 會將您的去識別化堆疊追蹤與其他 Firebase 應用程式的追蹤記錄進行比較,並在問題屬於更廣泛的趨勢時通知您,協助您解決問題。對於許多問題,當機情況深入分析甚至會提供資源,協助您對當機情況進行偵錯。

Crash Insights 會使用匯總的當機資料,找出常見的穩定性趨勢。如果不想分享應用程式資料,可以前往 Firebase 控制台的 DevOps 與參與度 > Crashlytics 資訊主頁 資訊主頁,在問題清單頂端的 當機深入分析 選單中,選擇不採用當機深入分析功能。

後續步驟