Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. 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 Firebase Crashlytics SDK. Domyślnie Crashlytics automatycznie zbiera raporty o awariach dla wszystkich użytkowników Twojej aplikacji (możesz zamiast tego wyłączyć automatyczne raportowanie o awariach i włączyć raportowanie dla swoich użytkowników). Crashlytics udostępnia od razu cztery mechanizmy rejestrowania: klucze niestandardowe , dzienniki niestandardowe , identyfikatory użytkowników i przechwycone wyjątki .

Dodaj niestandardowe klucze

Klucze niestandardowe pomagają uzyskać konkretny stan aplikacji, który może doprowadzić do awarii. Z raportami o awariach możesz powiązać dowolne pary klucz/wartość, a następnie użyć kluczy niestandardowych do wyszukiwania i filtrowania raportów o awariach w konsoli Firebase.

  • W panelu Crashlytics możesz wyszukiwać problemy pasujące do niestandardowego klucza.
  • Przeglądając konkretny problem w konsoli, możesz wyświetlić powiązane klucze niestandardowe dla każdego zdarzenia ( podkarta 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ść jako @( 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 również 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"];

Dodaj zbiorczo 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 uzyskać więcej kontekstu dla zdarzeń prowadzących do awarii, możesz dodać do swojej aplikacji niestandardowe dzienniki Crashlytics. Crashlytics kojarzy dzienniki z danymi o awariach i wyświetla je na stronie Crashlytics w konsoli Firebase na karcie Dzienniki .

Szybki

Użyj log() lub log(format:, arguments:) , aby pomóc w ustaleniu problemów. Jeśli chcesz uzyskać przydatne dane wyjściowe dziennika z komunikatami, obiekt, który przekazujesz 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 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 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 w dzienniku z komunikatami, obiekt przekazywany do dowolnej metody musi przesłonić 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];

Więcej informacji na temat używania log i logWithFormat można znaleźć w dokumentacji referencyjnej Crashlytics.

Ustaw identyfikatory użytkowników

Aby zdiagnozować problem, często warto wiedzieć, u którego z użytkowników wystąpiła dana awaria. Crashlytics umożliwia anonimowe identyfikowanie 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 ID, tokena lub wartości zaszyfrowanej:

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. Usunięcie 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łoś niekrytyczne wyjątki

Oprócz automatycznego zgłaszania awarii aplikacji Crashlytics umożliwia rejestrowanie niekrytycznych wyjątków 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];

Korzystając z metody recordError , ważne jest zrozumienie struktury NSError i sposobu, w jaki Crashlytics wykorzystuje dane do grupowania awarii. Nieprawidłowe użycie metody recordError może powodować nieprzewidywalne zachowanie i może spowodować, że Crashlytics ograniczy zgłaszanie zarejestrowanych błędów aplikacji.

Obiekt NSError ma trzy argumenty:

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

W przeciwieństwie do awarii krytycznych, które są grupowane za pomocą analizy śledzenia stosu, zarejestrowane błędy są grupowane według domain i code . Jest to ważne rozróżnienie między krytycznymi awariami 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, zostanie utworzony nowy problem pogrupowany według NSSomeErrorDomain i -1001 . Dodatkowe zarejestrowane błędy, które używają tej samej domeny i wartości kodu, są pogrupowane w ramach tego samego problemu. Dane zawarte w obiekcie userInfo są konwertowane na pary klucz-wartość i wyświetlane w sekcji klucze/dzienniki w ramach pojedynczego wydania.

Dzienniki i niestandardowe klucze

Podobnie jak raporty o awariach, możesz osadzać dzienniki i niestandardowe klucze, aby dodać kontekst do NSError . Istnieje jednak różnica w tym, jakie dzienniki są dołączane do awarii, a jakie są rejestrowane błędy. Gdy nastąpi awaria i aplikacja zostanie ponownie uruchomiona, dzienniki pobierane przez Crashlytics z dysku to te, które zostały zapisane do momentu awarii. Gdy rejestrujesz NSError , aplikacja nie kończy się natychmiast. Ponieważ Crashlytics wysyła raport o zarejestrowanych błędach tylko przy następnym uruchomieniu aplikacji i musi ograniczyć ilość miejsca przydzielonego dla dzienników na dysku, możliwe jest rejestrowanie wystarczającej ilości dzienników po zarejestrowaniu NSError , aby wszystkie odpowiednie dzienniki były rotowane do czasu wysłania przez Crashlytics raport z urządzenia. Pamiętaj o tej równowadze podczas rejestrowania NSErrors oraz używania dzienników i kluczy niestandardowych w swojej aplikacji.

Rozważania dotyczące wydajności

Należy pamiętać, że rejestrowanie NSError może być dość kosztowne. W momencie nawiązania połączenia Crashlytics przechwytuje stos wywołań bieżącego wątku za pomocą procesu zwanego rozwijaniem stosu. Proces ten może intensywnie obciążać procesor i operacje we/wy, szczególnie w przypadku architektur obsługujących rozwijanie DWARF (arm64 i x86). Po zakończeniu rozwijania informacje są zapisywane na dysku synchronicznie. Zapobiega to utracie danych w przypadku awarii następnej linii.

Chociaż można bezpiecznie wywołać ten interfejs API w wątku w tle, należy pamiętać, że wysłanie tego wywołania do innej kolejki powoduje utratę kontekstu bieżącego śladu stosu.

A co z NSExceptions?

Crashlytics nie oferuje funkcji bezpośredniego rejestrowania i rejestrowania wystąpień NSException . Ogólnie rzecz biorąc, interfejsy API Cocoa i Cocoa Touch nie są bezpieczne. 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 wyjątkową 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 innym niż natywne (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, wyłączając automatyczne raportowanie i wysyłając dane do Crashlytics tylko wtedy, gdy zdecydujesz się w 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 w czasie wykonywania funkcję zastępowania gromadzenia danych Crashlytics. Wartość zastąpienia utrzymuje się podczas uruchamiania aplikacji, dzięki czemu Crashlytics może automatycznie zbierać raporty.

    Aby zrezygnować z automatycznego raportowania o awariach, podaj wartość false jako wartość zastąpienia. Po ustawieniu 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 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 aplikacji, możesz zrezygnować z Crash Insights w menu Crash Insights u góry listy problemów z Crashlytics w konsoli Firebase .