Перейти к основному содержимому

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({ ... });
}