UNPKG

@datadog/mobile-react-native

Version:

A client-side React Native module to interact with Datadog

106 lines (101 loc) 4.12 kB
/* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2016-Present Datadog, Inc. */ import { InternalLog } from '../../InternalLog'; import { SdkVerbosity } from '../../SdkVerbosity'; import { DdLogs } from '../../logs/DdLogs'; import { getErrorMessage, getErrorStackTrace, EMPTY_STACK_TRACE, getErrorName, DEFAULT_ERROR_NAME } from '../../utils/errorUtils'; import { executeWithDelay } from '../../utils/jsUtils'; import { DdRum } from '../DdRum'; import { ErrorSource } from '../types'; /** * Provides RUM auto-instrumentation feature to track errors as RUM events. */ export class DdRumErrorTracking { static isTracking = false; static isInDefaultErrorHandler = false; // eslint-disable-next-line static defaultErrorHandler = (_error, _isFatal) => {}; // eslint-disable-next-line static defaultConsoleError = (..._params) => {}; /** * Starts tracking errors and sends a RUM Error event every time an error is detected. */ static startTracking() { // extra safety to avoid wrapping the Error handler twice if (DdRumErrorTracking.isTracking) { InternalLog.log('Datadog SDK is already tracking errors', SdkVerbosity.WARN); return; } if (ErrorUtils) { DdRumErrorTracking.defaultErrorHandler = ErrorUtils.getGlobalHandler(); DdRumErrorTracking.defaultConsoleError = console.error; ErrorUtils.setGlobalHandler(DdRumErrorTracking.onGlobalError); console.error = DdRumErrorTracking.onConsoleError; DdRumErrorTracking.isTracking = true; InternalLog.log('Datadog SDK is tracking errors', SdkVerbosity.INFO); } else { InternalLog.log('Datadog SDK cannot track errors, ErrorUtils is not defined', SdkVerbosity.ERROR); } } static onGlobalError = (error, isFatal) => { const message = getErrorMessage(error); const stacktrace = getErrorStackTrace(error); const errorName = getErrorName(error); this.reportError(message, ErrorSource.SOURCE, stacktrace, errorName, { '_dd.error.is_crash': isFatal, '_dd.error.raw': error }).then(async () => { DdRumErrorTracking.isInDefaultErrorHandler = true; try { // On real iOS devices, the crash context is not updated soon // enough for the view update to contain the crash. // Waiting for 50ms has low impact and ensures the crash context // is updated before actually crashing the app. await executeWithDelay(() => DdRumErrorTracking.defaultErrorHandler(error, isFatal), 50); } finally { DdRumErrorTracking.isInDefaultErrorHandler = false; } }); }; static onConsoleError = (...params) => { if (DdRumErrorTracking.isInDefaultErrorHandler) { return; } let stack = EMPTY_STACK_TRACE; let errorName = DEFAULT_ERROR_NAME; for (let i = 0; i < params.length; i += 1) { const param = params[i]; const paramStack = getErrorStackTrace(param); if (paramStack !== EMPTY_STACK_TRACE) { stack = paramStack; } const paramErrorName = getErrorName(param); if (paramErrorName !== DEFAULT_ERROR_NAME) { errorName = paramErrorName; } if (errorName !== DEFAULT_ERROR_NAME && stack !== EMPTY_STACK_TRACE) { break; } } const message = params.map(param => { if (typeof param === 'string') { return param; } else { return getErrorMessage(param); } }).join(' '); this.reportError(message, ErrorSource.CONSOLE, stack, errorName).then(() => { DdRumErrorTracking.defaultConsoleError.apply(console, params); }); }; static reportError = (message, source, stacktrace, errorName, context = {}) => { return Promise.all([DdRum.addError(message, source, stacktrace, context), DdLogs.error(message, errorName, message, stacktrace, { ...context, '_dd.error_log.is_crash': true }, undefined, source)]); }; } //# sourceMappingURL=DdRumErrorTracking.js.map