UNPKG

omnis-logger-sdk

Version:

SDK для интеграции Omnis Logger в проекты

781 lines (627 loc) 23.6 kB
# Omnis Logger SDK - React Native Guide Подробное руководство по интеграции Omnis Logger SDK в React Native приложения. ## Установка ```bash npm install @your-org/omnis-logger react-native-device-info ``` ## Быстрый старт ### 1. Простая инициализация (рекомендуемый способ) Самый простой способ - передать модуль `DeviceInfo` в SDK, и он сам соберет все нужные данные: ```javascript // Logger.js import { initOmnisLogger } from '@your-org/omnis-logger'; import DeviceInfo from 'react-native-device-info'; import { Platform } from 'react-native'; class LoggerService { constructor() { this.logger = null; this.isInitialized = false; } initialize() { if (this.isInitialized) return this.logger; try { // Простая инициализация - SDK сам соберет все данные this.logger = initOmnisLogger({ endpoint: 'https://your-api.com', apiKey: 'your-api-key', environment: __DEV__ ? 'development' : 'production', platform: Platform.OS, version: DeviceInfo.getVersion(), userId: 'user-123', // или получите из хранилища sessionId: `session-${Date.now()}`, deviceInfoModule: DeviceInfo // Передаем модуль, SDK сам соберет данные }); this.isInitialized = true; console.log('Logger инициализирован успешно'); return this.logger; } catch (error) { console.error('Ошибка инициализации логгера:', error); return null; } } getLogger() { return this.logger; } // Удобные методы для логирования error(message, context = {}) { if (this.logger) { this.logger.error(message, context); } else if (__DEV__) { console.error('[Logger не инициализирован]', message, context); } } info(message, context = {}) { if (this.logger) { this.logger.info(message, context); } else if (__DEV__) { console.info('[Logger не инициализирован]', message, context); } } exception(error, context = {}) { if (this.logger) { this.logger.exception(error, context); } else if (__DEV__) { console.error('[Logger не инициализирован]', error, context); } } } export default new LoggerService(); ``` ### 2. Инициализация в App.js ```javascript import React, { useEffect } from 'react'; import { AppState } from 'react-native'; import Logger from './src/services/Logger'; const App = () => { useEffect(() => { // Инициализируем логгер при запуске приложения (синхронно!) const logger = Logger.initialize(); if (logger) { Logger.info('Приложение запущено'); } // Логируем изменения состояния приложения const handleAppStateChange = (nextAppState) => { Logger.info('Изменение состояния приложения', { state: nextAppState }); }; const subscription = AppState.addEventListener( 'change', handleAppStateChange ); return () => { subscription?.remove(); Logger.info('Приложение закрыто'); }; }, []); return ( // Ваше приложение ); }; export default App; ``` ### Что происходит автоматически SDK автоматически соберет: **Синхронные данные** (мгновенно): - `deviceId`, `model`, `brand` - `systemName`, `systemVersion` - `bundleId`, `version`, `buildNumber` - `isTablet`, `deviceType` - `hasNotch`, `hasDynamicIsland` (iOS) **Асинхронные данные** (в фоне): - `deviceName`, `manufacturer` - `isEmulator`, `uniqueId` - `androidId`, `apiLevel` (Android) - `screenWidth`, `screenHeight`, `pixelRatio` - `networkType`, `isConnected` (если установлен NetInfo) ### 3. Расширенная инициализация (если нужен контроль) Если вам нужен полный контроль над сбором данных: ```javascript // ExtendedLogger.js import { initOmnisLogger } from '@your-org/omnis-logger'; import DeviceInfo from 'react-native-device-info'; import { Platform } from 'react-native'; class ExtendedLoggerService { constructor() { this.logger = null; this.isInitialized = false; } async initialize() { if (this.isInitialized) return this.logger; try { // Собираем критически важные данные сами const essentialDeviceInfo = { platform: Platform.OS, deviceId: DeviceInfo.getDeviceId(), model: DeviceInfo.getModel(), systemName: DeviceInfo.getSystemName(), systemVersion: DeviceInfo.getSystemVersion(), version: DeviceInfo.getVersion(), isTablet: DeviceInfo.isTablet(), // Добавляем кастомные поля customAppData: 'some-custom-value', userSegment: 'premium', }; // Инициализируем с готовыми данными this.logger = initOmnisLogger({ endpoint: 'https://your-api.com', apiKey: 'your-api-key', environment: __DEV__ ? 'development' : 'production', platform: Platform.OS, version: DeviceInfo.getVersion(), userId: 'user-123', sessionId: `session-${Date.now()}`, deviceInfo: essentialDeviceInfo // Используем готовые данные }); // Дополнительные данные собираем отдельно this.collectAdditionalInfo(); this.isInitialized = true; return this.logger; } catch (error) { console.error('Ошибка инициализации логгера:', error); return null; } } async collectAdditionalInfo() { try { const additionalInfo = { deviceName: await DeviceInfo.getDeviceName(), manufacturer: await DeviceInfo.getManufacturer(), isEmulator: await DeviceInfo.isEmulator(), }; // Обновляем данные об устройстве if (this.logger) { this.logger.updateDeviceInfo(additionalInfo); } } catch (error) { console.warn('Ошибка сбора дополнительных данных:', error); } } } export default new ExtendedLoggerService(); ``` ## Сравнение подходов | Критерий | deviceInfoModule | deviceInfo | |----------|------------------|------------| | **Простота** | ✅ Очень просто | ❌ Много кода | | **Скорость инициализации** | ✅ Мгновенно | ❌ Ждем async | | **Контроль** | ❌ Ограниченный | ✅ Полный | | **Кастомные поля** | ❌ Нет | ✅ Да | | **Оптимизация** | ✅ SDK оптимизирован | ❌ Ваша ответственность | **Рекомендация**: Используйте `deviceInfoModule` для большинства случаев, `deviceInfo` только если нужны кастомные поля. ### 4. Использование в компонентах #### Пример экрана профиля ```javascript import React, { useState, useEffect } from 'react'; import { View, Text, Button, Alert } from 'react-native'; import Logger from '../services/Logger'; // Используем наш упрощенный сервис const ProfileScreen = ({ navigation, route }) => { const [isLoading, setIsLoading] = useState(false); const [profile, setProfile] = useState(null); useEffect(() => { Logger.info('Экран профиля открыт', { screen: 'Profile', userId: route.params?.userId }); loadProfile(); return () => { Logger.info('Экран профиля закрыт', { screen: 'Profile' }); }; }, []); const loadProfile = async () => { setIsLoading(true); try { const response = await fetch('/api/profile'); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); setProfile(data); Logger.info('Профиль загружен успешно', { screen: 'Profile', profileId: data.id }); } catch (error) { Logger.exception(error, { screen: 'Profile', action: 'loadProfile' }); Alert.alert('Ошибка', 'Не удалось загрузить профиль'); } finally { setIsLoading(false); } }; // Остальной код компонента... return ( <View> <Text>Профиль</Text> {/* UI компонента */} </View> ); }; export default ProfileScreen; ``` #### Простая инициализация в реальном проекте ```javascript // services/Logger.js import { initOmnisLogger } from '@your-org/omnis-logger'; import DeviceInfo from 'react-native-device-info'; import { Platform } from 'react-native'; import { storage } from './storage'; // ваше хранилище class LoggerService { constructor() { this.logger = null; } initialize() { if (this.logger) return this.logger; const userId = storage.getString('USER_ID') || 'anonymous'; const sessionId = `session-${Date.now()}`; // Вся логика сбора данных теперь в SDK! this.logger = initOmnisLogger({ endpoint: 'https://your-api.com', apiKey: 'your-api-key', environment: __DEV__ ? 'development' : 'production', platform: Platform.OS, version: DeviceInfo.getVersion(), userId: userId, sessionId: sessionId, deviceInfoModule: DeviceInfo // SDK сам соберет все данные }); return this.logger; } // Простые методы для удобства error = (message, context) => this.logger?.error(message, context); info = (message, context) => this.logger?.info(message, context); exception = (error, context) => this.logger?.exception(error, context); } export default new LoggerService(); ``` Вместо 100+ строк кода для сбора данных, теперь всего несколько строк! ## Практические примеры ### Обработка аутентификации ```javascript // AuthService.js import Logger from './Logger'; class AuthService { async login(email, password) { try { Logger.info('Попытка входа', { email }); const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); if (!response.ok) { throw new Error(`Ошибка входа: ${response.status}`); } const data = await response.json(); // Обновляем пользователя в логгере const logger = Logger.getLogger(); if (logger) { logger.setUser(data.user.id); logger.setSession(data.sessionId); } Logger.info('Пользователь вошел в систему', { userId: data.user.id, email: data.user.email }); return data; } catch (error) { Logger.exception(error, { action: 'login', email }); throw error; } } } export default new AuthService(); ``` ### Логирование производительности ```javascript // PerformanceLogger.js import Logger from './Logger'; class PerformanceLogger { startTimer(name) { const startTime = Date.now(); return { end: (context = {}) => { const duration = Date.now() - startTime; Logger.info(`Производительность: ${name}`, { ...context, type: 'performance', operation: name, duration: `${duration}ms` }); } }; } logScreenLoad(screenName) { const timer = this.startTimer(`Screen Load: ${screenName}`); return timer; } } export default new PerformanceLogger(); ``` ## Лучшие практики ### 1. Оптимизация сбора данных об устройстве ```javascript // Быстрая инициализация с минимальными данными class OptimizedLoggerService extends LoggerService { async quickInitialize() { if (this.isInitialized) return this.logger; try { // Собираем только самые важные синхронные данные const essentialInfo = { platform: 'react-native', deviceId: DeviceInfo.getDeviceId(), model: DeviceInfo.getModel(), systemName: DeviceInfo.getSystemName(), systemVersion: DeviceInfo.getSystemVersion(), version: DeviceInfo.getVersion(), isTablet: DeviceInfo.isTablet(), }; // Инициализируем логгер немедленно this.logger = initOmnisLogger({ endpoint: 'https://your-api.com', apiKey: 'your-api-key', environment: __DEV__ ? 'development' : 'production', platform: 'react-native', version: DeviceInfo.getVersion(), deviceInfo: essentialInfo }); this.isInitialized = true; // Собираем дополнительные данные в фоне this.collectAdditionalInfo(); return this.logger; } catch (error) { console.error('Ошибка быстрой инициализации логгера:', error); return null; } } async collectAdditionalInfo() { try { // Собираем дополнительные данные асинхронно const additionalInfo = { deviceName: await DeviceInfo.getDeviceName(), manufacturer: await DeviceInfo.getManufacturer(), isEmulator: await DeviceInfo.isEmulator(), uniqueId: await DeviceInfo.getUniqueId(), }; // Android специфичные данные if (DeviceInfo.getSystemName() === 'Android') { additionalInfo.androidId = await DeviceInfo.getAndroidId(); additionalInfo.apiLevel = await DeviceInfo.getApiLevel(); } // iOS специфичные данные if (DeviceInfo.getSystemName() === 'iOS') { additionalInfo.hasNotch = DeviceInfo.hasNotch(); additionalInfo.hasDynamicIsland = DeviceInfo.hasDynamicIsland(); } // Обновляем данные об устройстве в логгере if (this.logger) { this.logger.updateDeviceInfo(additionalInfo); } } catch (error) { console.warn('Ошибка сбора дополнительных данных:', error); } } } export default new OptimizedLoggerService(); ``` ### 2. Полезные данные для UI Dashboard ```javascript // Функция для сбора данных специально для отображения в UI const getUIDisplayInfo = async () => { const uiInfo = {}; try { // Критически важные данные для техподдержки uiInfo.deviceName = await DeviceInfo.getDeviceName(); uiInfo.model = DeviceInfo.getModel(); uiInfo.manufacturer = await DeviceInfo.getManufacturer(); uiInfo.systemName = DeviceInfo.getSystemName(); uiInfo.systemVersion = DeviceInfo.getSystemVersion(); uiInfo.appVersion = DeviceInfo.getVersion(); uiInfo.buildNumber = DeviceInfo.getBuildNumber(); // Полезно для диагностики uiInfo.isEmulator = await DeviceInfo.isEmulator(); uiInfo.isTablet = DeviceInfo.isTablet(); // Android специфичные данные для техподдержки if (DeviceInfo.getSystemName() === 'Android') { uiInfo.apiLevel = await DeviceInfo.getApiLevel(); uiInfo.androidId = await DeviceInfo.getAndroidId(); } // iOS специфичные данные if (DeviceInfo.getSystemName() === 'iOS') { uiInfo.hasNotch = DeviceInfo.hasNotch(); uiInfo.hasDynamicIsland = DeviceInfo.hasDynamicIsland(); } // Размер экрана для понимания UX проблем const { Dimensions } = require('react-native'); const dimensions = Dimensions.get('window'); uiInfo.screenWidth = dimensions.width; uiInfo.screenHeight = dimensions.height; uiInfo.screenScale = dimensions.scale; // Сетевая информация (если доступна) try { const netInfo = require('@react-native-netinfo/netinfo'); const networkState = await netInfo.fetch(); uiInfo.networkType = networkState.type; uiInfo.isConnected = networkState.isConnected; } catch (e) { // NetInfo не установлен } } catch (error) { console.error('Ошибка сбора UI данных:', error); } return uiInfo; }; // Использование в приложении const App = () => { useEffect(() => { const initializeWithUIData = async () => { const deviceInfo = await getUIDisplayInfo(); const logger = initOmnisLogger({ endpoint: 'https://your-api.com', apiKey: 'your-api-key', environment: __DEV__ ? 'development' : 'production', platform: 'react-native', version: DeviceInfo.getVersion(), deviceInfo: deviceInfo }); // Логируем успешную инициализацию с основной информацией logger.info('Приложение запущено', { device: `${deviceInfo.manufacturer} ${deviceInfo.model}`, os: `${deviceInfo.systemName} ${deviceInfo.systemVersion}`, app: `${deviceInfo.appVersion} (${deviceInfo.buildNumber})`, screen: `${deviceInfo.screenWidth}x${deviceInfo.screenHeight}`, isEmulator: deviceInfo.isEmulator }); }; initializeWithUIData(); }, []); return <YourApp />; }; ``` ### 3. Структура контекста ```javascript // Всегда используйте структурированный контекст Logger.error('Ошибка сети', { screen: 'ProfileScreen', action: 'loadProfile', endpoint: '/api/profile', statusCode: 500, retry_attempt: 2 }); ``` ### 4. Логирование пользовательских действий ```javascript const handleButtonPress = () => { Logger.info('Пользователь нажал кнопку', { screen: 'HomeScreen', button: 'startOrder', user_action: true }); // ваша логика }; ``` ### 5. Обработка ошибок ```javascript try { // ваш код } catch (error) { Logger.exception(error, { screen: 'CurrentScreen', action: 'specific_action', additional_context: 'any_useful_info' }); // показать пользователю дружелюбное сообщение } ``` ### 6. Условное логирование ```javascript // Логирование только в определенных условиях if (isImportantOperation) { Logger.info('Выполняется важная операция', context); } // Различные уровни для разных окружений if (__DEV__) { Logger.debug('Отладочная информация', debugContext); } else { Logger.info('Продакшн информация', prodContext); } ``` ## Данные особенно полезные для UI Dashboard При создании dashboard для отображения ошибок, следующие поля из DeviceInfo особенно полезны: ### Критически важные для техподдержки: - `deviceName` - "iPhone 12 Pro", "Samsung Galaxy S21" - `manufacturer` - "Apple", "Samsung" - `model` - "iPhone14,3", "SM-G991B" - `systemName` + `systemVersion` - "iOS 16.4", "Android 13" - `appVersion` + `buildNumber` - "1.2.3 (456)" - `isEmulator` - помогает понять тестовая ли это ошибка ### Полезные для диагностики UX проблем: - `screenWidth` x `screenHeight` - размер экрана - `isTablet` - тип устройства - `hasNotch` / `hasDynamicIsland` - для iOS layout проблем - `networkType` - "wifi", "cellular" для сетевых ошибок ### Пример отображения в UI: ``` 📱 Device: iPhone 12 Pro (Apple) 🔧 System: iOS 16.4 📦 App: 1.2.3 (456) 📏 Screen: 390x844 🌐 Network: wifi ``` ## Troubleshooting ### Проблема: Logger не инициализируется ```javascript // Проверьте инициализацию if (!Logger.getLogger()) { console.warn('Logger не инициализирован'); // Попробуйте переинициализировать Logger.initialize(); } ``` ### Проблема: Отсутствуют данные об устройстве ```javascript // Убедитесь что react-native-device-info установлен // npm install react-native-device-info // Для старых версий React Native может потребоваться linking // react-native link react-native-device-info // Проверьте что модуль передается правильно const logger = initOmnisLogger({ // ... другие настройки deviceInfoModule: DeviceInfo // Убедитесь что импорт корректный }); ``` ### Проблема: Логи не отправляются ```javascript // Принудительная отправка логов const logger = Logger.getLogger(); if (logger) { await logger.flush(); } ``` ### Проблема: Нужны дополнительные поля DeviceInfo ```javascript // Если SDK не собирает нужные вам поля, используйте расширенный подход const customDeviceInfo = { // Базовые поля platform: Platform.OS, deviceId: DeviceInfo.getDeviceId(), // ... другие поля // Ваши кастомные поля customField: 'custom-value', userSegment: 'premium' }; const logger = initOmnisLogger({ // ... другие настройки deviceInfo: customDeviceInfo // Используйте готовый объект }); ``` ## Миграция с предыдущих версий ### Было (сложно): ```javascript // Много кода для сбора данных const deviceInfo = { platform: Platform.OS, deviceId: DeviceInfo.getDeviceId(), deviceName: await DeviceInfo.getDeviceName(), // ... еще 20+ полей }; const logger = initOmnisLogger({ // ... настройки deviceInfo: deviceInfo }); ``` ### Стало (просто): ```javascript // SDK сам соберет все данные const logger = initOmnisLogger({ // ... настройки deviceInfoModule: DeviceInfo }); ```