Personaliza los informes de fallas de Firebase Crashlytics

ios
android
unity [Beta]

Firebase Crashlytics puede funcionar con una configuración mínima de tu parte. Apenas agregas el SDK, Crashlytics comienza a enviar informes de fallas a Firebase console.

Para entregarte más estadísticas sobre los informes de fallas, Firebase Crashlytics ofrece cuatro mecanismos de registro desde el primer momento: claves personalizadas, registros personalizados, identificadores de usuarios y excepciones capturadas.

Agrega claves personalizadas

Las claves personalizadas te ayudan a obtener el estado específico de la app hasta el momento de la falla. Puedes asociar pares clave-valor arbitrarios con tus informes de fallas y verlos en Firebase console.

ios

Comienza con [CrashlyticsKit setObjectValue:forKey:] o uno de los métodos relacionados:

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

En algunos casos, debes cambiar el valor de clave existente. Llama a la misma clave, pero reemplazar el valor. Por ejemplo:

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

Existen cinco métodos para configurar claves. Cada uno controla un tipo de datos diferente:

Java
Android

Crashlytics.setString(key, "foo" /* string value */);

Crashlytics.setBool(key, true /* boolean value */);

Crashlytics.setDouble(key, 1.0 /* double value */);

Crashlytics.setFloat(key, 1.0f /* float value */);

Crashlytics.setInt(key, 1 /* int value */);

Kotlin
Android

Crashlytics.setString(key, "foo" /* string value */)

Crashlytics.setBool(key, true /* boolean value */)

Crashlytics.setDouble(key, 1.0 /* double value */)

Crashlytics.setFloat(key, 1.0f /* float value */)

Crashlytics.setInt(key, 1 /* int value */)

Si vuelves a configurar una clave, se actualiza su valor. Por ejemplo:

Java
Android

Crashlytics.setInt("current_level", 3);
Crashlytics.setString("last_UI_action", "logged_in");

Kotlin
Android

Crashlytics.setInt("current_level", 3)
Crashlytics.setString("last_UI_action", "logged_in")
unity [Beta]

Cuando estos métodos se llaman muchas veces, los valores nuevos de las claves existentes actualizarán el valor actual. Por lo tanto, solo se capturará el valor más reciente cuando se registre una falla.

Crashlytics.SetCustomKey(string key, string value);

Agrega mensajes de registro personalizados

Para obtener más contexto sobre los eventos anteriores a una falla, puedes agregar registros de Crashlytics personalizados a tu app. Crashlytics asocia los registros con tus datos de fallas y los hace visibles en Firebase console.

ios
Objective-C

En Objective-C, usa CLS_LOG para detectar problemas. Automáticamente, incluye información sobre la clase de Objective-C, el método y el número de línea asociado con el registro.

El comportamiento de CLS_LOG cambia si el registro es de una compilación de depuración o de actualización:

  • Compilaciones de depuración: CLS_LOG pasa por NSLog para que puedas ver el resultado en Xcode y en el dispositivo o simulador.
  • Compilaciones de actualización: Para mejorar el rendimiento, CLS_LOG silencia todos los demás resultados y no pasa por NSLog.

Usa CLS_LOG(format, ...) para registrar con CLS_LOG. Por ejemplo:

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

Examina el archivo de encabezado Crashlytics/Crashlytics.h para ver más detalles sobre cómo usar CLS_LOG.

Swift

En Swift, usa CLSLogv o CLSNSLogv para detectar problemas.

Hay dos elementos que debes considerar cuando generes registros con CLSLogv y CLSNSLogv:

  • Tu argumento de formato debe ser una string constante de tiempo de compilación. El compilador aplica esto en Objective-C, pero actualmente esa protección no se encuentra disponible en la transición a Swift.
  • Almacena los valores del registro en un arreglo y llama a getVaList en ese arreglo para recuperarlos.

Por ejemplo:

func write(string: String) {
    CLSLogv("%@", getVaList([string]))
}
La interpolación de strings de Swift no dará como resultado una string constante de tiempo de compilación. De la misma manera que con printf y NSLog, usar una string no constante con CLSLog puede causar un bloqueo.

Avanzado

Para obtener más control, puedes aprovechar CLSLog(format, ...) y CLSNSLog(format, ...) directamente. Este último pasa por NSLog y te permite ver el resultado en Xcode o en el dispositivo o simulador. CLSLog(format, ...) y CLSNSLog(format, ...) tienen seguridad en los subprocesos. CLSLog está diseñado a fin de registrar información importante para solucionar bloqueos. No se debe usar para seguir eventos en la app.

android

En Android, usa Crashlytics.log para detectar problemas.

Crashlytics.log puede escribir registros en un informe de fallas y con Log.println(), o solo en el próximo informe de fallas, de la siguiente manera:

  • Informe de fallas y Log.println:

    Java
    Android

    Crashlytics.log(Log.DEBUG, "tag", "message");

    Kotlin
    Android

    Crashlytics.log(Log.DEBUG, "tag", "message")
  • Solo informe de fallas:

    Java
    Android

    Crashlytics.log("message");

    Kotlin
    Android

    Crashlytics.log("message")
unity [Beta]

Los mensajes registrados se asocian con tus datos de fallas y están visibles en el panel de Firebase Crashlytics cuando visualizas una falla específica.

Crashlytics.Log(string message);

Configura identificadores de usuarios

Para diagnosticar un problema, resulta útil saber cuáles de tus usuarios sufrieron una falla. Crashlytics incluye una manera de identificar usuarios de forma anónima en tus informes de fallas.

ios

Para agregar los ID de usuario a tus informes, asigna a cada usuario un identificador único con el formato de un número de ID, un token o un valor con hash.

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

Si en algún momento necesitas borrar un identificador de usuario después de configurarlo, restablece el valor a una string en blanco. Borrar un identificador de usuario no quita los registros de Crashlytics existentes. Si necesitas borrar los registros asociados con un ID de usuario, comunícate con el equipo de Asistencia de Firebase.

android

Para agregar los ID de usuario a tus informes, asigna a cada usuario un identificador único con el formato de un número de ID, un token o un valor con hash.

Java
Android

Crashlytics.setUserIdentifier("user123456789");

Kotlin
Android

Crashlytics.setUserIdentifier("user123456789")

Si en algún momento necesitas borrar un identificador de usuario después de configurarlo, restablece el valor a una string en blanco. Borrar un identificador de usuario no quita los registros de Crashlytics existentes. Si necesitas borrar los registros asociados con un ID de usuario, comunícate con el equipo de Asistencia de Firebase.

unity [Beta]

Puedes usar un número de ID, un token o un valor con hash para identificar únicamente al usuario final de tu aplicación, sin necesidad de divulgar o transmitir su información personal. Además, puedes quitar el valor si lo configuras como una string en blanco. Este valor se muestra en el panel de Firebase Crashlytics cuando visualizas una falla específica.

Crashlytics.SetUserId(string identifier);

Registra excepciones no fatales

Además de informar las fallas de tu app automáticamente, Crashlytics te permite registrar excepciones no fatales.

ios

Para hacer esto en iOS, debes registrar objetos NSError, que Crashlytics informa y agrupa de la misma manera que los bloqueos:

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

Cuando usas el método recordError, es importante comprender la estructura de NSError y la manera en que Crashlytics usa los datos para agrupar los bloqueos. El uso incorrecto del método recordError puede causar un comportamiento impredecible y es posible que Crashlytics deba limitar la creación de informes de errores registrados en tu app.

Un objeto NSError tiene tres argumentos: domain: String, code: Int y userInfo: [AnyHashable : Any]? = nil

A diferencia de los bloqueos fatales, que se agrupan mediante el análisis de seguimiento de pila, los errores registrados se agrupan por domain y code de NSError. Esta es una distinción importante entre los bloqueos fatales y los errores registrados. Por ejemplo, registrar un error como el siguiente:

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

Crea un problema nuevo y se agrupa por NSSomeErrorDomain y -1001. Los errores registrados adicionales que tengan los mismos valores de dominio y código se agruparán bajo este problema.

Evita usar valores únicos, como ID de usuario, ID de producto y marcas de tiempo en los campos de dominio y código. Si usas valores únicos en estos campos, generas una cardinalidad de problemas alta y es posible que Crashlytics deba limitar el informe de errores registrados en tu app. En su lugar, los valores únicos se deben agregar al objeto de diccionario userInfo.

Los datos incluidos en el objeto userInfo se convierten en pares clave-valor y se muestran en la sección claves/registros dentro de un problema individual.

Crashlytics solo almacena las ocho excepciones más recientes en la sesión de una app determinada. Si tu app arroja más de 8 excepciones en una sesión, las excepciones más antiguas se perderán.

Registros y claves personalizadas

Al igual que los informes de fallos, puedes incorporar registros y claves personalizadas para agregar contexto a NSError. Sin embargo, existe una diferencia en los registros que se adjuntan a los bloqueos en comparación con los errores registrados. Cuando ocurre un bloqueo y la app se reinicia, los registros que Crashlytics recupera del disco son aquellos que se escribieron hasta el momento en que se produjo el bloqueo. Cuando registras un NSError, la app no se finaliza de inmediato. Dado que Crashlytics solo envía el informe del error registrado en el siguiente inicio de la app, y dado que Crashlytics debe limitar la cantidad de espacio asignada a los registros en el disco, es posible registrar lo suficiente antes de que un NSError se registre, de forma que todos los registros importantes rotan antes de que Crashlytics envíe el informe desde el dispositivo. Ten en cuenta este equilibrio cuando registres NSErrors y uses CLSLog y claves personalizadas en tu app.

Consideraciones de rendimiento

Ten en cuenta que registrar un NSError puede ser bastante caro. Cuando haces la llamada, Crashlytics captura la pila de llamadas del subproceso actual con un proceso llamado "liberación de pila". Este proceso puede consumir una gran cantidad de recursos de CPU y E/S, en particular en arquitecturas que admiten la liberación de DWARF (arm64 y x86). Cuando se completa la liberación, la información se escribe en el disco de manera asíncrona. Esto evita perder los datos si se produce un bloqueo en la línea siguiente.

Si bien es seguro llamar a esta API en un subproceso en segundo plano, recuerda que si despachas esta llamada a otra fila se perderá el contexto del seguimiento de pila actual.

¿Qué ocurre con NSExceptions?

Crashlytics no ofrece una instalación para el registro de instancias de NSException directamente. En términos generales, las API de Cocoa y Cocoa Touch no cuentan con seguridad para las excepciones. Esto significa que el uso de @catch puede tener efectos secundarios inesperados muy graves en tu proceso, incluso cuando se usa con un cuidado extremo. Nunca deberías usar declaraciones de @catch en tu código. Consulta la documentación de Apple sobre este tema.

android

En Android, esto significa que puedes registrar las excepciones capturadas en los bloques catch de la app:

Java
Android

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

Kotlin
Android

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

Todas las excepciones registradas aparecen como errores recuperables en Firebase console. Este resumen de problemas contiene toda la información de estado que se obtiene normalmente a partir de los bloqueos, junto con desgloses por versión de Android y dispositivo de hardware.

Crashlytics procesa excepciones en un subproceso dedicado en segundo plano, de manera que el impacto en el rendimiento de tu app es mínimo. Para reducir el tráfico de red de tus usuarios, Crashlytics agrupa las excepciones registradas en lotes y las envía la próxima vez que se inicie la app.

Crashlytics solo almacena las ocho excepciones más recientes en la sesión de una app determinada. Si tu app arroja más de 8 excepciones en una sesión, las excepciones más antiguas se perderán.
unity [Beta]

Puedes registrar excepciones personalizadas en C# a través de los siguientes métodos:

Crashlytics.LogException(Exception ex);

Puedes incluir las excepciones personalizas en los bloques try/catch de tu app:

try {
    myMethodThatThrows();
} catch (Exception e) {
   Crashlytics.LogException(e);
   // handle your exception here!
}

Habilita los informes de aceptación

Según la configuración predeterminada, Firebase Crashlytics recopila informes de fallas de todos los usuarios de tu app automáticamente. Para dar a los usuarios más control sobre los datos que envían, puedes habilitar los informes de aceptación en su lugar.

Con este fin, debes inhabilitar la recopilación automática y, luego, inicializar Crashlytics solo para los usuarios que aceptaron.

ios
  1. Desactiva la recopilación automática con una clave nueva en tu archivo Info.plist:
    • Clave: firebase_crashlytics_collection_enabled
    • Valor: false
  2. Habilita la recopilación para los usuarios seleccionados mediante la inicialización de Crashlytics en el tiempo de ejecución:
    Objective-C
    [Fabric with:@[[Crashlytics class]]];
    Swift
    Fabric.with([Crashlytics.self])
android
  1. Desactiva la recopilación automática con una etiqueta meta-data en tu archivo AndroidManifest.xml:
    <meta-data
        android:name="firebase_crashlytics_collection_enabled"
        android:value="false" />
    
  2. Habilita la recopilación para los usuarios seleccionados mediante la inicialización de Crashlytics desde una de las actividades de tu app:

    Java
    Android

    Fabric.with(this, new Crashlytics());

    Kotlin
    Android

    Fabric.with(this, Crashlytics())
Nota: No puedes detener los informes de Crashlytics una vez que los inicialices en la sesión de una app. Para inhabilitar los informes después de inicializar Crashlytics, los usuarios deben reiniciar la app.
unity [Beta]
Crashlytics.IsCrashlyticsCollectionEnabled = false;

A continuación, se presenta un ejemplo de cómo podrías adjuntar lo anterior a un elemento de la IU:

public class DataCollectionToggleScript : MonoBehaviour {

  public Toggle DataCollectionToggle;

  void Start () {
    Toggle toggle = DataCollectionToggle.GetComponent<Toggle>();
    toggle.isOn = Crashlytics.IsCrashlyticsCollectionEnabled;
    toggle.onValueChanged.AddListener(delegate {
      ToggleValueChanged(toggle);
    });
  }

  void ToggleValueChanged(Toggle toggle){
    Crashlytics.IsCrashlyticsCollectionEnabled = toggle.isOn;
  }
}

¿No puedes encontrar un método equivalente de Crashlytics de Fabric? Consulta nuestra página de cambios de la API de Unity para obtener más información sobre cómo Crashlytics evolucionó de Crashlytics de Fabric a Firebase Crashlytics.

Administra los datos de Crash Insights

Crash Insights te ayuda a resolver problemas a través de la comparación de tus seguimientos de pila anonimizados con seguimientos de otras apps de Firebase y te permite saber si tu problema es parte de una tendencia mayor. En muchos casos de problemas, Crash Insights incluso proporciona recursos para ayudarte a depurar el error.

Crash Insights usa datos de errores globales para identificar las tendencias de estabilidad comunes. Si prefieres no compartir los datos de tu app, puedes inhabilitar esta función en el menú Crash Insights ubicado en la parte superior de la lista de problemas de Crashlytics en Firebase console.

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.