Firebase is back at Google I/O on May 10! Register now

Dostosuj raporty o awariach Firebase Crashlytics

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

W tym przewodniku opisano, jak dostosować raporty o awariach za pomocą pakietu SDK Firebase Crashlytics. Domyślnie Crashlytics automatycznie zbiera raporty o awariach dla wszystkich użytkowników Twojej aplikacji (możesz wyłączyć automatyczne raportowanie o awariach i zamiast tego włączyć opcjonalne raportowanie dla swoich użytkowników). Crashlytics udostępnia cztery standardowe mechanizmy rejestrowania: klucze niestandardowe , dzienniki niestandardowe , identyfikatory użytkowników i przechwycone wyjątki .

Dodaj niestandardowe klucze

Klucze niestandardowe pomagają uzyskać określony stan aplikacji prowadzący do awarii. Możesz powiązać dowolne pary klucz/wartość z raportami o awariach, a następnie użyć niestandardowych kluczy do wyszukiwania i filtrowania raportów o awariach w konsoli Firebase.

  • W panelu Crashlytics możesz wyszukiwać problemy pasujące do klucza niestandardowego.
  • Przeglądając konkretny problem w konsoli, możesz wyświetlić powiązane klucze niestandardowe dla każdego zdarzenia (karta podrzędna Klucze ), a nawet filtrować zdarzenia według kluczy niestandardowych (menu Filtruj u góry strony).

Użyj metody setCustomValue , aby ustawić pary klucz/wartość. Na przykład:

Szybki

// Set int_key to 100.
Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key")

// Set str_key to "hello".
Crashlytics.crashlytics().setCustomValue("hello", forKey: "str_key")

Cel C

Podczas ustawiania liczb całkowitych, logicznych lub zmiennoprzecinkowych umieść wartość w ramce @( 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"];

Możesz także zmodyfikować wartość istniejącego klucza, wywołując klucz i ustawiając go na inną wartość. Na przykład:

Szybki

Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key")

// Set int_key to 50 from 100.
Crashlytics.crashlytics().setCustomValue(50, forKey: "int_key")

Cel C

[[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"];

// Set int_key to 50 from 100.
[[FIRCrashlytics crashlytics] setCustomValue:@(50) forKey:@"int_key"];

Masowo dodaj pary klucz/wartość, używając metody setCustomKeysAndValues ​​z NSDictionary jako jedynym parametrem:

Szybki

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)

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

Dodaj niestandardowe komunikaty dziennika

Aby zapewnić sobie lepszy kontekst dla zdarzeń prowadzących do awarii, możesz dodać do swojej aplikacji niestandardowe dzienniki Crashlytics. Crashlytics łączy dzienniki z danymi o awariach i wyświetla je na stronie Crashlytics w konsoli Firebase na karcie Dzienniki .

Szybki

Użyj funkcji log() lub log(format:, arguments:) aby wskazać problemy. Jeśli chcesz uzyskać przydatne wyniki dziennika z komunikatami, obiekt przekazywany do log() musi być zgodny z właściwością CustomStringConvertible . log() zwraca właściwość opisu zdefiniowaną dla obiektu. Na przykład:

Crashlytics.crashlytics().log("Higgs-Boson detected! Bailing out…, \(attributesDict)")

.log(format:, arguments:) formatuje wartości zwracane przez wywołanie funkcji getVaList() . Na przykład:

Crashlytics.crashlytics().log(format: "%@, %@", arguments: getVaList(["Higgs-Boson detected! Bailing out…", attributesDict]))

Aby uzyskać więcej informacji na temat używania funkcji log() lub log(format:, arguments:) , zapoznaj się z dokumentacją referencyjną Crashlytics .

Cel C

Użyj log lub logWithFormat , aby zidentyfikować problemy. Należy zauważyć, że jeśli chcesz uzyskać przydatne dane wyjściowe dziennika z komunikatami, obiekt przekazywany do dowolnej metody musi zastąpić właściwość instancji description . Na przykład:

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

Aby uzyskać więcej informacji na temat korzystania z log i logWithFormat , zapoznaj się z dokumentacją referencyjną Crashlytics.

Ustaw identyfikatory użytkowników

Aby zdiagnozować problem, często warto wiedzieć, który z użytkowników doświadczył danej awarii. Crashlytics umożliwia anonimową identyfikację użytkowników w raportach o awariach.

Aby dodać identyfikatory użytkowników do raportów, przypisz każdemu użytkownikowi unikalny identyfikator w postaci numeru identyfikacyjnego, tokena lub wartości zahaszowanej:

Szybki

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

Cel C

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

Jeśli kiedykolwiek będziesz musiał wyczyścić identyfikator użytkownika po jego ustawieniu, zresetuj wartość do pustego ciągu. Wyczyszczenie identyfikatora użytkownika nie powoduje usunięcia istniejących rekordów Crashlytics. Jeśli chcesz usunąć rekordy powiązane z identyfikatorem użytkownika, skontaktuj się z pomocą techniczną Firebase .

Zgłaszaj wyjątki niekrytyczne

Oprócz automatycznego zgłaszania awarii aplikacji Crashlytics umożliwia rejestrowanie wyjątków niekrytycznych i wysyłanie ich do Ciebie przy następnym uruchomieniu aplikacji.

Wyjątki niekrytyczne można rejestrować, rejestrując obiekty NSError za pomocą metody recordError . recordError przechwytuje stos wywołań wątku, wywołując [NSThread callStackReturnAddresses] .

Szybki

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

Cel C

[[FIRCrashlytics crashlytics] recordError:error];

Podczas korzystania z metody recordError ważne jest zrozumienie struktury NSError oraz sposobu, w jaki Crashlytics wykorzystuje dane do grupowania awarii. Nieprawidłowe użycie metody recordError może spowodować nieprzewidywalne zachowanie i spowodować, że Crashlytics ograniczy raportowanie zarejestrowanych błędów Twojej aplikacji.

Obiekt NSError ma trzy argumenty:

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

W przeciwieństwie do awarii krytycznych, które są grupowane na podstawie analizy śledzenia stosu, zarejestrowane błędy są grupowane według domain i code . Jest to ważne rozróżnienie między awariami śmiertelnymi a zarejestrowanymi błędami. Na przykład:

Szybki

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)

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

Gdy zarejestrujesz powyższy błąd, tworzy nowy problem, który jest pogrupowany według NSSomeErrorDomain i -1001 . Dodatkowe zarejestrowane błędy, które używają tej samej domeny i wartości kodu, są zgrupowane w ramach tego samego problemu. Dane zawarte w obiekcie userInfo są konwertowane na pary klucz-wartość i wyświetlane w sekcji klucze/logi w ramach pojedynczego zagadnienia.

Dzienniki i klucze niestandardowe

Podobnie jak raporty o awariach, możesz osadzać dzienniki i niestandardowe klucze, aby dodać kontekst do NSError . Istnieje jednak różnica między tym, jakie dzienniki są dołączane do awarii, a jakie są rejestrowane błędy. Gdy wystąpi awaria i ponowne uruchomienie aplikacji, Crashlytics pobiera z dysku dzienniki, które zostały zapisane aż do momentu awarii. Po zalogowaniu NSError aplikacja nie kończy się natychmiast. Ponieważ Crashlytics wysyła raport o zarejestrowanych błędach tylko przy następnym uruchomieniu aplikacji i musi ograniczać ilość miejsca przydzielonego na logi na dysku, po zarejestrowaniu NSError możliwe jest zarejestrowanie wystarczającej liczby logów, aby wszystkie odpowiednie logi zostały wyprzedzone do czasu wysłania przez Crashlytics raport z urządzenia. Pamiętaj o tej równowadze podczas rejestrowania NSErrors i korzystania z dzienników i kluczy niestandardowych w aplikacji.

Względy dotyczące wydajności

Należy pamiętać, że rejestrowanie NSError może być dość kosztowne. W momencie wywołania Crashlytics przechwytuje stos wywołań bieżącego wątku za pomocą procesu zwanego odwijaniem stosu. Ten proces może wymagać dużej mocy procesora i operacji we/wy, szczególnie w przypadku architektur obsługujących odwijanie DWARF (arm64 i x86). Po zakończeniu odwijania informacje są synchronicznie zapisywane na dysku. Zapobiega to utracie danych w przypadku awarii następnej linii.

Chociaż wywołanie tego interfejsu API w wątku w tle jest bezpieczne, pamiętaj, że wysłanie tego wywołania do innej kolejki powoduje utratę kontekstu bieżącego śladu stosu.

A co z NSExceptions?

Crashlytics nie oferuje możliwości bezpośredniego rejestrowania i rejestrowania wystąpień NSException . Ogólnie rzecz biorąc, interfejsy API Cocoa i Cocoa Touch nie są bezpieczne pod względem wyjątków. Oznacza to, że użycie @catch może mieć bardzo poważne niezamierzone skutki uboczne w twoim procesie, nawet jeśli jest używane z najwyższą ostrożnością. Nigdy nie powinieneś używać instrukcji @catch w swoim kodzie. Zapoznaj się z dokumentacją Apple na ten temat.

Dostosuj ślady stosu

Jeśli Twoja aplikacja działa w środowisku nienatywnym (takim jak C++ lub Unity), możesz użyć interfejsu API modelu wyjątków, aby zgłosić metadane awarii w natywnym formacie wyjątku aplikacji. Zgłoszone wyjątki są oznaczane jako niekrytyczne.

Szybki

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)

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

Niestandardowe ramki stosu można również zainicjować za pomocą samych adresów:

Szybki

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)

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

Włącz raportowanie zgody

Domyślnie Crashlytics automatycznie zbiera raporty o awariach dla wszystkich użytkowników Twojej aplikacji. Aby zapewnić użytkownikom większą kontrolę nad wysyłanymi przez nich danymi, możesz włączyć raportowanie zgody, wyłączając automatyczne raportowanie i wysyłając dane do Crashlytics tylko wtedy, gdy tak zdecydujesz w swoim kodzie:

  1. Wyłącz automatyczne zbieranie, dodając nowy klucz do pliku Info.plist :

    • Klucz: FirebaseCrashlyticsCollectionEnabled
    • Wartość: false
  2. Włącz zbieranie danych dla wybranych użytkowników, wywołując funkcję zastępowania zbierania danych Crashlytics w czasie wykonywania. Wartość zastąpienia pozostaje niezmieniona po uruchomieniu Twojej aplikacji, dzięki czemu Crashlytics może automatycznie zbierać raporty.

    Aby zrezygnować z automatycznego zgłaszania awarii, podaj false jako wartość zastępującą. Gdy jest ustawiona na false , nowa wartość nie ma zastosowania do następnego uruchomienia aplikacji.

    Szybki

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Cel C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

Zarządzaj danymi Crash Insights

Crash Insights pomaga rozwiązywać problemy, porównując anonimowe ślady stosu ze śladami z innych aplikacji Firebase i informując, czy problem jest częścią większego trendu. W przypadku wielu problemów usługa Crash Insights zapewnia nawet zasoby ułatwiające debugowanie awarii.

Crash Insights wykorzystuje zagregowane dane o awariach do identyfikowania typowych trendów stabilności. Jeśli nie chcesz udostępniać danych swojej aplikacji, możesz zrezygnować z Crash Insights w menu Crash Insights u góry listy problemów Crashlytics w konsoli Firebase .