Firebase Crashlytics のクラッシュ レポートをカスタマイズする

iOS
android

Firebase Crashlytics を動作させるためにユーザー側で行う設定はほとんどありません。SDK を追加するとすぐに、Crashlytics はクラッシュ レポートを Firebase コンソールに送信するようになります。

クラッシュ レポートを細かく制御するには、Crashlytics SDK の設定をカスタマイズします。たとえば、プライバシーを重視するユーザー用にオプトイン レポートを有効にしたり、面倒なバグを追跡するためにログを追加したりするなど、さまざまなカスタマイズが可能です。

オプトイン レポートを有効にする

デフォルトでは、Firebase Crashlytics は自動的にアプリの全ユーザーを対象にクラッシュ レポートを収集します。どのデータを送信するかをユーザーが細かく制御できるようにするには、デフォルトの代わりにオプトイン レポートを有効にします。

オプトイン レポートを有効にするには、自動収集を無効にして、オプトイン ユーザーに対してのみ Crashlytics を初期化する必要があります。

iOS
  1. Info.plist ファイルの新しいキーを使用して自動収集を無効にします。
    • キー: firebase_crashlytics_collection_enabled
    • 値: false
  2. Crashlytics を実行時に初期化して、選択されたユーザーに対して収集を有効にします。
    Objective-C
    [Fabric with:@[[Crashlytics class]]];
    Swift
    Fabric.with([Crashlytics.self])
android
  1. AndroidManifest.xml ファイル内で meta-data タグを使用して自動収集を無効にします。
    <meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />
  2. アプリのいずれかのアクティビティから Crashlytics を初期化して、選択されたユーザーに対して収集を有効にします。
    Fabric.with(this, new Crashlytics());
注: アプリのセッションで Crashlytics を初期化した後は、Crashlytics によるレポート作成を停止できません。ユーザーが Crashlytics の初期化後にレポートをオプトアウトするには、アプリを再起動する必要があります。

カスタムログを追加する

クラッシュにつながったイベントのコンテキストをさらに詳細に把握するには、カスタム Crashlytics ログをアプリに追加します。Crashlytics はログをクラッシュ データに関連付けて、Firebase コンソールで表示できるようにします。

iOS
Objective-C

Objective-C では、CLS_LOG を使用すると問題の特定に役立ちます。これを使用すると、ログに関連付けられた Objective-C のクラス、メソッド、行番号に関する情報が自動的にログに組み込まれるようになります。

CLS_LOG の動作は、ロギング対象がビルドのデバッグまたはビルドのリリースのどちらであるかによって異なります。

  • デバッグビルド: CLS_LOGNSLog に渡されるため、出力を Xcode や端末またはシミュレータで表示できます。
  • リリースビルド: パフォーマンスを向上させるために、CLS_LOG はその他すべての出力を無効にし、NSLog に出力を渡しません。

CLS_LOG でログを記録するには、次のように CLS_LOG(format, ...) を使用します。

CLS_LOG(@"Higgs-Boson detected! Bailing out... %@", attributesDict);

CLS_LOG の使用方法の詳細については、Crashlytics/Crashlytics.h ヘッダー ファイルを参照してください。

Swift

Swift では、CLSLogv または CLSNSLogv が問題の特定に役立ちます。

CLSLogv および CLSNSLogv を使用してログを記録する際は、次の 2 点に注意してください。

  • 形式を指定する引数は、コンパイル時の定数文字列でなければなりません。これは Objective-C ではコンパイラによって強制されますが、現在のところ、この保護は Swift へのブリッジングで失われます。
  • ログの値を配列に格納し、その配列に対して getVaList を呼び出して値を取得します。

例:

func write(string: String) {
    CLSLogv("%@", getVaList([string]))
}
Swift 文字列を内挿しても、コンパイル時の定数文字列にはなりません。printf や NSLog の場合と同じく、CLSLog で非定数文字列を使用するとクラッシュが発生する可能性があります。

詳細

さらに細かく制御するには、CLSLog(format, ...)CLSNSLog(format, ...) を直接利用することができます。後者は NSLog に渡されるため、出力を Xcode や端末またはシミュレータで表示できます。CLSLog(format, ...)CLSNSLog(format, ...) はスレッドセーフです。CLSLog は、クラッシュを解決する上で重要な情報をログに記録するためのものです。アプリ内イベントの追跡には使用しないでください。

android

Android では、Crashlytics.log が問題の特定に役立ちます。

Crashlytics.log では、Log.println() を指定してログをクラッシュ レポートに書き込むか、単に次のクラッシュ レポートに書き込むことができます。

  • クラッシュ レポートと Log.println:
    Crashlytics.log(int priority, String tag, String msg);
  • クラッシュ レポートのみ:
    Crashlytics.log(msg);
アプリの速度低下を避けるため、Crashlytics ではログのサイズを 64 KB に制限しています。セッションのログがこの上限を超えると、Crashlytics は古いエントリからログを削除します。

カスタムキーを追加する

カスタムキーを使用して、クラッシュにつながったアプリの特定の状態を把握できます。任意の Key-Value ペアをクラッシュ レポートに関連付けて、Firebase コンソールでそれらのペアを表示することができます。

iOS

[CrashlyticsKit setObjectValue:forKey:] または関連するいずれかのメソッドで開始します。

- (void)setObjectValue:(id)value forKey:(NSString *)key;

// calls -description on value, perfect for NSStrings!
- (void)setIntValue:(int)value forKey:(NSString *)key;

- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;

- (void)setFloatValue:(float)value forKey:(NSString *)key;

場合によっては、既存のキー値の変更が必要です。その場合、次の例のように同じキーを、値を置き換えて呼び出します。

Objective-C
[CrashlyticsKit setIntValue:3 forKey:@"current_level"];
[CrashlyticsKit setObjectValue:@"logged_in" forKey:@"last_UI_action"];
Swift
Crashlytics.sharedInstance().setIntValue(42, forKey: "MeaningOfLife")
Crashlytics.sharedInstance().setObjectValue("Test value", forKey: "last_UI_action")
android

キーを設定するには 5 つの方法があります。設定方法によって、処理するデータ型は異なります。

Crashlytics.setString(key, value);

Crashlytics.setBool(String key, boolean value);

Crashlytics.setDouble(String key, double value);

Crashlytics.setFloat(String key, float value);

Crashlytics.setInt(String key, int value);

次のように、キーを再設定するとその値が更新されます。

Crashlytics.setInt("current_level", 3);
Crashlytics.setString("last_UI_action", "logged_in");
Crashlytics では、最大 64 個の Key-Value ペアがサポートされます。このしきい値に達すると、それ以上値が保存されなくなります。各 Key-Value ペアの最大サイズは 1 KB です。

ユーザー ID を設定する

問題を診断する際には、多くの場合、特定のクラッシュがどのユーザーで発生したかを把握すると役立ちます。Crashlytics には、クラッシュ レポート内でユーザーを匿名で識別する手段が用意されています。

iOS

レポートにユーザー ID を追加するには、各ユーザーに ID 番号、トークン、またはハッシュ値の形で一意の ID を割り当てます。

Objective-C
[CrashlyticsKit setUserIdentifier:@"123456789"];
Swift
Crashlytics.sharedInstance().setUserIdentifier("123456789")

ユーザー ID を設定後にクリアする必要が生じた場合は、ID の値を空白の文字列にリセットします。

android

レポートにユーザー ID を追加するには、各ユーザーに ID 番号、トークン、またはハッシュ値の形で一意の ID を割り当てます。

void Crashlytics.setUserIdentifier(String identifier);

ユーザー ID を設定後クリアする必要が生じた場合は、ID の値を空白の文字列にリセットします。

致命的でない例外をログに記録する

Crashlytics では自動的にアプリのクラッシュを報告するだけでなく、致命的でない例外をユーザーがログに記録できるようになっています。

iOS

iOS で非致命的な例外をログに記録するには、NSError オブジェクトを記録します。Crashlytics はこのオブジェクトを、クラッシュと同様に報告およびグループ化します。

Objective-C
[CrashlyticsKit recordError:error];
Swift
Crashlytics.sharedInstance().recordError(error)

recordError メソッドを使用する場合、NSError の構造と、このデータを使用して Crashlytics がどのようにクラッシュをグループ化するかを理解していることが重要です。recordError メソッドを誤った方法で使用すると、予測不可能な動作が発生し、アプリについてログに記録されたエラーの報告を Crashlytics が制限する必要が生じる可能性があります。

NSError オブジェクトの引数は次の 3 つです。domain: Stringcode: IntuserInfo: [AnyHashable : Any]? = nil

スタック トレース分析によってグループ化される致命的なクラッシュとは異なり、ログに記録されるエラーは NSError の domaincode を基準にグループ化されます。これは、致命的なクラッシュとログに記録されるエラーとの重要な違いです。たとえば、次のエラーをログに記録するとします。

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";
    UserID: @"Jane Smith"
};

NSError *error = [NSError domain:NSSomeErrorDomain
                          code:-1001
                          userInfo:userInfo];

これにより、NSSomeErrorDomain-1001 を基準にグループ化される新しい問題が作成されます。以降にログに記録される、同じドメインとコードの値が使用されているエラーは、この問題に分類されます。

domain フィールドと code フィールドには、ユーザー ID、製品 ID、タイムスタンプなどの一意の値を使用しないでください。これらのフィールドに一意の値を使用すると、問題のカーディナリティが高くなり、アプリ内でログに記録されたエラーの報告を Crashlytics が制限する必要が生じることがあります。一意の値は、代わりに userInfo 辞書オブジェクトに追加してください。

userInfo オブジェクト内に格納されたデータは Key-Value ペアに変換され、各問題内の keys/logs セクションに表示されます。

Crashlytics は所定のアプリ セッションで、最新の 8 件の例外だけを保管します。アプリが 1 つのセッションで 8 件を超える例外をスローすると、古い例外が失われます。

ログとカスタムキー

クラッシュ レポートと同様に、ログとカスタムキーを埋め込んで NSError にコンテキストを追加することができます。ただし、クラッシュに関連付けられるログと、ログに記録されるエラーに関連付けられるログには違いがあります。クラッシュが発生してアプリが再起動された時点で Crashlytics がディスクから取得するログは、クラッシュが発生する直前までに書き込まれたログです。NSError をログに記録した場合、アプリが直ちに終了することはありません。Crashlytics はアプリが次に起動されるまでログに記録されたエラーのレポートを送信せず、また、Crashlytics はディスク上でログに割り当てるスペースの量を制限しなければならないため、NSError が記録された後、十分な数のログが記録され、Crashlytics が端末からレポートを送信するときには、関連するすべてのログが回転してクリアされている可能性があります。アプリで NSErrors をログに記録し、CLSLog とカスタムキーを使用する場合は、このバランスに注意してください。

パフォーマンスに関する注意事項

NSError のロギングでは、コストがかなり高くなる場合があるので注意してください。Crashlytics を呼び出した時点で、Crashlytics はスタックの巻き戻しと呼ばれるプロセスによって現行スレッドのコールスタックをキャプチャします。このプロセスでは CPU と I/O の使用量が高まります。特に、DWARF 巻き戻しをサポートするアーキテクチャ(arm64 および x86)で顕著です。巻き戻しが完了した後、情報が同期的にディスクに書き込まれます。これにより、次の行でクラッシュが発生した場合のデータ損失を防ぎます。

この API 呼び出しはバックグラウンド スレッドで行っても差し支えありませんが、この呼び出しを別のキューにディスパッチすると、現在のスタック トレースのコンテキストが失われることに注意してください。

NSExceptions とは

Crashlytics には、NSException インスタンスを直接ロギング/記録する機能がありません。一般に、Cocoa API と Cocoa Touch API は例外セーフではありません。つまり、@catch を使用すると、かなり慎重を期したとしても、プロセスに非常に深刻な想定外の副次作用がもたらされる可能性があります。コードでは決して @catch ステーメントを使用しないでください。このトピックについては、Apple のドキュメントをご覧ください。

android

Android では、これは、アプリの catch ブロックでキャッチされた例外をログに記録できることを意味します。

try {
    methodThatThrows();
} catch (Exception e) {
    Crashlytics.logException(e);
    // handle your exception here
}

ログに記録された例外は、いずれも Firebase コンソースでは非致命的な問題として表示されます。問題の概要には、クラッシュの場合に通常表示されるすべての状態情報に加え、Android バージョンおよびハードウェア端末ごとの内訳が示されます。

Crashlytics は専用のバックグラウンド スレッドで例外を処理するため、アプリのパフォーマンスに対する影響は最小限です。ユーザーのネットワーク トラフィックを削減するために、Crashlytics はログに記録された例外を 1 回の送信分にまとめて、アプリの次の起動時に送信します。

Crashlytics は所定のアプリ セッションで、最新の 8 件の例外だけを保管します。アプリが 1 つのセッションで 8 件を超える例外をスローすると、古い例外が失われます。

クラッシュ分析データを管理する

クラッシュ分析は、匿名化されたスタック トレースと他の Firebase アプリのトレースを比較し、問題がより大きい傾向の一部である場合にそのことを通知することによって、問題の解決に役立ちます。多くの問題について、クラッシュ分析はクラッシュのデバッグに役立つリソースも提供します。

クラッシュ分析は、集計されたクラッシュ データを使用して、一般的な安定性の傾向を特定します。アプリのデータを共有しない場合は、Firebase コンソールの Crashlytics 問題リストの最上部にある [Crash Insights] メニューからクラッシュ分析を無効にできます。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。