¿Cómo configurás crash reporting y monitoreo para una app móvil en producción — Crashlytics, Sentry?
Errores fatales y no-fatales, stack traces symbolicados, y una tasa de crash-free conectada como el guardrail que habilita un staged rollout.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cómo configurás crash reporting y monitoreo para una app móvil en producción — Crashlytics, Sentry?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.El crash reporting no es un lujo que se agrega después del lanzamiento — es el circuito de feedback que le da sentido a los staged rollouts y a los feature flags desde el principio. Si no podés ver moverse la tasa de crash-free casi en tiempo real, "frenar el rollout en 20%" es una adivinanza, no una decisión. Las dos herramientas a las que recurre la mayoría de los equipos son Firebase Crashlytics y Sentry, y se superponen más de lo que su marketing sugiere, así que un entrevistador generalmente está escuchando si entendés qué te da cada una en realidad debajo del dashboard.
#Fatal vs. no-fatal, y por qué querés las dos
Un reporte de crash fatal se genera cuando la app termina inesperadamente: un crash nativo, una excepción de JS no capturada en React Native, una señal fatal. Un no-fatal es algo que reportás explícitamente desde un catch: una llamada a una API que falló y cayó a datos en caché, un error de parseo que se manejó, un pago que hubo que reintentar. Los equipos que solo conectan el reporting de crashes fatales están a ciegas frente a las fallas que más le importan al producto aunque no hayan tirado abajo la app — un proveedor de pagos devolviendo respuestas mal formadas en silencio durante una hora es un incidente de cinco alarmas que un dashboard solo-fatal nunca va a mostrar.
#Symbolication: el paso que hace legible todo esto
Un stack trace crudo de un build de release es una lista de direcciones de memoria o nombres ofuscados, no nombres de funciones ni números de línea — inútil sin el archivo de símbolos correspondiente. En iOS eso es el bundle dSYM generado por cada build, que Crashlytics o Sentry necesitan que subas — mediante un script en una build phase, o sentry-cli upload-dif — asociado al UUID exacto del build. En Android con el shrinking de código de R8/ProGuard activado, que en la práctica siempre está activo en un build de release, eso es el archivo mapping.txt que el plugin de Gradle puede subir automáticamente. Salteá este paso y cada reporte de crash de producción va a ser hexadecimal ilegible, descubierto recién cuando alguien lo necesite durante un incidente.
class PaymentRepository(private val crashlytics: FirebaseCrashlytics) {fun processPayment(orderId: String, provider: String) {crashlytics.setCustomKey("order_id", orderId)crashlytics.setCustomKey("payment_provider", provider)crashlytics.log("payment: starting charge for $orderId")try {chargeCard(orderId)} catch (e: PaymentDeclinedException) {// Manejado, visible para el usuario — igual vale la pena saberlo en agregado.crashlytics.recordException(e)showDeclinedDialog()} catch (e: PaymentGatewayTimeoutException) {crashlytics.recordException(e)retryWithBackoff(orderId)}}}
android {buildTypes {release {isMinifyEnabled = trueproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")}}}firebaseCrashlytics {mappingFileUploadEnabled = truenativeSymbolUploadEnabled = true}
#Sentry: crashes más performance y release health
Sentry cubre la misma división fatal/no-fatal pero agrega dos cosas por las que muchos equipos lo eligen específicamente: performance monitoring — traces para el tiempo de cold start, la carga de pantallas, una llamada de red lenta, muestreados a una tasa que vos controlás para que no explote el volumen de eventos — y release health, que ata la tasa de sesiones y usuarios libres de crash directamente a una versión de release y a la duración de sesión, no solo a un conteo crudo de crashes. Esa es la métrica que realmente querés al decidir si avanzar un staged rollout.
import * as Sentry from "@sentry/react-native";Sentry.init({dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",release: `com.myapp@${appVersion}+${buildNumber}`,tracesSampleRate: 0.2,beforeSend(event) {// Sacá todo lo que pueda identificar a una persona antes de que salga del dispositivo.if (event.user) {delete event.user.email;delete event.user.ip_address;}return event;},});export function identifyUser(hashedUserId: string) {Sentry.setUser({ id: hashedUserId });}export function trackCheckoutStep(step: string) {Sentry.addBreadcrumb({ category: "checkout", message: step, level: "info" });}
#Convertir la tasa de crash-free en un gate de release
La recompensa de conectar todo esto con cuidado es que se convierte en la métrica de guardrail que decide si un staged rollout avanza: mantenelo en 20% y avisale a alguien si las sesiones libres de crash caen más de medio punto respecto del release anterior, o automatizalo por completo — un job programado lee la API de Crashlytics o Sentry y llama a la Play Developer API o a la App Store Connect API para frenar el rollout por sí solo, antes de que una persona siquiera mire un dashboard.