Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const datadogConfiguration = new DatadogProviderConfiguration(
applicationId: '<RUM_APPLICATION_ID>',
trackInteractions: true, // track User interactions (e.g.: Tap on buttons. You can use 'accessibilityLabel' element property to give tap action the name, otherwise element type will be reported)
trackResources: true, // track XHR Resources
trackFetchResources: true, // Optional: also track requests made with the global Expo Fetch implementation
trackFrustrations: true, // track Frustrations
trackErrors: true, // track errors
nativeCrashReportEnabled: true, // Optional: enable or disable native crash reports
Expand Down Expand Up @@ -80,6 +81,15 @@ export default function App() {
}
```

`trackFetchResources` tracks calls made through the Expo-installed global
`fetch`. Direct imports retained from `expo/fetch` are not intercepted. XHR
tracking remains enabled for clients such as axios.

GraphQL error extraction (via `DatadogLink({ trackErrors: true })`) for
requests made through `expo/fetch` requires Expo SDK 56 or later, as older
versions of `expo/fetch` do not implement `Response.clone()`. On earlier
versions, GraphQL metadata is still reported, but response errors are not.

### Track view navigation

Because React Native offers a wide range of libraries to create screen navigation, by default only manual View tracking is supported. You can manually start and stop a View using the following `startView()` and `stopView` methods.
Expand Down
4 changes: 4 additions & 0 deletions packages/core/datadog-configuration.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@
"description": "Track React Native resources.",
"type": "boolean"
},
"trackFetchResources": {
"description": "Track requests made with supported native Fetch implementations, such as the global Fetch installed by Expo. Only applies when resource tracking is enabled.",
"type": "boolean"
},
"trackErrors": {
"description": "Track React Native errors.",
"type": "boolean"
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/DdSdkReactNative.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,9 @@ export class DdSdkReactNative {
const trackResources =
configuration.rumConfiguration?.trackResources ||
RUM_DEFAULTS.trackResources;
const trackFetchResources =
configuration.rumConfiguration?.trackFetchResources ??
RUM_DEFAULTS.trackFetchResources;
const trackErrors =
configuration.rumConfiguration?.trackErrors ||
RUM_DEFAULTS.trackErrors;
Expand Down Expand Up @@ -553,7 +556,8 @@ export class DdSdkReactNative {
if (trackResources) {
DdRumResourceTracking.startTracking({
resourceTraceSampleRate,
firstPartyHosts
firstPartyHosts,
trackFetchResources
});
}

Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/__tests__/DdSdkReactNative.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,9 @@ describe('DdSdkReactNative', () => {
configuration.rumConfiguration = new RumConfiguration(
fakeAppId,
false,
true
true,
false,
{ trackFetchResources: true }
);
configuration.rumConfiguration.resourceTraceSampleRate = 42;
configuration.rumConfiguration.firstPartyHosts = [
Expand Down Expand Up @@ -676,7 +678,8 @@ describe('DdSdkReactNative', () => {
match: 'something.fr',
propagatorTypes: ['datadog']
}
]
],
trackFetchResources: true
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('DdSdkReactNativeConfiguration', () => {
"telemetrySampleRate": 20,
"trackBackgroundEvents": false,
"trackErrors": false,
"trackFetchResources": false,
"trackFrustrations": true,
"trackInteractions": false,
"trackMemoryWarnings": true,
Expand Down Expand Up @@ -217,6 +218,7 @@ describe('DdSdkReactNativeConfiguration', () => {
"telemetrySampleRate": 20,
"trackBackgroundEvents": true,
"trackErrors": true,
"trackFetchResources": false,
"trackFrustrations": true,
"trackInteractions": true,
"trackMemoryWarnings": true,
Expand Down Expand Up @@ -320,6 +322,7 @@ describe('DdSdkReactNativeConfiguration', () => {
"telemetrySampleRate": 0,
"trackBackgroundEvents": false,
"trackErrors": false,
"trackFetchResources": false,
"trackFrustrations": false,
"trackInteractions": false,
"trackMemoryWarnings": false,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/config/FileBasedConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ export const getJSONConfiguration = (
trackInteractions:
configuration.rumConfiguration.trackInteractions,
trackResources: configuration.rumConfiguration.trackResources,
trackFetchResources:
configuration.rumConfiguration.trackFetchResources,
trackErrors: configuration.rumConfiguration.trackErrors,
nativeLongTaskThresholdMs:
configuration.rumConfiguration.nativeLongTaskThresholdMs,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/FileBasedConfiguration.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface JsonConfiguration extends CoreConfigurationOptions {
useAccessibilityLabel?: boolean;
trackInteractions?: boolean;
trackResources?: boolean;
trackFetchResources?: boolean;
trackErrors?: boolean;
longTaskThresholdMs?: number;
actionNameAttribute?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('FileBasedConfiguration', () => {
"telemetrySampleRate": 20,
"trackBackgroundEvents": true,
"trackErrors": true,
"trackFetchResources": true,
"trackFrustrations": true,
"trackInteractions": true,
"trackMemoryWarnings": false,
Expand Down Expand Up @@ -179,6 +180,7 @@ describe('FileBasedConfiguration', () => {
"telemetrySampleRate": 20,
"trackBackgroundEvents": false,
"trackErrors": true,
"trackFetchResources": false,
"trackFrustrations": true,
"trackInteractions": true,
"trackMemoryWarnings": true,
Expand Down Expand Up @@ -243,6 +245,7 @@ describe('FileBasedConfiguration', () => {
"telemetrySampleRate": 20,
"trackBackgroundEvents": false,
"trackErrors": false,
"trackFetchResources": false,
"trackFrustrations": true,
"trackInteractions": false,
"trackMemoryWarnings": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"useAccessibilityLabel": false,
"trackInteractions": true,
"trackResources": true,
"trackFetchResources": true,
"trackErrors": true,
"longTaskThresholdMs": 44,
"trackNonFatalAnrs": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type AutoInstrumentationConfiguration = {
readonly rumConfiguration: {
readonly trackInteractions: boolean;
readonly trackResources: boolean;
readonly trackFetchResources?: boolean;
readonly trackErrors: boolean;
readonly useAccessibilityLabel?: boolean;
readonly actionNameAttribute?: string;
Expand All @@ -45,6 +46,7 @@ export type AutoInstrumentationParameters = {
readonly useAccessibilityLabel: boolean;
readonly trackInteractions: boolean;
readonly trackResources: boolean;
readonly trackFetchResources: boolean;
readonly trackErrors: boolean;
readonly actionNameAttribute?: string;
readonly resourceTraceSampleRate?: number;
Expand Down Expand Up @@ -81,6 +83,9 @@ export const addDefaultValuesToAutoInstrumentationConfiguration = (
trackResources:
features.rumConfiguration.trackResources ??
RUM_DEFAULTS.trackResources,
trackFetchResources:
features.rumConfiguration.trackFetchResources ??
RUM_DEFAULTS.trackFetchResources,
trackErrors:
features.rumConfiguration.trackErrors ??
RUM_DEFAULTS.trackErrors,
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/config/features/RumConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const DEFAULTS = {
telemetrySampleRate: 20.0,
trackBackgroundEvents: false,
trackErrors: false,
trackFetchResources: false,
trackFrustrations: true,
trackInteractions: false,
trackMemoryWarnings: true,
Expand Down Expand Up @@ -103,6 +104,9 @@ export class RumConfiguration implements RumConfigurationType {
// Track Background Events Enabled
public trackBackgroundEvents: boolean = DEFAULTS.trackBackgroundEvents;

// Track native Fetch resources
public trackFetchResources: boolean = DEFAULTS.trackFetchResources;

// Track Frustrations Enabled
public trackFrustrations: boolean = DEFAULTS.trackFrustrations;

Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/config/features/RumConfiguration.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ export interface RumConfigurationOptions {
*/
errorEventMapper?: ErrorEventMapper | null;

/**
* Enables tracking of requests made with native Fetch implementations,
* such as the global Fetch installed by Expo.
*
* This option only takes effect when resource tracking is enabled.
*/
trackFetchResources?: boolean;

/**
* List of backend hosts used to enable tracing.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { FirstPartyHost } from '../../types';

import { DistributedTracingSampling } from './distributedTracing/distributedTracingSampling';
import { firstPartyHostsRegexMapBuilder } from './distributedTracing/firstPartyHosts';
import { FetchProxy } from './requestProxy/FetchProxy/FetchProxy';
import { XHRProxy } from './requestProxy/XHRProxy/XHRProxy';
import type { RequestProxy } from './requestProxy/interfaces/RequestProxy';

Expand All @@ -24,7 +25,7 @@ const RUM_RESOURCE_TRACKING_MODULE =
*/
class RumResourceTracking {
private _isTracking = false;
private _requestProxy: RequestProxy | null = null;
private _requestProxies: RequestProxy[] = [];
private _maxSampledTraceId: BigInt.BigInteger | null = null;

get isTracking(): boolean {
Expand All @@ -40,33 +41,55 @@ class RumResourceTracking {
*/
startTracking({
resourceTraceSampleRate,
firstPartyHosts
firstPartyHosts,
trackFetchResources = false
}: {
resourceTraceSampleRate: number;
firstPartyHosts: FirstPartyHost[];
trackFetchResources?: boolean;
}): void {
// extra safety to avoid proxying the XHR class twice
if (this._isTracking) {
InternalLog.log(
'Datadog SDK is already tracking XHR resources',
'Datadog SDK is already tracking resources',
SdkVerbosity.WARN
);
return;
}

this._requestProxy = XHRProxy.createWithResourceReporter();
this._requestProxy.onTrackingStart({
const requestProxyOptions = {
tracingSamplingRate: resourceTraceSampleRate,
firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder(
firstPartyHosts
)
});
};

const xhrProxy = XHRProxy.createWithResourceReporter();
xhrProxy.onTrackingStart(requestProxyOptions);
this._requestProxies.push(xhrProxy);

InternalLog.log(
'Datadog SDK is tracking XHR resources',
SdkVerbosity.INFO
);

if (trackFetchResources) {
if (typeof globalThis.fetch !== 'function') {
InternalLog.log(
'Datadog SDK did not install Fetch resource tracking because global Fetch is not available',
SdkVerbosity.INFO
);
} else {
const fetchProxy = FetchProxy.createWithResourceReporter();
fetchProxy.onTrackingStart(requestProxyOptions);
this._requestProxies.push(fetchProxy);
InternalLog.log(
'Datadog SDK is tracking Fetch resources',
SdkVerbosity.INFO
);
}
}

this._isTracking = true;
DistributedTracingSampling.setResourceTraceSampleRate(
resourceTraceSampleRate
Expand All @@ -85,11 +108,13 @@ class RumResourceTracking {
}: {
resourceTraceSampleRate: number;
}): void {
if (!this._isTracking || !this._requestProxy) {
if (!this._isTracking) {
return;
}
this._requestProxy.onTrackingUpdate({
tracingSamplingRate: resourceTraceSampleRate
this._requestProxies.forEach(requestProxy => {
requestProxy.onTrackingUpdate({
tracingSamplingRate: resourceTraceSampleRate
});
});
// Keep the distributed-tracing sampler's max-trace-id in sync; the
// shouldSampleTrace path consults this for rates strictly between 0
Expand All @@ -102,10 +127,10 @@ class RumResourceTracking {
stopTracking(): void {
if (this._isTracking) {
this._isTracking = false;
if (this._requestProxy) {
this._requestProxy.onTrackingStop();
}
this._requestProxy = null;
this._requestProxies.forEach(requestProxy =>
requestProxy.onTrackingStop()
);
this._requestProxies = [];
this._maxSampledTraceId = null;
}
}
Expand Down
Loading