Personaliza tus informes de fallos de Firebase Crashlytics

En el panel de Crashlytics, puede hacer clic en un problema y obtener un informe detallado del evento. Puede personalizar esos informes para ayudarle a comprender mejor lo que sucede en su aplicación y las circunstancias en torno a los eventos informados a Crashlytics.

  • Obtenga automáticamente registros de ruta de navegación si su aplicación utiliza el SDK de Firebase para Google Analytics. Estos registros le brindan visibilidad de las acciones del usuario que conducen a un evento recopilado por Crashlytics en su aplicación.

  • Desactive los informes automáticos de fallos y habilite los informes de suscripción voluntaria para sus usuarios. Tenga en cuenta que, de forma predeterminada, Crashlytics recopila automáticamente informes de fallos para todos los usuarios de su aplicación.

Agregar claves personalizadas

Las claves personalizadas lo ayudan a obtener el estado específico de su aplicación antes de fallar. Puede asociar pares clave/valor arbitrarios con sus informes de fallos y luego usar las claves personalizadas para buscar y filtrar informes de fallos en Firebase console.

  • En el panel de Crashlytics , puede buscar problemas que coincidan con una clave personalizada.
  • Cuando revisa un problema específico en la consola, puede ver las claves personalizadas asociadas para cada evento (subpestaña Claves ) e incluso filtrar los eventos por claves personalizadas (menú Filtro en la parte superior de la página).

Utilice el método setCustomValue para establecer pares clave/valor. Por ejemplo:

Rápido

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

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

C objetivo

Al configurar números enteros, booleanos o flotantes, encuadre el valor como @( 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"];

También puede modificar el valor de una clave existente llamando a la clave y configurándola en un valor diferente. Por ejemplo:

Rápido

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

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

C objetivo

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

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

Agregue pares clave/valor de forma masiva utilizando el método setCustomKeysAndValues ​​con un NSDictionary como único parámetro:

Rápido

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)

C objetivo

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

Agregar mensajes de registro personalizados

Para tener más contexto sobre los eventos que conducen a un bloqueo, puede agregar registros personalizados de Crashlytics a su aplicación. Crashlytics asocia los registros con sus datos de fallas y los muestra en la página Crashlytics de Firebase console , en la pestaña Registros .

Rápido

Utilice log() o log(format:, arguments:) para ayudar a identificar problemas. Si desea obtener una salida de registro útil con mensajes, el objeto que pase a log() debe ajustarse a la propiedad CustomStringConvertible . log() devuelve la propiedad de descripción que define para el objeto. Por ejemplo:

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

.log(format:, arguments:) formatea los valores devueltos al llamar getVaList() . Por ejemplo:

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

Para obtener más detalles sobre cómo usar log() o log(format:, arguments:) , consulte la documentación de referencia de Crashlytics.

C objetivo

Utilice log o logWithFormat para ayudar a identificar problemas. Tenga en cuenta que si desea obtener una salida de registro útil con mensajes, el objeto que pase a cualquiera de los métodos debe anular la propiedad de instancia description . Por ejemplo:

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

Para obtener más detalles sobre cómo utilizar log y logWithFormat , consulte la documentación de referencia de Crashlytics.

Establecer identificadores de usuario

Para diagnosticar un problema, suele ser útil saber cuál de sus usuarios experimentó un bloqueo determinado. Crashlytics incluye una forma de identificar usuarios de forma anónima en sus informes de fallos.

Para agregar ID de usuario a sus informes, asigne a cada usuario un identificador único en forma de número de ID, token o valor hash:

Rápido

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

C objetivo

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

Si alguna vez necesita borrar un identificador de usuario después de configurarlo, restablezca el valor a una cadena en blanco. Borrar un identificador de usuario no elimina los registros de Crashlytics existentes. Si necesita eliminar registros asociados con una ID de usuario, comuníquese con el soporte de Firebase .

Informar excepciones no fatales

Además de informar automáticamente los fallos de tu aplicación, Crashlytics te permite registrar excepciones no fatales y te las envía la próxima vez que se inicie tu aplicación.

Puede registrar excepciones no fatales registrando objetos NSError con el método recordError . recordError captura la pila de llamadas del hilo llamando a [NSThread callStackReturnAddresses] .

Rápido

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

C objetivo

[[FIRCrashlytics crashlytics] recordError:error];

Cuando se utiliza el método recordError , es importante comprender la estructura NSError y cómo Crashlytics usa los datos para agrupar fallas. El uso incorrecto del método recordError puede causar un comportamiento impredecible y puede hacer que Crashlytics limite los informes de errores registrados para su aplicación.

Un objeto NSError tiene tres argumentos:

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

A diferencia de los fallos fatales, que se agrupan mediante análisis de seguimiento de pila, los errores registrados se agrupan por domain y code . Ésta es una distinción importante entre accidentes fatales y errores registrados. Por ejemplo:

Rápido

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)

C objetivo

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

Cuando registra el error anterior, se crea un nuevo problema agrupado por NSSomeErrorDomain y -1001 . Los errores registrados adicionales que utilizan el mismo dominio y valores de código se agrupan bajo el mismo problema. Los datos contenidos en el objeto userInfo se convierten en pares clave-valor y se muestran en la sección de claves/registros dentro de un problema individual.

Registros y claves personalizadas

Al igual que los informes de fallos, puede incrustar registros y claves personalizadas para agregar contexto al NSError . Sin embargo, existe una diferencia entre los registros que se adjuntan a los fallos y los errores registrados. Cuando se produce un bloqueo y se reinicia la aplicación, los registros que Crashlytics recupera del disco son aquellos que se escribieron justo en el momento del bloqueo. Cuando registra un NSError , la aplicación no finaliza inmediatamente. Debido a que Crashlytics solo envía el informe de errores registrados en el siguiente inicio de la aplicación y debe limitar la cantidad de espacio asignado para los registros en el disco, es posible registrar suficiente después de registrar un NSError para que todos los registros relevantes se eliminen cuando Crashlytics envíe el informe del dispositivo. Tenga en cuenta este equilibrio al registrar NSErrors y utilizar registros y claves personalizadas en su aplicación.

Consideraciones de rendimiento

Tenga en cuenta que registrar un NSError puede resultar bastante caro. En el momento de realizar la llamada, Crashlytics captura la pila de llamadas del hilo actual mediante un proceso llamado desenrollado de pila. Este proceso puede requerir un uso intensivo de CPU y E/S, particularmente en arquitecturas que admiten el desenrollado DWARF (arm64 y x86). Una vez completada la desenredación, la información se escribe en el disco de forma sincrónica. Esto evita la pérdida de datos si la siguiente línea fallara.

Si bien es seguro llamar a esta API en un subproceso en segundo plano, recuerde que al enviar esta llamada a otra cola se pierde el contexto del seguimiento de la pila actual.

¿Qué pasa con las NSExceptions?

Crashlytics no ofrece una función para registrar y registrar instancias NSException directamente. En términos generales, las API Cocoa y Cocoa Touch no son seguras para excepciones. Eso significa que el uso de @catch puede tener efectos secundarios no deseados muy graves en su proceso, incluso cuando se usa con extremo cuidado. Nunca debes usar declaraciones @catch en tu código. Consulte la documentación de Apple sobre el tema.

Personalizar seguimientos de pila

Si su aplicación se ejecuta en un entorno no nativo (como C++ o Unity), puede usar la API del modelo de excepción para informar los metadatos de fallas en el formato de excepción nativo de su aplicación. Las excepciones reportadas están marcadas como no fatales.

Rápido

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)

C objetivo

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

Los marcos de pila personalizados también se pueden inicializar solo con direcciones:

Rápido

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)

C objetivo

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

Obtener registros de ruta de navegación

Los registros de ruta de navegación le brindan una mejor comprensión de las interacciones que tuvo un usuario con su aplicación antes de un evento de falla, no fatal o ANR. Estos registros pueden resultar útiles al intentar reproducir y depurar un problema.

Los registros de ruta de navegación funcionan con Google Analytics, por lo que para obtener registros de ruta de navegación, debe habilitar Google Analytics para su proyecto de Firebase y agregar el SDK de Firebase para Google Analytics a su aplicación. Una vez que se cumplen estos requisitos, los registros de ruta de navegación se incluyen automáticamente con los datos de un evento dentro de la pestaña Registros cuando ve los detalles de un problema.

El SDK de Analytics registra automáticamente el evento screen_view , lo que permite que los registros de ruta de navegación muestren una lista de las pantallas vistas antes del evento de falla, no fatal o ANR. Un registro de ruta de navegación screen_view contiene un parámetro firebase_screen_class .

Los registros de ruta de navegación también se completan con cualquier evento personalizado que registre manualmente dentro de la sesión del usuario, incluidos los datos de los parámetros del evento. Estos datos pueden ayudar a mostrar una serie de acciones del usuario que conducen a un evento de falla, no fatal o ANR.

Tenga en cuenta que puede controlar la recopilación y el uso de los datos de Google Analytics , que incluyen los datos que completan los registros de ruta de navegación.

Habilitar informes de suscripción voluntaria

De forma predeterminada, Crashlytics recopila automáticamente informes de fallos para todos los usuarios de su aplicación. Para brindarles a los usuarios más control sobre los datos que envían, puede habilitar los informes de suscripción deshabilitando los informes automáticos y solo enviando datos a Crashlytics cuando así lo elija en su código:

  1. Desactive la recopilación automática agregando una nueva clave a su archivo Info.plist :

    • Clave: FirebaseCrashlyticsCollectionEnabled
    • Valor: false
  2. Habilite la recopilación para usuarios seleccionados llamando a la anulación de la recopilación de datos de Crashlytics en tiempo de ejecución. El valor de anulación persiste durante los lanzamientos de su aplicación para que Crashlytics pueda recopilar informes automáticamente.

    Para optar por no recibir informes automáticos de fallos, pase false como valor de anulación. Cuando se establece en false , el nuevo valor no se aplica hasta la siguiente ejecución de la aplicación.

    Rápido

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    C objetivo

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

Administrar datos de Crash Insights

Crash Insights te ayuda a resolver problemas al comparar tus seguimientos de pila anónimos con los de otras aplicaciones de Firebase y te permite saber si tu problema es parte de una tendencia más amplia. Para muchos problemas, Crash Insights incluso proporciona recursos para ayudarle a depurar el fallo.

Crash Insights utiliza datos agregados sobre accidentes para identificar tendencias de estabilidad comunes. Si prefieres no compartir los datos de tu aplicación, puedes optar por no participar en Crash Insights desde el menú Crash Insights en la parte superior de tu lista de problemas de Crashlytics en Firebase console .