Monitoring
Error tracking и аналитика.
Структура
src/core/monitoring/
├── sentry.ts # Error tracking
├── analytics.ts # Firebase + Vexo Analytics
└── index.ts
Sentry
Error tracking и crash reporting.
Инициализация
// src/core/monitoring/sentry.ts
import * as Sentry from '@sentry/react-native';
export function initSentry() {
Sentry.init({
dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
environment: __DEV__ ? 'development' : 'production',
enableAutoSessionTracking: true,
tracesSampleRate: 0.2, // 20% транзакций для performance
attachStacktrace: true,
});
}
Использование
import * as Sentry from '@sentry/react-native';
// Отловить ошибку
try {
await riskyOperation();
} catch (error) {
Sentry.captureException(error);
throw error;
}
// Добавить контекст
Sentry.setUser({
id: user.id,
email: user.email,
});
Sentry.setTag('subscription_tier', tier);
// Breadcrumbs для отладки
Sentry.addBreadcrumb({
category: 'navigation',
message: `Navigated to ${screen}`,
level: 'info',
});
Error Boundary
// app/_layout.tsx
import * as Sentry from '@sentry/react-native';
export default Sentry.wrap(function RootLayout() {
return <App />;
});
Firebase Analytics
Инициализация
// src/core/monitoring/analytics.ts
import analytics from '@react-native-firebase/analytics';
export const Analytics = {
async logScreenView(screenName: string) {
await analytics().logScreenView({
screen_name: screenName,
screen_class: screenName,
});
},
async logEvent(name: string, params?: Record<string, any>) {
await analytics().logEvent(name, params);
},
async setUserId(userId: string) {
await analytics().setUserId(userId);
},
async setUserProperty(name: string, value: string) {
await analytics().setUserProperty(name, value);
},
};
События
// Логирование событий
Analytics.logEvent('lesson_completed', {
lesson_id: lessonId,
course_id: courseId,
time_spent: timeSpent,
});
Analytics.logEvent('course_created', {
language: language,
difficulty: difficulty,
});
Analytics.logEvent('subscription_started', {
tier: tier,
price: price,
});
Analytics.logEvent('game_completed', {
game_type: 'memory_cards',
score: score,
moves: moves,
});
Screen Tracking
// В layout экранов
import { usePathname } from 'expo-router';
import { Analytics } from '@/core/monitoring';
export default function AppLayout() {
const pathname = usePathname();
useEffect(() => {
Analytics.logScreenView(pathname);
}, [pathname]);
return <Slot />;
}
Vexo Analytics
Session replay и heatmaps.
// src/core/monitoring/analytics.ts
import Vexo from 'vexo-analytics';
export function initVexo() {
if (!__DEV__) {
Vexo.init(process.env.EXPO_PUBLIC_VEXO_API_KEY);
}
}
// Идентификация пользователя
export function identifyUser(userId: string, traits?: Record<string, any>) {
Vexo.identify(userId, traits);
}
// Кастомные события
export function trackVexoEvent(name: string, properties?: Record<string, any>) {
Vexo.track(name, properties);
}
Unified Monitoring Init
// src/core/monitoring/index.ts
import { initSentry } from './sentry';
import { initVexo, Analytics } from './analytics';
export function initMonitoring() {
initSentry();
initVexo();
}
export { Analytics };
export * from './sentry';
// app/_layout.tsx
import { initMonitoring, Analytics } from '@/core/monitoring';
export default function RootLayout() {
useEffect(() => {
initMonitoring();
}, []);
// При получении сессии — идентифицировать пользователя
useEffect(() => {
if (session?.user) {
Analytics.setUserId(session.user.id);
Sentry.setUser({ id: session.user.id, email: session.user.email });
}
}, [session]);
}
Performance Monitoring
import * as Sentry from '@sentry/react-native';
// Измерение производительности операции
async function fetchCourses() {
const transaction = Sentry.startTransaction({
name: 'fetch-courses',
op: 'http.client',
});
try {
const result = await api.getCourses();
transaction.setStatus('ok');
return result;
} catch (error) {
transaction.setStatus('internal_error');
throw error;
} finally {
transaction.finish();
}
}
Environment Variables
EXPO_PUBLIC_SENTRY_DSN=https://xxx@sentry.io/xxx
EXPO_PUBLIC_VEXO_API_KEY=vexo_xxx
Debug Mode
В development отключаем отправку:
export function initSentry() {
if (__DEV__) {
console.log('Sentry disabled in development');
return;
}
Sentry.init({ ... });
}