UNPKG

@datadog/mobile-react-native

Version:

A client-side React Native module to interact with Datadog

262 lines (252 loc) 12.6 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 { version as reactNativeVersion } from 'react-native/package.json'; import { InteractionManager } from 'react-native'; import { DdSdkReactNativeConfiguration, InitializationMode, addDefaultValuesToAutoInstrumentationConfiguration, buildConfigurationFromPartialConfiguration, formatFirstPartyHosts } from './DdSdkReactNativeConfiguration'; import { InternalLog } from './InternalLog'; import { SdkVerbosity } from './SdkVerbosity'; import { DdLogs } from './logs/DdLogs'; import { DdRum } from './rum/DdRum'; import { DdRumErrorTracking } from './rum/instrumentation/DdRumErrorTracking'; import { DdBabelInteractionTracking } from './rum/instrumentation/interactionTracking/DdBabelInteractionTracking'; import { DdRumUserInteractionTracking } from './rum/instrumentation/interactionTracking/DdRumUserInteractionTracking'; import { DdRumResourceTracking } from './rum/instrumentation/resourceTracking/DdRumResourceTracking'; import { AttributesSingleton } from './sdk/AttributesSingleton/AttributesSingleton'; import { registerNativeBridge } from './sdk/DatadogInternalBridge/DdSdkInternalNativeBridge'; import { BufferSingleton } from './sdk/DatadogProvider/Buffer/BufferSingleton'; import { DdSdk } from './sdk/DdSdk'; import { FileBasedConfiguration } from './sdk/FileBasedConfiguration/FileBasedConfiguration'; import { GlobalState } from './sdk/GlobalState/GlobalState'; import { UserInfoSingleton } from './sdk/UserInfoSingleton/UserInfoSingleton'; import { DdSdkConfiguration } from './types'; import { adaptLongTaskThreshold } from './utils/longTasksUtils'; import { version as sdkVersion } from './version'; /** * This class initializes the Datadog SDK, and sets up communication with the server. */ export class DdSdkReactNative { static DD_SOURCE_KEY = '_dd.source'; static DD_SDK_VERSION = '_dd.sdk_version'; static DD_VERSION = '_dd.version'; static DD_VERSION_SUFFIX = '_dd.version_suffix'; static DD_REACT_NATIVE_VERSION = '_dd.react_native_version'; static wasAutoInstrumented = false; /** * Initializes the Datadog SDK. * @param configuration the configuration for the SDK library * @returns a Promise. */ static initialize = async configuration => { await DdSdkReactNative.initializeNativeSDK(configuration, { initializationModeForTelemetry: 'LEGACY' }); DdSdkReactNative.enableFeatures(configuration); }; static initializeNativeSDK = async (configuration, params) => { if (GlobalState.instance.isInitialized) { InternalLog.log("Can't initialize Datadog, SDK was already initialized", SdkVerbosity.WARN); if (!__DEV__) { DdSdk.telemetryDebug('RN SDK was already initialized in javascript'); } return new Promise(resolve => resolve()); } InternalLog.verbosity = configuration.verbosity; registerNativeBridge(); await DdSdk.initialize(DdSdkReactNative.buildConfiguration(configuration, params)); InternalLog.log('Datadog SDK was initialized', SdkVerbosity.INFO); GlobalState.instance.isInitialized = true; BufferSingleton.onInitialization(); }; /** * FOR INTERNAL USE ONLY. */ static _initializeFromDatadogProvider = async configuration => { DdSdkReactNative.enableFeatures(configuration); if (configuration instanceof FileBasedConfiguration) { return DdSdkReactNative.initializeNativeSDK(configuration, { initializationModeForTelemetry: 'FILE' }); } if (configuration.initializationMode === InitializationMode.SYNC) { return DdSdkReactNative.initializeNativeSDK(configuration, { initializationModeForTelemetry: 'SYNC' }); } if (configuration.initializationMode === InitializationMode.ASYNC) { return InteractionManager.runAfterInteractions(() => { return DdSdkReactNative.initializeNativeSDK(configuration, { initializationModeForTelemetry: 'ASYNC' }); }); } // TODO: Remove when DdSdkReactNativeConfiguration is deprecated if (configuration instanceof DdSdkReactNativeConfiguration) { return DdSdkReactNative.initializeNativeSDK(configuration, { initializationModeForTelemetry: 'SYNC' }); } }; /** * FOR INTERNAL USE ONLY. */ static _enableFeaturesFromDatadogProvider = features => { DdSdkReactNative._enableFeaturesFromDatadogProviderAsync(features); }; static _enableFeaturesFromDatadogProviderAsync = async features => { DdSdkReactNative.features = features; DdSdkReactNative.enableFeatures(addDefaultValuesToAutoInstrumentationConfiguration(features)); }; /** * FOR INTERNAL USE ONLY. */ static _initializeFromDatadogProviderWithConfigurationAsync = async configuration => { if (!DdSdkReactNative.features) { InternalLog.log("Can't initialize Datadog, make sure the DatadogProvider component is mounted before calling this function", SdkVerbosity.WARN); return new Promise(resolve => resolve()); } return DdSdkReactNative.initializeNativeSDK(buildConfigurationFromPartialConfiguration(DdSdkReactNative.features, configuration), { initializationModeForTelemetry: 'PARTIAL' }); }; /** * Adds a set of attributes to the global context attached with all future Logs, Spans and RUM events. * To remove an attribute, set it to `undefined` in a call to `setAttributes`. * @param attributes: The global context attributes. * @returns a Promise. */ // eslint-disable-next-line @typescript-eslint/ban-types static setAttributes = async attributes => { InternalLog.log(`Setting attributes ${JSON.stringify(attributes)}`, SdkVerbosity.DEBUG); await DdSdk.setAttributes(attributes); AttributesSingleton.getInstance().setAttributes(attributes); }; /** * Set the user information. * @deprecated UserInfo id property is now mandatory (please user setUserInfo instead) * @param user: The user object (use builtin attributes: 'id', 'email', 'name', and/or any custom attribute). * @returns a Promise. */ // eslint-disable-next-line @typescript-eslint/ban-types static setUser = async user => { InternalLog.log(`Setting user ${JSON.stringify(user)}`, SdkVerbosity.DEBUG); await DdSdk.setUser(user); UserInfoSingleton.getInstance().setUserInfo(user); }; /** * Sets the user information. * @param id: A mandatory unique user identifier (relevant to your business domain). * @param name: The user name or alias. * @param email: The user email. * @param extraInfo: Additional information. * @returns a Promise. */ static setUserInfo = async userInfo => { InternalLog.log(`Setting user ${JSON.stringify(userInfo)}`, SdkVerbosity.DEBUG); await DdSdk.setUserInfo(userInfo); UserInfoSingleton.getInstance().setUserInfo(userInfo); }; /** * Set the user information. * @param extraUserInfo: The additional information. (To set the id, name or email please user setUserInfo). * @returns a Promise. */ static addUserExtraInfo = async extraUserInfo => { InternalLog.log(`Adding extra user info ${JSON.stringify(extraUserInfo)}`, SdkVerbosity.DEBUG); const userInfo = UserInfoSingleton.getInstance().getUserInfo(); const updatedUserInfo = { ...userInfo, extraInfo: { ...userInfo.extraInfo, ...extraUserInfo } }; await DdSdk.addUserExtraInfo(extraUserInfo); UserInfoSingleton.getInstance().setUserInfo(updatedUserInfo); }; /** * Set the tracking consent regarding the data collection. * @param trackingConsent: One of TrackingConsent values. * @returns a Promise. */ static setTrackingConsent = consent => { InternalLog.log(`Setting consent ${consent}`, SdkVerbosity.DEBUG); return DdSdk.setTrackingConsent(consent); }; /** * Clears all data that has not already been sent to Datadog servers * @returns a Promise */ static clearAllData = () => { InternalLog.log('Clearing all data', SdkVerbosity.DEBUG); return DdSdk.clearAllData(); }; static buildConfiguration = (configuration, params) => { configuration.additionalConfiguration[DdSdkReactNative.DD_SOURCE_KEY] = 'react-native'; configuration.additionalConfiguration[DdSdkReactNative.DD_SDK_VERSION] = sdkVersion; if (configuration.version) { configuration.additionalConfiguration[DdSdkReactNative.DD_VERSION] = `${configuration.version}${configuration.versionSuffix ? `-${configuration.versionSuffix}` : ''}`; } // If both version and version suffix are provided, we merge them into the version field. // To avoid adding it in again the native part, we only set it if the version isn't set. if (configuration.versionSuffix && !configuration.version) { configuration.additionalConfiguration[DdSdkReactNative.DD_VERSION_SUFFIX] = `-${configuration.versionSuffix}`; } if (reactNativeVersion) { configuration.additionalConfiguration[DdSdkReactNative.DD_REACT_NATIVE_VERSION] = `${reactNativeVersion}`; } return new DdSdkConfiguration(configuration.clientToken, configuration.env, configuration.applicationId, configuration.nativeCrashReportEnabled, adaptLongTaskThreshold(configuration.nativeLongTaskThresholdMs), adaptLongTaskThreshold(configuration.longTaskThresholdMs), configuration.sampleRate === undefined ? configuration.sessionSamplingRate : configuration.sampleRate, configuration.site, configuration.trackingConsent, configuration.additionalConfiguration, configuration.telemetrySampleRate, configuration.vitalsUpdateFrequency, configuration.uploadFrequency, configuration.batchSize, configuration.trackFrustrations, configuration.trackBackgroundEvents, configuration.customEndpoints, { initializationType: params.initializationModeForTelemetry, trackErrors: configuration.trackErrors, trackInteractions: configuration.trackInteractions, trackNetworkRequests: configuration.trackResources, // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires reactNativeVersion: require('react-native/package.json').version, // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires reactVersion: require('react/package.json').version }, configuration.nativeViewTracking, configuration.nativeInteractionTracking, configuration.verbosity, configuration.proxyConfig, configuration.serviceName, formatFirstPartyHosts(configuration.firstPartyHosts), configuration.bundleLogsWithRum, configuration.bundleLogsWithTraces, configuration.trackNonFatalAnrs, configuration.appHangThreshold, configuration.resourceTracingSamplingRate, configuration.trackWatchdogTerminations, configuration.batchProcessingLevel, configuration.initialResourceThreshold); }; static enableFeatures(configuration) { if (globalThis.__DD_RN_BABEL_PLUGIN_ENABLED__) { DdBabelInteractionTracking.config = { trackInteractions: configuration.trackInteractions, useAccessibilityLabel: configuration.useAccessibilityLabel }; } if (DdSdkReactNative.wasAutoInstrumented) { InternalLog.log("Can't auto instrument Datadog, SDK was already instrumented", SdkVerbosity.WARN); return; } if (configuration.trackInteractions && !globalThis.__DD_RN_BABEL_PLUGIN_ENABLED__) { DdRumUserInteractionTracking.startTracking({ actionNameAttribute: configuration.actionNameAttribute, useAccessibilityLabel: configuration.useAccessibilityLabel }); } if (configuration.trackResources) { DdRumResourceTracking.startTracking({ tracingSamplingRate: configuration.resourceTracingSamplingRate, firstPartyHosts: formatFirstPartyHosts(configuration.firstPartyHosts) }); } if (configuration.trackErrors) { DdRumErrorTracking.startTracking(); } if (configuration.logEventMapper) { DdLogs.registerLogEventMapper(configuration.logEventMapper); } if (configuration.errorEventMapper) { DdRum.registerErrorEventMapper(configuration.errorEventMapper); } if (configuration.resourceEventMapper) { DdRum.registerResourceEventMapper(configuration.resourceEventMapper); } if (configuration.actionEventMapper) { DdRum.registerActionEventMapper(configuration.actionEventMapper); } DdSdkReactNative.wasAutoInstrumented = true; } } //# sourceMappingURL=DdSdkReactNative.js.map