From 440d774b686ce8710f8f5551ac878e1137de97a4 Mon Sep 17 00:00:00 2001 From: Maksym Teplyi Date: Tue, 7 Jul 2026 11:55:34 +0300 Subject: [PATCH] Issue #1327: apply resourceEventMapper to auto tracked XHR resources --- packages/core/src/DdSdkReactNative.tsx | 3 +- .../src/__tests__/DdSdkReactNative.test.tsx | 12 +- packages/core/src/rum/DdRum.ts | 55 +++++--- packages/core/src/rum/__tests__/DdRum.test.ts | 12 +- .../rum/eventMappers/resourceEventMapper.ts | 3 +- .../DdRumResourceTracking.tsx | 19 ++- .../__tests__/DdRumResourceTracking.test.ts | 64 +++++++++ .../DatadogRumResource/ResourceReporter.ts | 70 ++++++++-- .../__tests__/ResourceReporter.test.ts | 124 ++++++++++++++++++ .../internalDevResourceBlocklist.ts | 6 +- .../requestProxy/XHRProxy/XHRProxy.ts | 28 +++- .../requestProxy/interfaces/RequestProxy.ts | 4 +- 12 files changed, 346 insertions(+), 54 deletions(-) diff --git a/packages/core/src/DdSdkReactNative.tsx b/packages/core/src/DdSdkReactNative.tsx index 4c8042815..8fd9074a7 100644 --- a/packages/core/src/DdSdkReactNative.tsx +++ b/packages/core/src/DdSdkReactNative.tsx @@ -553,7 +553,8 @@ export class DdSdkReactNative { if (trackResources) { DdRumResourceTracking.startTracking({ resourceTraceSampleRate, - firstPartyHosts + firstPartyHosts, + resourceEventMapper }); } diff --git a/packages/core/src/__tests__/DdSdkReactNative.test.tsx b/packages/core/src/__tests__/DdSdkReactNative.test.tsx index 4a3902d32..682026c5b 100644 --- a/packages/core/src/__tests__/DdSdkReactNative.test.tsx +++ b/packages/core/src/__tests__/DdSdkReactNative.test.tsx @@ -676,7 +676,8 @@ describe('DdSdkReactNative', () => { match: 'something.fr', propagatorTypes: ['datadog'] } - ] + ], + resourceEventMapper: undefined }); }); @@ -835,6 +836,15 @@ describe('DdSdkReactNative', () => { await DdRum.stopResource('key', 200, 'xhr', 22, {}, 345); // THEN + expect(NativeModules.DdRum.startResource).toHaveBeenCalledWith( + 'key', + 'GET', + 'https://datadoghq.com', + { + body: 'content' + }, + 234 + ); expect(NativeModules.DdRum.stopResource).toHaveBeenCalledWith( 'key', 200, diff --git a/packages/core/src/rum/DdRum.ts b/packages/core/src/rum/DdRum.ts index 9a7f15dae..0c52449ef 100644 --- a/packages/core/src/rum/DdRum.ts +++ b/packages/core/src/rum/DdRum.ts @@ -40,6 +40,7 @@ import { getTracingContext, getTracingContextForPropagators } from './instrumentation/resourceTracking/distributedTracing/distributedTracingHeaders'; +import { DdRumResourceTracking } from './instrumentation/resourceTracking/DdRumResourceTracking'; import type { DdRumType, FirstPartyHost, @@ -253,8 +254,31 @@ class DdRumWrapper implements DdRumType { context: object = {}, timestampMs: number = this.timeProvider.now() ): Promise => { + const mappedEvent = this.resourceEventMapper.applyEventMapper({ + key, + statusCode: 0, + kind: 'xhr', + size: -1, + context, + timestampMs, + resourceContext: { responseURL: url } as XMLHttpRequest + }); + /** + * The keep/drop decision is made here, where the request URL is always + * available (`responseURL` is set to `url`). When the mapper drops the + * event (non-first-party host or missing consent) the resource is never + * started, so the matching `stopResource` is a native no-op. We always + * use the original `key` for the native call so start/stop correlate, + * and only sanitize the displayed URL and context. + */ + if (!mappedEvent) { + return generateEmptyPromise(); + } + + const startUrl = mappedEvent.resourceContext?.responseURL ?? url; + InternalLog.log( - `Starting RUM Resource #${key} ${method}: ${url}`, + `Starting RUM Resource #${key} ${method}: ${startUrl}`, SdkVerbosity.DEBUG ); @@ -262,8 +286,8 @@ class DdRumWrapper implements DdRumType { this.nativeRum.startResource( key, method, - url, - encodeAttributes(context), + startUrl, + encodeAttributes(mappedEvent.context), timestampMs ) ); @@ -287,24 +311,13 @@ class DdRumWrapper implements DdRumType { timestampMs, resourceContext }); + /** + * We never drop at `stopResource`: the keep/drop decision was already + * made at `startResource`. A resource dropped there was never started, + * so this stop is a native no-op. + */ if (!mappedEvent) { - /** - * To drop the resource we call `stopResource` and pass the `_dd.drop_resource` attribute in the context. - * It will be picked up by the resource mappers we implement on the native side that will drop the resource. - * This ensures we don't have any "started" resource left in memory on the native side. - */ - return bufferVoidNativeCall(() => - this.nativeRum.stopResource( - key, - statusCode, - kind, - size, - { - '_dd.resource.drop_resource': true - }, - timestampMs - ) - ); + return generateEmptyPromise(); } InternalLog.log( @@ -507,10 +520,12 @@ class DdRumWrapper implements DdRumType { this.resourceEventMapper = generateResourceEventMapper( resourceEventMapper ); + DdRumResourceTracking.updateResourceEventMapper(resourceEventMapper); } unregisterResourceEventMapper() { this.resourceEventMapper = generateResourceEventMapper(undefined); + DdRumResourceTracking.updateResourceEventMapper(undefined); } registerActionEventMapper(actionEventMapper: ActionEventMapper) { diff --git a/packages/core/src/rum/__tests__/DdRum.test.ts b/packages/core/src/rum/__tests__/DdRum.test.ts index 7d0a3688b..e3bfb3e52 100644 --- a/packages/core/src/rum/__tests__/DdRum.test.ts +++ b/packages/core/src/rum/__tests__/DdRum.test.ts @@ -1673,7 +1673,7 @@ describe('DdRum', () => { ); }); - it('adds the drop context key to the event if the mapper returns null', async () => { + it('does not start or stop the resource if the mapper returns null', async () => { const resourceEventMapper: ResourceEventMapper = resource => { return null; }; @@ -1696,14 +1696,8 @@ describe('DdRum', () => { 245 ); - expect(NativeModules.DdRum.stopResource).toHaveBeenCalledWith( - 'key', - 200, - 'xhr', - 302, - { '_dd.resource.drop_resource': true }, - 245 - ); + expect(NativeModules.DdRum.startResource).not.toHaveBeenCalled(); + expect(NativeModules.DdRum.stopResource).not.toHaveBeenCalled(); }); }); diff --git a/packages/core/src/rum/eventMappers/resourceEventMapper.ts b/packages/core/src/rum/eventMappers/resourceEventMapper.ts index dd070be84..e43bfc744 100644 --- a/packages/core/src/rum/eventMappers/resourceEventMapper.ts +++ b/packages/core/src/rum/eventMappers/resourceEventMapper.ts @@ -18,7 +18,7 @@ type RawResource = { resourceContext: XMLHttpRequest | undefined; }; -type ResourceEvent = RawResource & AdditionalEventDataForMapper; +export type ResourceEvent = RawResource & AdditionalEventDataForMapper; type NativeResource = { key: string; @@ -27,6 +27,7 @@ type NativeResource = { size: number; context: object; timestampMs: number; + resourceContext: XMLHttpRequest | undefined; }; export type ResourceEventMapper = ( diff --git a/packages/core/src/rum/instrumentation/resourceTracking/DdRumResourceTracking.tsx b/packages/core/src/rum/instrumentation/resourceTracking/DdRumResourceTracking.tsx index 5db4153a6..fc005f65d 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/DdRumResourceTracking.tsx +++ b/packages/core/src/rum/instrumentation/resourceTracking/DdRumResourceTracking.tsx @@ -9,6 +9,7 @@ import BigInt from 'big-integer'; import { InternalLog } from '../../../InternalLog'; import { SdkVerbosity } from '../../../config/types/SdkVerbosity'; import { getGlobalInstance } from '../../../utils/singletonUtils'; +import type { ResourceEventMapper } from '../../eventMappers/resourceEventMapper'; import type { FirstPartyHost } from '../../types'; import { DistributedTracingSampling } from './distributedTracing/distributedTracingSampling'; @@ -40,10 +41,12 @@ class RumResourceTracking { */ startTracking({ resourceTraceSampleRate, - firstPartyHosts + firstPartyHosts, + resourceEventMapper }: { resourceTraceSampleRate: number; firstPartyHosts: FirstPartyHost[]; + resourceEventMapper?: ResourceEventMapper | null; }): void { // extra safety to avoid proxying the XHR class twice if (this._isTracking) { @@ -54,7 +57,8 @@ class RumResourceTracking { return; } - this._requestProxy = XHRProxy.createWithResourceReporter(); + this._requestProxy = + XHRProxy.createWithResourceReporter(resourceEventMapper); this._requestProxy.onTrackingStart({ tracingSamplingRate: resourceTraceSampleRate, firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder( @@ -99,6 +103,17 @@ class RumResourceTracking { ); } + updateResourceEventMapper( + resourceEventMapper?: ResourceEventMapper | null + ): void { + if (!this._isTracking || !this._requestProxy) { + return; + } + this._requestProxy.onTrackingUpdate({ + resourceEventMapper + }); + } + stopTracking(): void { if (this._isTracking) { this._isTracking = false; diff --git a/packages/core/src/rum/instrumentation/resourceTracking/__tests__/DdRumResourceTracking.test.ts b/packages/core/src/rum/instrumentation/resourceTracking/__tests__/DdRumResourceTracking.test.ts index f48f6fd51..aac64fd41 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/__tests__/DdRumResourceTracking.test.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/__tests__/DdRumResourceTracking.test.ts @@ -7,6 +7,7 @@ import { NativeModules } from 'react-native'; import { BufferSingleton } from '../../../../sdk/DatadogProvider/Buffer/BufferSingleton'; +import { DdRum as DdRumWrapper } from '../../../DdRum'; import { PropagatorType } from '../../../types'; import { DdRumResourceTracking } from '../DdRumResourceTracking'; import { SAMPLING_PRIORITY_HEADER_KEY } from '../distributedTracing/headers'; @@ -26,6 +27,8 @@ beforeEach(() => { }); afterEach(() => { + DdRumWrapper.unregisterResourceEventMapper(); + DdRumResourceTracking.stopTracking(); global.XMLHttpRequest = undefined; }); @@ -92,6 +95,67 @@ describe('DdRumResourceTracking', () => { expect(DdRum.stopResource).not.toHaveBeenCalled(); }); + it('applies a resource event mapper registered after tracking has started', async () => { + // GIVEN + DdRumResourceTracking.startTracking({ + resourceTraceSampleRate: 100, + firstPartyHosts: [] + }); + DdRumWrapper.registerResourceEventMapper(resource => { + return { + ...resource, + resourceContext: { + responseURL: 'https://sanitized.example.com/' + } as XMLHttpRequest + }; + }); + + // WHEN + executeRequest('https://api.example.com/users/123'); + await flushPromises(); + + // THEN + expect(DdRum.startResource).toHaveBeenCalledWith( + expect.anything(), + 'GET', + 'https://sanitized.example.com/', + expect.anything(), + expect.anything() + ); + expect(DdRum.stopResource).toHaveBeenCalledTimes(1); + }); + + it('stops applying a resource event mapper after it is unregistered', async () => { + // GIVEN + DdRumResourceTracking.startTracking({ + resourceTraceSampleRate: 100, + firstPartyHosts: [] + }); + DdRumWrapper.registerResourceEventMapper(resource => { + return { + ...resource, + resourceContext: { + responseURL: 'https://sanitized.example.com/' + } as XMLHttpRequest + }; + }); + DdRumWrapper.unregisterResourceEventMapper(); + + // WHEN + executeRequest('https://api.example.com/users/123'); + await flushPromises(); + + // THEN + expect(DdRum.startResource).toHaveBeenCalledWith( + expect.anything(), + 'GET', + 'https://api.example.com/users/123', + expect.anything(), + expect.anything() + ); + expect(DdRum.stopResource).toHaveBeenCalledTimes(1); + }); + describe('updateTrackingContext', () => { beforeEach(() => { DdRumResourceTracking.stopTracking(); diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/ResourceReporter.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/ResourceReporter.ts index abbf07513..f9920881f 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/ResourceReporter.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/ResourceReporter.ts @@ -5,32 +5,69 @@ */ import { DdRum } from '../../../../../DdRum'; +import type { + ResourceEvent, + ResourceEventMapper +} from '../../../../../eventMappers/resourceEventMapper'; import { TracingIdFormat } from '../../../distributedTracing/TracingIdentifier'; import type { RUMResource } from '../../interfaces/RumResource'; import { createTimings } from './resourceTiming'; -type ResourceMapper = (resource: RUMResource) => RUMResource | null; +export type ReportedResourceEvent = RUMResource & ResourceEvent; +type ResourceEventMapperAdapter = ( + resource: ReportedResourceEvent +) => Partial | null; +type RumResourceMapper = (resource: RUMResource) => RUMResource | null; +export type ResourceMapper = ResourceEventMapperAdapter | RumResourceMapper; export class ResourceReporter { - private mappers: ResourceMapper[]; - - constructor(resourceMappers: ResourceMapper[]) { - this.mappers = resourceMappers; + private resourceMappers: ResourceMapper[]; + private resourceEventMapper?: ResourceEventMapper | null; + + constructor( + resourceMappers: ResourceMapper[], + resourceEventMapper?: ResourceEventMapper | null + ) { + this.resourceMappers = resourceMappers; + this.resourceEventMapper = resourceEventMapper; } reportResource = (resource: RUMResource) => { - let modifiedResource: RUMResource | null = resource; + let modifiedResource = toReportedResourceEvent(resource); - for (const mapper of this.mappers) { - modifiedResource = mapper(resource); - if (modifiedResource === null) { + for (const mapper of this.getMappers()) { + const mappedResource = mapper(modifiedResource); + if (mappedResource === null) { return; } + modifiedResource = { + ...modifiedResource, + ...mappedResource + }; } - reportResource(modifiedResource); + reportResource({ + ...modifiedResource, + request: { + ...modifiedResource.request, + url: + modifiedResource.resourceContext?.responseURL ?? + modifiedResource.request.url + } + }); + }; + + setResourceEventMapper = ( + resourceEventMapper?: ResourceEventMapper | null + ): void => { + this.resourceEventMapper = resourceEventMapper; }; + + private getMappers = (): ResourceMapper[] => [ + ...this.resourceMappers, + ...(this.resourceEventMapper ? [this.resourceEventMapper] : []) + ]; } const formatResourceStartContext = ( @@ -50,6 +87,17 @@ const formatResourceStartContext = ( return attributes; }; +const toReportedResourceEvent = (resource: RUMResource): ReportedResourceEvent => ({ + ...resource, + statusCode: resource.response.statusCode, + kind: resource.request.kind, + size: resource.response.size, + context: {}, + timestampMs: resource.timings.stopTime, + resourceContext: resource.resourceContext, + attributes: {} +}); + const formatResourceStopContext = ( timings: RUMResource['timings'], graphqlAttributes: RUMResource['graphqlAttributes'] @@ -89,7 +137,7 @@ const formatResourceStopContext = ( return attributes; }; -const reportResource = async (resource: RUMResource) => { +const reportResource = async (resource: ReportedResourceEvent) => { await DdRum.startResource( resource.key, resource.request.method, diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/__tests__/ResourceReporter.test.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/__tests__/ResourceReporter.test.ts index a2c147603..6f96ca934 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/__tests__/ResourceReporter.test.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/__tests__/ResourceReporter.test.ts @@ -6,6 +6,7 @@ import { NativeModules } from 'react-native'; +import type { ResourceEventMapper } from '../../../../../../eventMappers/resourceEventMapper'; import { BufferSingleton } from '../../../../../../../sdk/DatadogProvider/Buffer/BufferSingleton'; import type { RUMResource } from '../../../interfaces/RumResource'; import { ResourceReporter } from '../ResourceReporter'; @@ -67,6 +68,129 @@ describe('Resource reporter', () => { expect(DdRum.stopResource).toHaveBeenCalledTimes(1); }); + it('uses resource context response URL from resource event mapper', async () => { + // GIVEN + const sanitizeURL: ResourceEventMapper = resource => { + return { + ...resource, + resourceContext: { + responseURL: 'https://sanitized.example.com/' + } as XMLHttpRequest + }; + }; + const resourceReporter = new ResourceReporter([sanitizeURL]); + const resource = resourceMockFactory.getCustomResource({ + request: { + method: 'GET', + url: 'https://api.example.com/users/123', + kind: 'xhr' + } + }); + + // WHEN + resourceReporter.reportResource(resource); + await flushPromises(); + + // THEN + expect(DdRum.startResource).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + 'https://sanitized.example.com/', + expect.anything(), + expect.anything() + ); + expect(DdRum.stopResource).toHaveBeenCalledTimes(1); + }); + + it('builds the resource event mapper fields from the RUM resource', async () => { + // GIVEN + const inspectResourceEventMapper = jest.fn(resource => resource); + const resourceReporter = new ResourceReporter([ + inspectResourceEventMapper + ]); + const resource = resourceMockFactory.getCustomResource({ + request: { + method: 'GET', + url: 'https://api.example.com/users/123', + kind: 'xhr' + }, + response: { + statusCode: 201, + size: 1234 + }, + timings: { + startTime: 1000, + stopTime: 1500 + } + }); + + // WHEN + resourceReporter.reportResource(resource); + await flushPromises(); + + // THEN + expect(inspectResourceEventMapper).toHaveBeenCalledWith( + expect.objectContaining({ + key: resource.key, + statusCode: resource.response.statusCode, + kind: resource.request.kind, + size: resource.response.size, + context: {}, + timestampMs: resource.timings.stopTime, + attributes: {} + }) + ); + expect(DdRum.startResource).toHaveBeenCalledTimes(1); + expect(DdRum.stopResource).toHaveBeenCalledTimes(1); + }); + + it('updates the resource event mapper while keeping existing resource mappers', async () => { + // GIVEN + const setURLToGoogle = (resource: RUMResource) => { + resource.request.url = 'https://google.com/'; + return resource; + }; + const sanitizeURL: ResourceEventMapper = resource => { + return { + ...resource, + resourceContext: { + responseURL: 'https://sanitized.example.com/' + } as XMLHttpRequest + }; + }; + const resourceReporter = new ResourceReporter([setURLToGoogle]); + resourceReporter.setResourceEventMapper(sanitizeURL); + + // WHEN + resourceReporter.reportResource(resourceMockFactory.getBasicResource()); + await flushPromises(); + + // THEN + expect(DdRum.startResource).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + 'https://sanitized.example.com/', + expect.anything(), + expect.anything() + ); + + // WHEN + DdRum.startResource.mockClear(); + DdRum.stopResource.mockClear(); + resourceReporter.setResourceEventMapper(undefined); + resourceReporter.reportResource(resourceMockFactory.getBasicResource()); + await flushPromises(); + + // THEN + expect(DdRum.startResource).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + 'https://google.com/', + expect.anything(), + expect.anything() + ); + }); + it('drops the resource when a mapper returns null', async () => { // GIVEN const discardResource = (resource: RUMResource) => { diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/internalDevResourceBlocklist.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/internalDevResourceBlocklist.ts index c8dae8ef5..ac2bb130d 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/internalDevResourceBlocklist.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/DatadogRumResource/internalDevResourceBlocklist.ts @@ -4,7 +4,7 @@ * Copyright 2016-Present Datadog, Inc. */ -import type { RUMResource } from '../../interfaces/RumResource'; +import type { ResourceMapper } from './ResourceReporter'; /** * Expo sends all console.* calls to the packager. As we log all API calls @@ -36,8 +36,8 @@ const internalDevResourceBlocklist: RegExp[] = [ * @param resource RUMResource */ export const filterDevResource = ( - resource: RUMResource -): RUMResource | null => { + resource: Parameters[0] +): Parameters[0] | null => { if (__DEV__) { for (const resourceRegex of internalDevResourceBlocklist) { if (resourceRegex.test(resource.request.url)) { diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts index 4f42292d7..02b63d069 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts @@ -27,13 +27,16 @@ import { DATADOG_GRAPH_QL_PAYLOAD_HEADER, DATADOG_GRAPH_QL_VARIABLES_HEADER } from '../../graphql/graphqlHeaders'; +import type { ResourceEventMapper } from '../../../../eventMappers/resourceEventMapper'; import { extractGraphQLErrors } from '../../graphql/graphqlUtils'; import { DATADOG_BAGGAGE_HEADER, isDatadogCustomHeader } from '../../headers'; import type { RequestProxyOptions } from '../interfaces/RequestProxy'; import { RequestProxy } from '../interfaces/RequestProxy'; import type { DdRumResourceGraphqlAttributes } from '../interfaces/RumResource'; -import { ResourceReporter } from './DatadogRumResource/ResourceReporter'; +import { + ResourceReporter +} from './DatadogRumResource/ResourceReporter'; import { filterDevResource } from './DatadogRumResource/internalDevResourceBlocklist'; import { URLHostParser } from './URLHostParser'; import { formatBaggageHeader } from './baggageHeaderUtils'; @@ -78,10 +81,15 @@ export class XHRProxy extends RequestProxy { this.providers = providers; } - static createWithResourceReporter() { + static createWithResourceReporter( + resourceEventMapper?: ResourceEventMapper | null + ) { return new XHRProxy({ xhrType: XMLHttpRequest, - resourceReporter: new ResourceReporter([filterDevResource]) + resourceReporter: new ResourceReporter( + [filterDevResource], + resourceEventMapper + ) }); } @@ -101,11 +109,21 @@ export class XHRProxy extends RequestProxy { this.context = null; }; - onTrackingUpdate = (options: { tracingSamplingRate: number }) => { + onTrackingUpdate = (options: { + tracingSamplingRate?: number; + resourceEventMapper?: ResourceEventMapper | null; + }) => { if (this.context === null) { return; } - this.context.tracingSamplingRate = options.tracingSamplingRate; + if (options.tracingSamplingRate !== undefined) { + this.context.tracingSamplingRate = options.tracingSamplingRate; + } + if ('resourceEventMapper' in options) { + this.providers.resourceReporter.setResourceEventMapper( + options.resourceEventMapper + ); + } }; } diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/interfaces/RequestProxy.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/interfaces/RequestProxy.ts index 37abc1eec..75ec1c6ef 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/interfaces/RequestProxy.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/interfaces/RequestProxy.ts @@ -5,6 +5,7 @@ */ import type { PropagatorType } from '../../../../types'; +import type { ResourceEventMapper } from '../../../../eventMappers/resourceEventMapper'; export interface RequestProxyOptions { tracingSamplingRate: number; @@ -20,6 +21,7 @@ export abstract class RequestProxy { abstract onTrackingStart: (context: RequestProxyOptions) => void; abstract onTrackingStop: () => void; abstract onTrackingUpdate: (context: { - tracingSamplingRate: number; + tracingSamplingRate?: number; + resourceEventMapper?: ResourceEventMapper | null; }) => void; }