Реализация Breadcrumbs (последовательность действий до краша) в мобильном приложении
Крэш без контекста — это строчка в стеке вызовов и вопрос «как это воспроизвести». Breadcrumbs — это хронологический лог событий, которые предшествовали падению: переходы между экранами, нажатые кнопки, HTTP-запросы, кастомные события. Разница между «NullPointerException в ProductViewModel» и тем же крэшем с breadcrumbs — это разница между часом поиска и двумя минутами до фикса.
Как Sentry хранит breadcrumbs
Sentry SDK держит кольцевой буфер breadcrumbs в памяти. По умолчанию — последние 100 событий. При крэше буфер сериализуется и уходит с crash report. Буфер не записывается на диск между сессиями — только для текущего запуска приложения.
Это важно: если приложение завершилось корректно (backgrounded) и крэш произошёл при следующем запуске — breadcrumbs предыдущей сессии недоступны.
Автоматические breadcrumbs
Sentry добавляет часть breadcrumbs автоматически:
iOS:
SentrySDK.start { options in
options.dsn = "https://[email protected]/project"
options.enableAutoBreadcrumbTracking = true
// Автоматически: UIViewController transitions, HTTP requests (URLSession),
// System notifications (UIApplicationDidBecomeActiveNotification и др.)
}
Android:
SentryAndroid.init(this) { options ->
options.dsn = "https://[email protected]/project"
options.isEnableActivityLifecycleBreadcrumbs = true // Activity transitions
options.isEnableUserInteractionBreadcrumbs = true // Click events
options.isEnableNetworkEventBreadcrumbs = true // Network requests
options.isEnableAppComponentBreadcrumbs = true // App lifecycle
}
Автоматические breadcrumbs покрывают навигацию и сеть. Всё, что выше уровня framework — добавляем вручную.
Кастомные breadcrumbs
// iOS — навигационное событие в кастомном роутере
SentrySDK.addBreadcrumb({
let crumb = Breadcrumb()
crumb.category = "navigation"
crumb.message = "Opened ProductDetail"
crumb.data = ["product_id": productId, "source": "search"]
crumb.level = .info
return crumb
}())
// Android — бизнес-событие
val breadcrumb = Breadcrumb().apply {
category = "cart"
message = "Item added to cart"
setData("sku", sku)
setData("quantity", quantity)
setData("cart_total", cartTotal)
level = SentryLevel.INFO
}
Sentry.addBreadcrumb(breadcrumb)
Структурирование breadcrumbs для диагностики
Категории breadcrumbs определяют их отображение в Sentry UI. Используемые категории:
| Категория | Назначение |
|---|---|
navigation |
Переходы между экранами |
ui.click |
Нажатия кнопок, элементов списка |
http |
Сетевые запросы (автоматически) |
auth |
Авторизация, смена пользователя |
cart |
Корзина, оформление заказа |
lifecycle |
Фоновый/активный режим |
Конкретные данные в data — ключ к быстрой диагностике:
// Хорошо: видно, что именно произошло
breadcrumb.setData("screen", "CheckoutStep3")
breadcrumb.setData("payment_method", "card")
breadcrumb.setData("card_type", "visa")
// Плохо: непонятно без исходного кода
breadcrumb.setData("step", 3)
breadcrumb.setData("type", "card")
Настройка буфера
// iOS — увеличить лимит breadcrumbs
SentrySDK.start { options in
options.maxBreadcrumbs = 200 // по умолчанию 100
}
200 событий при активном пользователе — это примерно 2–3 минуты взаимодействия. Для сложных flow (регистрация, оплата) этого достаточно. Больше не нужно: крэш-репорт становится слишком большим, а старые события бесполезны.
Интеграция с навигацией
React Native Navigation:
// React Navigation v6 — автоматические breadcrumbs при переходах
import * as Sentry from "@sentry/react-native";
import { useNavigationContainerRef } from "@react-navigation/native";
const navigationRef = useNavigationContainerRef();
function App() {
return (
<NavigationContainer
ref={navigationRef}
onStateChange={() => {
const currentRoute = navigationRef.getCurrentRoute();
Sentry.addBreadcrumb({
category: "navigation",
message: `Navigated to ${currentRoute?.name}`,
level: "info",
});
}}
>
Flutter:
// NavigatorObserver для автоматических breadcrumbs
class SentryNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route route, Route? previousRoute) {
Sentry.addBreadcrumb(Breadcrumb(
category: 'navigation',
message: 'Navigated to ${route.settings.name}',
level: SentryLevel.info,
));
}
}
// В MaterialApp:
navigatorObservers: [SentryNavigatorObserver()],
Защита от утечки данных
Breadcrumbs могут содержать чувствительные данные. Настройка before-send фильтра:
options.beforeBreadcrumb = { breadcrumb in
// Не логируем breadcrumbs с токенами и паролями
if breadcrumb.category == "http",
let url = breadcrumb.data?["url"] as? String,
url.contains("/auth") || url.contains("/payment") {
return nil // не добавлять этот breadcrumb
}
return breadcrumb
}
Что делаем
- Включаем автоматические breadcrumbs для навигации, сети и lifecycle
- Определяем таксономию кастомных категорий под бизнес-логику
- Добавляем кастомные breadcrumbs в ключевые точки: корзина, оплата, авторизация
- Интегрируем с навигационными фреймворками (React Navigation, Flutter Navigator)
- Настраиваем
beforeBreadcrumbфильтр для исключения чувствительных данных
Сроки
Базовая настройка с автоматическими breadcrumbs: 4–8 часов. Полная инструментация с кастомными категориями: 2–3 дня. Стоимость рассчитывается индивидуально.







