En el panel de Crashlytics, puedes hacer clic en un problema para obtener un informe detallado del evento. Puedes personalizar esos informes para comprender mejor lo que sucede en tu app y las circunstancias de los eventos informados a Crashlytics.
Instrumenta tu app para registrar claves personalizadas, mensajes de registro personalizados y, además, identificadores de usuario.
Informa excepciones a Crashlytics.
Obtén automáticamente registros de rutas de navegación si tu app usa el SDK de Firebase para Google Analytics. Estos registros te brindan visibilidad sobre las acciones del usuario que conducen a un evento recopilado por Crashlytics en tu app.
Desactiva los informes de fallas automáticos y habilita los informes de aceptación para tus usuarios. Ten en cuenta que, de forma predeterminada, Crashlytics recopila informes de fallas de todos los usuarios de tu app automáticamente.
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, luego, usar las claves personalizadas para buscar y filtrar informes de fallas en Firebase console.
- En el panel de Crashlytics, puedes buscar problemas que coincidan con una clave personalizada.
- Cuando revises un problema específico en la consola, podrás ver las claves personalizadas asociadas a cada evento (pestaña secundaria Claves) y filtrar los eventos por claves personalizadas (menú Filtrar en la parte superior de la página).
Usa el método setCustomValue
para establecer pares clave-valor: Por ejemplo:
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
Cuando configures números enteros, valores booleanos o números de punto flotante, enmarca 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 puedes modificar el valor de una clave existente llamando a la clave y configurándola con un valor diferente. Por ejemplo:
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"];
Para agregar pares clave-valor de forma masiva, usa el método setCustomKeysAndValues
con un
NSDictionary como único parámetro:
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];
Agrega mensajes de registro personalizados
Para darte más contexto sobre los eventos que se produjeron antes de una falla, puedes agregar registros personalizados de Crashlytics a la app. Crashlytics asocia los registros con los datos de fallas y los hace visibles en la página de Crashlytics de Firebase console, en la pestaña Registros.
Swift
Usa log()
o log(format:, arguments:)
para identificar problemas. Si
deseas obtener un resultado de registro útil con mensajes, el objeto que pases a
log()
debe cumplir con la
propiedad
CustomStringConvertible
. log()
muestra la propiedad de descripción que defines para el objeto. Por ejemplo:
Crashlytics.crashlytics().log("Higgs-Boson detected! Bailing out…, \(attributesDict)")
.log(format:, arguments:)
da formato a los valores que se muestran después de llamar a getVaList()
. Por ejemplo:
Crashlytics.crashlytics().log(format: "%@, %@", arguments: getVaList(["Higgs-Boson detected! Bailing out…", attributesDict]))
Para obtener más detalles acerca de cómo usar log()
o log(format:, arguments:)
,
consulta la
documentación de referencia de Crashlytics.
Objective-C
Usa log
o logWithFormat
para identificar problemas. Ten presente que, si deseas obtener un resultado de registro útil con mensajes, el objeto que pases 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 acerca de cómo usar log
y logWithFormat
, consulta la
documentación de referencia de Crashlytics.
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 los informes de fallas.
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 de hash:
Swift
Crashlytics.crashlytics().setUserID("123456789")
Objective-C
[[FIRCrashlytics crashlytics] setUserID:@"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.
Informa excepciones recuperables
Además de informar las fallas de la app automáticamente, Crashlytics te permite registrar excepciones recuperables y te las envía la próxima vez que se inicie la app.
Puedes registrar excepciones recuperables si registras objetos NSError
con el método
recordError
. recordError
captura la pila de llamadas del subproceso mediante una llamada a [NSThread callStackReturnAddresses]
.
Swift
Crashlytics.crashlytics().record(error: error)
Objective-C
[[FIRCrashlytics crashlytics] 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 las fallas. El uso
incorrecto del método recordError
puede provocar un comportamiento impredecible y, además,
hacer que Crashlytics limite los informes de errores registrados en tu app.
Un objeto NSError
tiene tres argumentos:
domain: String
code: Int
userInfo: [AnyHashable : Any]? = nil
A diferencia de las fallas no recuperables, que se agrupan mediante el análisis de seguimiento de pila, los errores registrados se agrupan por domain
y code
. Esta es una distinción importante entre las fallas no recuperables y los errores registrados. Por ejemplo:
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];
Cuando registras el error anterior, se crea un problema nuevo que se agrupa por NSSomeErrorDomain
y -1001
. Los errores registrados adicionales que tengan los mismos valores de dominio y código se agrupan bajo el mismo problema. 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.
Registros y claves personalizadas
Al igual que los informes de fallas, puedes incorporar registros y claves personalizadas para agregar contexto a NSError
. Sin embargo, existe una diferencia entre los registros que se adjuntan a las fallas y los errores registrados. Cuando ocurre una falla y la app se reinicia, los
registros que Crashlytics recupera del disco son aquellos que se escribieron hasta el momento en que
se produjo la falla. 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 que debe limitar la cantidad de espacio asignada a los registros en el disco,
es posible registrar lo suficiente después de que se registre un NSError
, de forma que se roten
todos los registros pertinentes antes de que Crashlytics envíe el informe desde el
dispositivo. Ten en cuenta este equilibrio cuando registres NSErrors
y uses registros y
claves personalizadas en tu app.
Consideraciones de rendimiento
Ten en cuenta que registrar un NSError
puede ser bastante costoso. 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 síncrona.
Esto evita perder los datos si se produce una falla 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 pierde el contexto del seguimiento de pila actual.
¿Qué ocurre con NSExceptions?
Crashlytics no ofrece facilidades para registrar y grabar 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 debes
usar declaraciones @catch
en tu código. Consulta la
documentación de Apple
sobre este tema.
Personaliza seguimientos de pila
Si tu app se ejecuta en un entorno no nativo (como C++ o Unity), puedes usar la API de Exception Model para informar metadatos de fallas en el formato de excepción nativo de tu app. Las excepciones informadas se marcan como recuperables.
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];
Los marcos de pila personalizados también se pueden inicializar únicamente con direcciones, de esta manera:
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];
Obtén registros de rutas de navegación
Los registros de rutas de navegación te permiten comprender mejor las interacciones que un usuario tuvo con tu app que desencadenaron el evento de falla, recuperable o de ANR. Estos registros pueden ser útiles cuando se intenta reproducir y depurar un problema.
Los registros de rutas de navegación se basan en Google Analytics, por lo que, para obtenerlos, debes habilitar Google Analytics para tu proyecto de Firebase y agregar el SDK de Firebase para Google Analytics a tu app. Una vez que se cumplan estos requisitos, los registros de rutas de navegación se incluyen automáticamente con los datos de un evento en la pestaña Registros cuando ves los detalles de un problema.
El SDK de Analytics
registra automáticamente el evento screen_view
,
lo que permite que los registros de rutas de navegación muestren una lista de pantallas vistas antes del
evento de falla, recuperable o de ANR. Un registro de rutas de navegación screen_view
contiene un parámetro firebase_screen_class
.
Los registros de rutas de navegación también se completan con cualquier evento personalizado que registres de forma manual en 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 desencadenaron un evento de falla, recuperable o de ANR.
Ten en cuenta que puedes controlar la recopilación y el uso de los datos de Google Analytics, que incluyen los datos que propagan los registros de rutas de navegación.
Habilita los informes de participación
Según la configuración predeterminada, Crashlytics recopila informes de fallas de todos los usuarios de la app automáticamente. Para permitir que los usuarios tengan más control sobre los datos que envían, puedes habilitar los informes opcionales; para ello, inhabilita los informes automáticos y solo envía datos a Crashlytics cuando lo decidas en tu código:
Agrega una clave nueva al archivo
Info.plist
para desactivar la recopilación automática:- Clave:
FirebaseCrashlyticsCollectionEnabled
- Valor:
false
- Clave:
Habilita la recopilación para usuarios específicos; para ello, llama la anulación de recopilación de datos de Crashlytics durante el tiempo de ejecución. El valor de anulación persiste en todos los lanzamientos de tu app para que Crashlytics pueda recopilar informes automáticamente.
Para inhabilitar los informes automáticos de fallas, pasa
false
como el valor de anulación. Cuando se configura enfalse
, el valor nuevo no se aplica hasta la próxima ejecución de la app.Swift
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
Objective-C
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];
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, Crash Insights incluso proporciona recursos para ayudarte a depurar la falla.
Crash Insights usa datos de fallas globales para identificar las tendencias de estabilidad comunes. Si prefieres no compartir los datos de la app, puedes inhabilitar esta función en el menú Crash Insights ubicado en la parte superior de la lista de problemas de Crashlytics de Firebase console.