UNPKG

omnis-logger-sdk

Version:

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

573 lines 21.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getOmnisLogger = exports.initOmnisLogger = exports.getDeviceId = exports.OmnisLogger = void 0; const axios_1 = __importDefault(require("axios")); class OmnisLogger { constructor(config) { this.queue = []; this.isProcessing = false; this.globalContext = {}; this.deviceInfo = {}; this.config = { environment: 'production', enableConsole: true, enableGlobalErrorHandlers: true, enableNetworkErrorCapture: true, maxRetries: 3, timeout: 5000, ...config, }; this.initializeDeviceInfo(config); this.client = axios_1.default.create({ baseURL: this.config.endpoint, timeout: this.config.timeout, headers: { 'Content-Type': 'application/json', 'X-API-Key': this.config.apiKey, }, }); if (this.config.enableGlobalErrorHandlers) { this.setupGlobalErrorHandlers(); } if (this.config.enableNetworkErrorCapture) { this.setupNetworkErrorCapture(); } } initializeDeviceInfo(config) { if (config.deviceInfo) { this.deviceInfo = { ...config.deviceInfo }; } else if (config.deviceInfoModule) { this.collectDeviceInfoFromModule(config.deviceInfoModule); } else { this.collectBrowserInfo(); } } collectDeviceInfoFromModule(DeviceInfoModule) { try { let Platform; try { Platform = require('react-native').Platform; } catch (e) { console.warn('React Native Platform недоступен'); return; } const syncInfo = { platform: 'react-native', os: DeviceInfoModule.getSystemName(), osVersion: DeviceInfoModule.getSystemVersion(), systemName: DeviceInfoModule.getSystemName(), systemVersion: DeviceInfoModule.getSystemVersion(), deviceId: DeviceInfoModule.getDeviceId(), brand: DeviceInfoModule.getBrand(), model: DeviceInfoModule.getModel(), deviceType: DeviceInfoModule.getDeviceType(), bundleId: DeviceInfoModule.getBundleId(), version: DeviceInfoModule.getVersion(), buildNumber: DeviceInfoModule.getBuildNumber(), readableVersion: DeviceInfoModule.getReadableVersion(), isTablet: DeviceInfoModule.isTablet(), }; if (Platform.OS === 'ios') { try { syncInfo.hasNotch = DeviceInfoModule.hasNotch(); syncInfo.hasDynamicIsland = DeviceInfoModule.hasDynamicIsland(); } catch (e) { } } this.deviceInfo = syncInfo; this.collectAsyncDeviceInfo(DeviceInfoModule, Platform); } catch (error) { console.warn('Ошибка сбора данных об устройстве из модуля:', error); this.deviceInfo = { platform: 'react-native' }; } } async collectAsyncDeviceInfo(DeviceInfoModule, Platform) { try { const asyncInfo = {}; try { asyncInfo.uniqueId = await DeviceInfoModule.getUniqueId(); asyncInfo.deviceName = await DeviceInfoModule.getDeviceName(); asyncInfo.manufacturer = await DeviceInfoModule.getManufacturer(); asyncInfo.applicationName = await DeviceInfoModule.getApplicationName(); asyncInfo.userAgent = await DeviceInfoModule.getUserAgent(); } catch (e) { } try { if (typeof DeviceInfoModule.isEmulatorSync === 'function') { asyncInfo.isEmulator = DeviceInfoModule.isEmulatorSync(); } else { asyncInfo.isEmulator = await DeviceInfoModule.isEmulator(); } } catch (e) { } if (Platform.OS === 'android') { try { asyncInfo.androidId = await DeviceInfoModule.getAndroidId(); asyncInfo.apiLevel = await DeviceInfoModule.getApiLevel(); } catch (e) { } } try { const { Dimensions } = require('react-native'); const dimensions = Dimensions.get('window'); asyncInfo.screenWidth = dimensions.width; asyncInfo.screenHeight = dimensions.height; asyncInfo.pixelRatio = dimensions.scale; } catch (e) { } try { const netInfo = require('@react-native-netinfo/netinfo'); const networkState = await netInfo.fetch(); asyncInfo.isConnected = networkState.isConnected; asyncInfo.networkType = networkState.type; } catch (e) { } this.deviceInfo = { ...this.deviceInfo, ...asyncInfo }; } catch (error) { console.warn('Ошибка сбора асинхронных данных об устройстве:', error); } } isBrowser() { return typeof window !== 'undefined'; } isReactNative() { return typeof navigator !== 'undefined' && navigator.product === 'ReactNative' || (typeof global !== 'undefined' && typeof global.navigator !== 'undefined' && global.navigator.product === 'ReactNative'); } collectBrowserInfo() { if (!this.isBrowser()) return; this.deviceInfo = { platform: 'browser', userAgent: navigator.userAgent, language: navigator.language, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, }; if (screen) { this.deviceInfo.screenWidth = screen.width; this.deviceInfo.screenHeight = screen.height; } if (window.devicePixelRatio) { this.deviceInfo.pixelRatio = window.devicePixelRatio; } const ua = navigator.userAgent.toLowerCase(); if (ua.includes('windows')) { this.deviceInfo.os = 'Windows'; const match = ua.match(/windows nt ([\d.]+)/); if (match) this.deviceInfo.osVersion = match[1]; } else if (ua.includes('mac os')) { this.deviceInfo.os = 'macOS'; const match = ua.match(/mac os x ([\d_]+)/); if (match) this.deviceInfo.osVersion = match[1].replace(/_/g, '.'); } else if (ua.includes('linux')) { this.deviceInfo.os = 'Linux'; } else if (ua.includes('android')) { this.deviceInfo.os = 'Android'; const match = ua.match(/android ([\d.]+)/); if (match) this.deviceInfo.osVersion = match[1]; } else if (ua.includes('iphone') || ua.includes('ipad')) { this.deviceInfo.os = 'iOS'; const match = ua.match(/os ([\d_]+)/); if (match) this.deviceInfo.osVersion = match[1].replace(/_/g, '.'); } } setupGlobalErrorHandlers() { if (this.isReactNative()) { this.setupReactNativeErrorHandlers(); } else if (this.isBrowser()) { this.setupBrowserErrorHandlers(); } } setupBrowserErrorHandlers() { const self = this; window.addEventListener('error', function (event) { self.handleGlobalError(event.error || event); }); window.addEventListener('unhandledrejection', function (event) { self.handleGlobalRejection(event); }); } setupReactNativeErrorHandlers() { const self = this; try { if (typeof global !== 'undefined' && global.ErrorUtils) { const originalGlobalHandler = global.ErrorUtils.getGlobalHandler(); global.ErrorUtils.setGlobalHandler((error, isFatal) => { self.handleGlobalError({ error, isFatal, type: 'react_native_js_error' }); if (originalGlobalHandler) { originalGlobalHandler(error, isFatal); } }); } if (typeof global !== 'undefined') { const originalRejectionHandler = global.onunhandledrejection; global.onunhandledrejection = function (event) { self.handleGlobalRejection(event); if (originalRejectionHandler) { originalRejectionHandler.call(this, event); } }; } } catch (error) { } } setupNetworkErrorCapture() { if (this.isReactNative()) { this.setupReactNativeNetworkCapture(); } else if (this.isBrowser()) { this.setupBrowserNetworkCapture(); } } setupBrowserNetworkCapture() { const self = this; if (typeof window !== 'undefined' && window.fetch) { const originalFetch = window.fetch; window.fetch = async function (...args) { var _a, _b; try { const response = await originalFetch(...args); const url = self.extractUrlFromFetchArgs(args[0]); const method = ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.method) || 'GET'; if (!response.ok) { self.error(`HTTP Error: ${response.status} ${response.statusText}`, { type: 'network_error', url, status: response.status, statusText: response.statusText, method, }); } return response; } catch (error) { const url = self.extractUrlFromFetchArgs(args[0]); const method = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.method) || 'GET'; self.exception(error, { type: 'network_error', url, method, }); throw error; } }; } if (typeof window !== 'undefined' && window.XMLHttpRequest) { const originalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function () { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; let method = ''; let url = ''; xhr.open = function (methodArg, urlArg, async, username, password) { method = methodArg; url = urlArg; return originalOpen.call(this, methodArg, urlArg, async !== null && async !== void 0 ? async : true, username, password); }; xhr.send = function (body) { const result = originalSend.call(this, body); xhr.addEventListener('error', function () { self.error('XMLHttpRequest Error', { type: 'network_error', method, url, status: xhr.status, statusText: xhr.statusText, }); }); xhr.addEventListener('load', function () { if (xhr.status >= 400) { self.error(`HTTP Error: ${xhr.status} ${xhr.statusText}`, { type: 'network_error', method, url, status: xhr.status, statusText: xhr.statusText, }); } }); return result; }; return xhr; }; } } setupReactNativeNetworkCapture() { const self = this; try { if (typeof global !== 'undefined' && global.fetch) { const originalFetch = global.fetch; global.fetch = async function (...args) { var _a, _b; try { const response = await originalFetch(...args); const url = self.extractUrlFromFetchArgs(args[0]); const method = ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.method) || 'GET'; if (!response.ok) { self.error(`HTTP Error: ${response.status} ${response.statusText}`, { type: 'network_error', url, status: response.status, statusText: response.statusText, method, platform: 'react-native' }); } return response; } catch (error) { const url = self.extractUrlFromFetchArgs(args[0]); const method = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.method) || 'GET'; self.exception(error, { type: 'network_error', url, method, platform: 'react-native' }); throw error; } }; } if (typeof global !== 'undefined' && global.XMLHttpRequest) { const originalXHR = global.XMLHttpRequest; global.XMLHttpRequest = function () { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; let method = ''; let url = ''; xhr.open = function (methodArg, urlArg, async, username, password) { method = methodArg; url = urlArg; return originalOpen.call(this, methodArg, urlArg, async !== null && async !== void 0 ? async : true, username, password); }; xhr.send = function (body) { const result = originalSend.call(this, body); xhr.addEventListener('error', function () { self.error('XMLHttpRequest Error', { type: 'network_error', method, url, status: xhr.status, statusText: xhr.statusText, platform: 'react-native' }); }); xhr.addEventListener('load', function () { if (xhr.status >= 400) { self.error(`HTTP Error: ${xhr.status} ${xhr.statusText}`, { type: 'network_error', method, url, status: xhr.status, statusText: xhr.statusText, platform: 'react-native' }); } }); return result; }; return xhr; }; } } catch (error) { } } error(message, context) { this.log('error', message, context); } warn(message, context) { this.log('warn', message, context); } info(message, context) { this.log('info', message, context); } debug(message, context) { this.log('debug', message, context); } exception(error, context) { this.log('error', error.message, { ...context, stack: error.stack, name: error.name, }); } log(level, message, context) { const logData = { level, message, context: { ...this.globalContext, ...(context || {}) }, userAgent: this.getUserAgent(), url: this.getCurrentUrl(), userId: this.config.userId, sessionId: this.config.sessionId, platform: this.config.platform, version: this.config.version, environment: this.config.environment, deviceInfo: this.deviceInfo, }; if (this.config.enableConsole) { console[level](`[Omnis Logger] ${message}`, { ...this.globalContext, ...(context || {}) }); } this.queue.push(logData); this.processQueue(); } handleGlobalError(event) { const error = event.error || event; this.exception(error, { type: 'uncaught_exception', filename: event.filename, lineno: event.lineno, colno: event.colno, }); } handleGlobalRejection(event) { const reason = event.reason || event; this.error('Unhandled Promise Rejection', { type: 'unhandled_rejection', reason: reason.toString(), stack: reason.stack, }); } getUserAgent() { if (typeof window !== 'undefined' && window.navigator) { return window.navigator.userAgent; } return undefined; } extractUrlFromFetchArgs(input) { var _a; if (typeof input === 'string') { return input; } if (input && typeof input === 'object' && 'url' in input) { return input.url; } if (input && typeof input === 'object' && input.toString && ((_a = input.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'URL') { return input.toString(); } return String(input); } getCurrentUrl() { if (typeof window !== 'undefined' && window.location) { return window.location.href; } return undefined; } async processQueue() { if (this.isProcessing || this.queue.length === 0) { return; } this.isProcessing = true; while (this.queue.length > 0) { const logData = this.queue.shift(); if (logData) { await this.sendLog(logData); } } this.isProcessing = false; } async sendLog(logData, retryCount = 0) { try { await this.client.post('/api/logs', { data: logData }); } catch (error) { if (retryCount < this.config.maxRetries) { const self = this; setTimeout(function () { self.sendLog(logData, retryCount + 1); }, Math.pow(2, retryCount) * 1000); } } } async flush() { return this.processQueue(); } setConfig(config) { this.config = { ...this.config, ...config }; if (config.apiKey) { this.client.defaults.headers['X-API-Key'] = config.apiKey; } } setUser(userId) { this.config.userId = userId; } setSession(sessionId) { this.config.sessionId = sessionId; } setGlobalContext(context) { this.globalContext = { ...this.globalContext, ...context }; } getGlobalContext() { return { ...this.globalContext }; } clearGlobalContext() { this.globalContext = {}; } setDeviceInfo(deviceInfo) { this.deviceInfo = { ...deviceInfo }; } getDeviceInfo() { return { ...this.deviceInfo }; } updateDeviceInfo(updates) { this.deviceInfo = { ...this.deviceInfo, ...updates }; } } exports.OmnisLogger = OmnisLogger; let globalLogger = null; const getDeviceId = () => { try { const DeviceInfo = require('react-native-device-info'); return DeviceInfo.getDeviceId(); } catch (e) { return 'unknown-device'; } }; exports.getDeviceId = getDeviceId; const initOmnisLogger = (config) => { globalLogger = new OmnisLogger(config); return globalLogger; }; exports.initOmnisLogger = initOmnisLogger; const getOmnisLogger = () => { return globalLogger; }; exports.getOmnisLogger = getOmnisLogger; exports.default = OmnisLogger; //# sourceMappingURL=index.js.map