@datadog/mobile-react-native
Version:
A client-side React Native module to interact with Datadog
106 lines (101 loc) • 4.16 kB
JavaScript
/*
* 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, getErrorContext } 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, getErrorContext(context)), DdLogs.error(message, errorName, message, stacktrace, {
...context,
'_dd.error_log.is_crash': true
}, undefined, source)]);
};
}
//# sourceMappingURL=DdRumErrorTracking.js.map