Dostosowywanie raportów o awariach na platformach Apple

Wybierz platformę: iOS+ Android Flutter Unity


Możesz kliknąć problem i uzyskać szczegółowy raport o zdarzeniu na panelu DevOps i zaangażowanie > Crashlytics w Firebase konsoli. Możesz dostosować te raporty, aby lepiej zrozumieć, co dzieje się w Twojej aplikacji, oraz okoliczności zdarzeń zgłaszanych do Crashlytics.

Dodawanie kluczy niestandardowych

Klucze niestandardowe pomagają uzyskać informacje o konkretnym stanie aplikacji, który doprowadził do awarii. Możesz powiązać dowolne pary klucz-wartość z raportami o awariach, a następnie użyć kluczy niestandardowych do wyszukiwania i filtrowania raportów o awariach na panelu DevOps i zaangażowanie > Crashlytics w Firebase konsoli.

  • Możesz wyszukiwać problemy pasujące do klucza niestandardowego.

  • Gdy przeglądasz konkretny problem w konsoli, możesz wyświetlić powiązane z nim klucze niestandardowe dla każdego zdarzenia (podkarta Klucze) oraz filtrować zdarzenia według kluczy niestandardowych (menu Filtr u góry strony).

Do ustawiania par klucz-wartość używaj metody setCustomValue. Przykład:

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

Podczas ustawiania liczb całkowitych, wartości logicznych lub liczb zmiennoprzecinkowych umieść wartość w polu @(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 też zmodyfikować wartość istniejącego klucza, wywołując klucz i ustawiając go na inną wartość. Przykład:

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

Aby dodać pary klucz-wartość zbiorczo, użyj metody setCustomKeysAndValues z NSDictionary jako jedynym parametrem:

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

Dodawanie niestandardowych wiadomości z dziennika

Aby uzyskać więcej kontekstu dotyczącego zdarzeń prowadzących do awarii, możesz dodać niestandardowe dzienniki Crashlytics do aplikacji. Crashlytics powiąże dzienniki z danymi o awariach i wyświetli je na karcie Dzienniki po wyświetleniu szczegółów problemu (wszystkie problemy znajdziesz na panelu DevOps i zaangażowanie > Crashlytics w konsoli Firebase).

Swift

Aby pomóc w identyfikowaniu problemów, użyj funkcji log() lub log(format:, arguments:). Jeśli chcesz uzyskać przydatne dane wyjściowe dziennika z wiadomościami, obiekt przekazywany do log() musi być zgodny z CustomStringConvertible właściwością. log() zwraca właściwość opisu zdefiniowaną dla obiektu. Przykład:

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

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

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

Więcej informacji o tym, jak używać funkcji log() lub log(format:, arguments:), znajdziesz w Crashlytics dokumentacji referencyjnej.

Objective-C

Aby pomóc w identyfikowaniu problemów, użyj funkcji log lub logWithFormat. Pamiętaj, że jeśli chcesz uzyskać przydatne dane wyjściowe dziennika z wiadomościami, obiekt przekazywany do dowolnej z tych metod musi zastępować właściwość instancji description. 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 o tym, jak używać funkcji log i logWithFormat, znajdziesz w Crashlytics dokumentacji referencyjnej.

Ustawianie identyfikatorów użytkowników

Aby zdiagnozować problem, często przydatne jest sprawdzenie, który z użytkowników doświadczył danej awarii. Crashlytics zawiera sposób na 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 identyfikacyjnego, tokena lub zaszyfrowanej wartości:

Swift

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

Objective-C

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

Jeśli po ustawieniu identyfikatora użytkownika musisz go wyczyścić, zresetuj wartość do pustego ciągu znaków. Wyczyszczenie identyfikatora użytkownika nie powoduje usunięcia istniejących Crashlytics rekordów. Jeśli musisz usunąć rekordy powiązane z identyfikatorem użytkownika, skontaktuj się z zespołem pomocy Firebase.

Zgłaszanie wyjątków niekrytycznych

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żesz rejestrować, rejestrując obiekty NSError za pomocą metody recordError. recordError przechwytuje stos wywołań wątku, wywołując [NSThread callStackReturnAddresses].

Swift

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

Objective-C

[[FIRCrashlytics crashlytics] recordError:error];

Podczas korzystania z metody recordError ważne jest, aby zrozumieć strukturę NSError i sposób, w jaki Crashlytics używa danych do grupowania awarii. Nieprawidłowe użycie metody recordError może powodować nieprzewidywalne zachowanie i może spowodować, że Crashlytics ograniczy raportowanie zarejestrowanych błędów w aplikacji.

Obiekt NSError ma 3 argumenty:

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

W przeciwieństwie do awarii krytycznych, które są grupowane na podstawie analizy zrzutu stosu, zarejestrowane błędy są grupowane według domain i code. Jest to ważna różnica między awariami krytycznymi a zarejestrowanymi błędami. Przykład:

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

Gdy zarejestrujesz powyższy błąd, utworzy się nowy problem, który zostanie pogrupowany według NSSomeErrorDomain i -1001. Dodatkowe zarejestrowane błędy, które używają tych samych wartości domeny i kodu, są grupowane w ramach tego samego problemu. Dane zawarte w obiekcie userInfo są konwertowane na pary klucz-wartość i wyświetlane w sekcji kluczy/dzienników w ramach poszczególnych problemów.

.

Dzienniki i klucze niestandardowe

Podobnie jak w przypadku raportów o awariach, możesz osadzać dzienniki i klucze niestandardowe, aby dodać kontekst do NSError. Istnieje jednak różnica w tym, jakie dzienniki są dołączane do awarii, a jakie do zarejestrowanych błędów. Gdy wystąpi awaria i aplikacja zostanie ponownie uruchomiona, dzienniki Crashlytics pobiera z dysku, to te, które zostały zapisane do momentu awarii. Gdy zarejestrujesz NSError, aplikacja nie zostanie natychmiast zamknięta. Ponieważ Crashlytics wysyła raport o zarejestrowanym błędzie dopiero przy następnym uruchomieniu aplikacji i musi ograniczyć ilość miejsca na dysku przeznaczonego na dzienniki, możliwe jest zarejestrowanie wystarczającej ilości danych po zarejestrowaniu NSError aby wszystkie odpowiednie dzienniki zostały usunięte, zanim Crashlytics wyśle raport z urządzenia. Pamiętaj o tym, rejestrując NSErrors oraz używając dzienników i kluczy niestandardowych w aplikacji.

Możliwe spowolnienie działania witryny

Pamiętaj, że rejestrowanie NSError może być dość kosztowne. W momencie wywołania CrashlyticsCrashlytics przechwytuje stos wywołań bieżącego wątku za pomocą procesu zwanego rozwijaniem stosu. Proces ten może być intensywny pod względem wykorzystania procesora i operacji wejścia/wyjścia, 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 w następnym wierszu.

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

A co z NSExceptions?

Crashlytics nie oferuje możliwości bezpośredniego rejestrowania i zapisywania instancji NSException. Ogólnie rzecz biorąc, interfejsy API Cocoa i Cocoa Touch nie są bezpieczne w przypadku wyjątków. Oznacza to, że użycie @catch może mieć bardzo poważne niezamierzone skutki uboczne w Twoim procesie, nawet jeśli używasz go z dużą ostrożnością. W kodzie nigdy nie należy używać instrukcji @catch. Więcej informacji na ten temat znajdziesz w dokumentacji Apple.

Dostosowywanie stosów wywołań

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

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

Niestandardowe ramki stosu można też inicjować tylko za pomocą adresów:

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

Pobieranie dzienników ścieżki

Dzienniki ścieżki pozwalają lepiej zrozumieć interakcje użytkownika z aplikacją, które doprowadziły do awarii, wyjątku niekrytycznego lub zdarzenia ANR. Te dzienniki mogą być przydatne podczas próby odtworzenia i debugowania problemu.

Dzienniki ścieżki są obsługiwane przez Google Analytics, więc aby je uzyskać, musisz włączyć Google Analytics w projekcie Firebase i dodać do aplikacji pakiet SDK Firebase dla Google Analytics. Gdy te wymagania zostaną spełnione, dzienniki ścieżki będą automatycznie dołączane do danych zdarzenia na karcie Dzienniki po wyświetleniu szczegółów problemu (wszystkie problemy znajdziesz na panelu DevOps i zaangażowanie > Crashlytics w konsoli Firebase).

Pakiet Analytics SDK automatycznie rejestruje zdarzenie screen_view które umożliwia wyświetlanie w dziennikach ścieżki listy ekranów wyświetlanych przed awarią, wyjątkiem niekrytycznym lub zdarzeniem ANR. Dziennik ścieżki screen_view zawiera parametr firebase_screen_class.

Dzienniki ścieżki są też wypełniane wszystkimi zdarzeniami niestandardowymi, które ręcznie rejestrujesz w sesji użytkownika , w tym danymi parametrów zdarzenia. Te dane mogą pomóc w pokazaniu serii działań użytkownika, które doprowadziły do awarii, wyjątku niekrytycznego lub zdarzenia ANR.

Pamiętaj, że możesz kontrolować zbieranie i wykorzystywanie danychGoogle Analytics, w tym danych, które wypełniają dzienniki ścieżki.

Włączanie zgłaszania za zgodą użytkownika

Domyślnie Crashlytics automatycznie zbiera raporty o awariach wszystkich użytkowników Twojej aplikacji. Aby zapewnić użytkownikom większą kontrolę nad wysyłanymi przez nich danymi, możesz włączyć zgłaszanie za zgodą użytkownika, wyłączając automatyczne zgłaszanie i wysyłając dane do Crashlytics tylko wtedy, gdy zdecydujesz się na to 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 działania aplikacji Crashlytics zastąpienie zbierania danych przez Crashlytics. Wartość zastąpienia jest zachowywana we wszystkich kolejnych uruchomieniach aplikacji, dzięki czemu Crashlytics może automatycznie zbierać raporty dla tego użytkownika.

    Swift

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Objective-C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

    Jeśli użytkownik później zrezygnuje ze zbierania danych, możesz przekazać wartość false jako wartość zastąpienia. Zostanie ona zastosowana przy następnym uruchomieniu aplikacji przez użytkownika i będzie zachowywana we wszystkich kolejnych uruchomieniach.

Zarządzanie danymi statystyk awarii

Statystyki awarii pomagają rozwiązywać problemy, porównując zanonimizowane stosy wywołań z innymi aplikacjami Firebase i informując, czy Twój problem jest częścią większego trendu. W przypadku wielu problemów statystyki awarii udostępniają też zasoby, które pomagają w debugowaniu awarii.

Statystyki awarii używają zagregowanych danych o awariach do identyfikowania typowych trendów stabilności. Jeśli nie chcesz udostępniać danych aplikacji, możesz zrezygnować ze statystyk awarii w menu Statystyki awarii u góry listy problemów na panelu DevOps i zaangażowanie > Crashlytics dashboard w Firebase konsoli.

Dalsze kroki