Skip to content

Commit 3825259

Browse files
Merge branch 'staging-38' into fix-merge-aedeef16b6-into-staging-38
2 parents 429f651 + f5a0dea commit 3825259

28 files changed

+396
-217
lines changed

packages/core/src/domain/telemetry/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type { Telemetry } from './telemetry'
1+
export type { Telemetry, SampleRateByMetric } from './telemetry'
22
export {
33
TelemetryService,
44
addTelemetryDebug,

packages/core/src/domain/telemetry/telemetry.spec.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import {
2020
startTelemetryCollection,
2121
addTelemetryMetrics,
2222
addTelemetryDebug,
23+
type SampleRateByMetric,
2324
} from './telemetry'
2425
import type { TelemetryEvent } from './telemetryEvent.types'
2526
import { StatusType, TelemetryType } from './rawTelemetryEvent.types'
2627

2728
const NETWORK_METRICS_KIND = 'Network metrics'
2829
const PERFORMANCE_METRICS_KIND = 'Performance metrics'
2930

30-
function startAndSpyTelemetry(configuration?: Partial<Configuration>) {
31+
function startAndSpyTelemetry(configuration?: Partial<Configuration>, sampleRateByMetric: SampleRateByMetric = {}) {
3132
const observable = new Observable<TelemetryEvent & Context>()
3233

3334
const events: TelemetryEvent[] = []
@@ -42,7 +43,8 @@ function startAndSpyTelemetry(configuration?: Partial<Configuration>) {
4243
...configuration,
4344
} as Configuration,
4445
hooks,
45-
observable
46+
observable,
47+
sampleRateByMetric
4648
)
4749

4850
return {
@@ -157,7 +159,10 @@ describe('telemetry', () => {
157159

158160
describe('addTelemetryMetrics', () => {
159161
it('should collect metrics when sampled', async () => {
160-
const { getTelemetryEvents } = startAndSpyTelemetry({ telemetrySampleRate: 100 })
162+
const { getTelemetryEvents } = startAndSpyTelemetry(
163+
{ telemetrySampleRate: 100 },
164+
{ [PERFORMANCE_METRICS_KIND]: 100 }
165+
)
161166

162167
addTelemetryMetrics(PERFORMANCE_METRICS_KIND, { speed: 1000 })
163168

@@ -172,8 +177,22 @@ describe('telemetry', () => {
172177
])
173178
})
174179

175-
it('should not notify metrics when not sampled', async () => {
176-
const { getTelemetryEvents } = startAndSpyTelemetry({ telemetrySampleRate: 0 })
180+
it('should not notify metrics when telemetry not sampled', async () => {
181+
const { getTelemetryEvents } = startAndSpyTelemetry(
182+
{ telemetrySampleRate: 0 },
183+
{ [PERFORMANCE_METRICS_KIND]: 100 }
184+
)
185+
186+
addTelemetryMetrics(PERFORMANCE_METRICS_KIND, { speed: 1000 })
187+
188+
expect(await getTelemetryEvents()).toEqual([])
189+
})
190+
191+
it('should not notify metrics when metric not sampled', async () => {
192+
const { getTelemetryEvents } = startAndSpyTelemetry(
193+
{ telemetrySampleRate: 100 },
194+
{ [PERFORMANCE_METRICS_KIND]: 0 }
195+
)
177196

178197
addTelemetryMetrics(PERFORMANCE_METRICS_KIND, { speed: 1000 })
179198

packages/core/src/domain/telemetry/telemetry.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ export const enum TelemetryService {
5959
export interface Telemetry {
6060
stop: () => void
6161
enabled: boolean
62+
enabledMetrics: { [metricName: string]: boolean }
63+
}
64+
65+
export interface SampleRateByMetric {
66+
[metricName: string]: number
6267
}
6368

6469
const TELEMETRY_EXCLUDED_SITES: string[] = [INTAKE_SITE_US1_FED]
@@ -78,25 +83,34 @@ export function startTelemetry(
7883
hooks: AbstractHooks,
7984
reportError: (error: RawError) => void,
8085
pageMayExitObservable: Observable<PageMayExitEvent>,
81-
createEncoder: (streamId: DeflateEncoderStreamId) => Encoder
86+
createEncoder: (streamId: DeflateEncoderStreamId) => Encoder,
87+
sampleRateByMetric: SampleRateByMetric = {}
8288
): Telemetry {
8389
const observable = new Observable<TelemetryEvent & Context>()
8490

8591
const { stop } = startTelemetryTransport(configuration, reportError, pageMayExitObservable, createEncoder, observable)
8692

87-
const { enabled } = startTelemetryCollection(telemetryService, configuration, hooks, observable)
93+
const { enabled, enabledMetrics } = startTelemetryCollection(
94+
telemetryService,
95+
configuration,
96+
hooks,
97+
observable,
98+
sampleRateByMetric
99+
)
88100

89101
return {
90102
stop,
91103
enabled,
104+
enabledMetrics,
92105
}
93106
}
94107

95108
export function startTelemetryCollection(
96109
telemetryService: TelemetryService,
97110
configuration: Configuration,
98111
hooks: AbstractHooks,
99-
observable: Observable<TelemetryEvent & Context>
112+
observable: Observable<TelemetryEvent & Context>,
113+
sampleRateByMetric: SampleRateByMetric
100114
) {
101115
const alreadySentEventsByKind: Record<string, Set<string>> = {}
102116

@@ -109,10 +123,18 @@ export function startTelemetryCollection(
109123
[TelemetryType.USAGE]: telemetryEnabled && performDraw(configuration.telemetryUsageSampleRate),
110124
}
111125

126+
const telemetryEnabledPerMetrics: { [metricName: string]: boolean } = {}
127+
Object.keys(sampleRateByMetric).forEach((metricName) => {
128+
telemetryEnabledPerMetrics[metricName] = telemetryEnabled && performDraw(sampleRateByMetric[metricName])
129+
})
130+
112131
const runtimeEnvInfo = getRuntimeEnvInfo()
113132
const telemetryObservable = getTelemetryObservable()
114133
telemetryObservable.subscribe(({ rawEvent, kind }) => {
115-
if (!telemetryEnabledPerType[rawEvent.type!]) {
134+
if (
135+
!telemetryEnabledPerType[rawEvent.type!] ||
136+
(kind in telemetryEnabledPerMetrics && !telemetryEnabledPerMetrics[kind])
137+
) {
116138
return
117139
}
118140

@@ -154,6 +176,7 @@ export function startTelemetryCollection(
154176

155177
return {
156178
enabled: telemetryEnabled,
179+
enabledMetrics: telemetryEnabledPerMetrics,
157180
}
158181

159182
function toTelemetryEvent(

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type {
4040
TelemetryUsageEvent,
4141
RawTelemetryUsage,
4242
RawTelemetryUsageFeature,
43+
SampleRateByMetric,
4344
} from './domain/telemetry'
4445
export {
4546
startTelemetry,

packages/core/src/tools/experimentalFeatures.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { objectHasValue } from './utils/objectUtils'
1616
export enum ExperimentalFeature {
1717
TRACK_INTAKE_REQUESTS = 'track_intake_requests',
1818
WRITABLE_RESOURCE_GRAPHQL = 'writable_resource_graphql',
19-
EARLY_REQUEST_COLLECTION = 'early_request_collection',
2019
USE_TREE_WALKER_FOR_ACTION_NAME = 'use_tree_walker_for_action_name',
2120
GRAPHQL_TRACKING = 'graphql_tracking',
2221
FEATURE_OPERATION_VITAL = 'feature_operation_vital',

packages/rum-core/src/boot/rumPublicApi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
Account,
1414
RumInternalContext,
1515
Telemetry,
16+
SampleRateByMetric,
1617
} from '@datadog/browser-core'
1718
import {
1819
ContextManagerMethod,
@@ -473,6 +474,7 @@ export interface RecorderApi {
473474
isRecording: () => boolean
474475
getReplayStats: (viewId: string) => ReplayStats | undefined
475476
getSessionReplayLink: () => string | undefined
477+
getTelemetrySampleRateByMetric: (configuration: RumConfiguration) => SampleRateByMetric | undefined
476478
}
477479

478480
export interface ProfilerApi {

packages/rum-core/src/boot/startRum.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ import { startRumEventBridge } from '../transport/startRumEventBridge'
3535
import { startUrlContexts } from '../domain/contexts/urlContexts'
3636
import { createLocationChangeObservable } from '../browser/locationChangeObservable'
3737
import type { RumConfiguration } from '../domain/configuration'
38+
import { REMOTE_CONFIGURATION_METRIC_NAME } from '../domain/configuration'
3839
import type { ViewOptions } from '../domain/view/trackViews'
3940
import { startFeatureFlagContexts } from '../domain/contexts/featureFlagContext'
40-
import { startCustomerDataTelemetry } from '../domain/startCustomerDataTelemetry'
41+
import { startCustomerDataTelemetry, CUSTOMER_DATA_METRIC_NAME } from '../domain/startCustomerDataTelemetry'
4142
import type { PageStateHistory } from '../domain/contexts/pageStateHistory'
4243
import { startPageStateHistory } from '../domain/contexts/pageStateHistory'
4344
import { startDisplayContext } from '../domain/contexts/displayContext'
@@ -94,13 +95,20 @@ export function startRum(
9495
})
9596
cleanupTasks.push(() => pageMayExitSubscription.unsubscribe())
9697

98+
const sampleRateByMetric = {
99+
[CUSTOMER_DATA_METRIC_NAME]: configuration.customerDataTelemetrySampleRate,
100+
[REMOTE_CONFIGURATION_METRIC_NAME]: configuration.remoteConfigurationTelemetrySampleRate,
101+
...recorderApi.getTelemetrySampleRateByMetric(configuration),
102+
}
103+
97104
const telemetry = startTelemetry(
98105
TelemetryService.RUM,
99106
configuration,
100107
hooks,
101108
reportError,
102109
pageMayExitObservable,
103-
createEncoder
110+
createEncoder,
111+
sampleRateByMetric
104112
)
105113
cleanupTasks.push(telemetry.stop)
106114

@@ -118,7 +126,7 @@ export function startRum(
118126
createEncoder
119127
)
120128
cleanupTasks.push(() => batch.stop())
121-
startCustomerDataTelemetry(configuration, telemetry, lifeCycle, batch.flushController.flushObservable)
129+
startCustomerDataTelemetry(telemetry, lifeCycle, batch.flushController.flushObservable)
122130
} else {
123131
startRumEventBridge(lifeCycle)
124132
}

packages/rum-core/src/domain/configuration/configuration.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ describe('serializeRumConfiguration', () => {
591591
trackResources: true,
592592
trackLongTasks: true,
593593
trackBfcacheViews: true,
594+
trackEarlyRequests: true,
594595
remoteConfigurationId: '123',
595596
remoteConfigurationProxy: 'config',
596597
plugins: [{ name: 'foo', getConfigurationTelemetry: () => ({ bar: true }) }],
@@ -642,6 +643,7 @@ describe('serializeRumConfiguration', () => {
642643
track_resources: true,
643644
track_long_task: true,
644645
track_bfcache_views: true,
646+
track_early_requests: true,
645647
use_worker_url: true,
646648
compress_intake_requests: true,
647649
plugins: [{ name: 'foo', bar: true }],

packages/rum-core/src/domain/configuration/configuration.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ export interface RumInitConfiguration extends InitConfiguration {
198198
*/
199199
trackLongTasks?: boolean | undefined
200200

201+
/**
202+
* Enables early request collection before resource timing entries are available.
203+
*
204+
* @category Data Collection
205+
* @defaultValue false
206+
*/
207+
trackEarlyRequests?: boolean | undefined
208+
201209
/**
202210
* List of plugins to enable. The plugins API is unstable and experimental, and may change without
203211
* notice. Please use only plugins provided by Datadog matching the version of the SDK you are
@@ -258,10 +266,12 @@ export interface RumConfiguration extends Configuration {
258266
trackResources: boolean
259267
trackLongTasks: boolean
260268
trackBfcacheViews: boolean
269+
trackEarlyRequests: boolean
261270
subdomain?: string
262271
customerDataTelemetrySampleRate: number
263272
initialViewMetricsTelemetrySampleRate: number
264273
replayTelemetrySampleRate: number
274+
remoteConfigurationTelemetrySampleRate: number
265275
traceContextInjection: TraceContextInjection
266276
plugins: RumPlugin[]
267277
trackFeatureFlagsForEvents: FeatureFlagsForEvents[]
@@ -330,6 +340,7 @@ export function validateAndBuildRumConfiguration(
330340
trackResources: !!(initConfiguration.trackResources ?? true),
331341
trackLongTasks: !!(initConfiguration.trackLongTasks ?? true),
332342
trackBfcacheViews: !!initConfiguration.trackBfcacheViews,
343+
trackEarlyRequests: !!initConfiguration.trackEarlyRequests,
333344
subdomain: initConfiguration.subdomain,
334345
defaultPrivacyLevel: objectHasValue(DefaultPrivacyLevel, initConfiguration.defaultPrivacyLevel)
335346
? initConfiguration.defaultPrivacyLevel
@@ -338,6 +349,7 @@ export function validateAndBuildRumConfiguration(
338349
customerDataTelemetrySampleRate: 1,
339350
initialViewMetricsTelemetrySampleRate: 1,
340351
replayTelemetrySampleRate: 1,
352+
remoteConfigurationTelemetrySampleRate: 1,
341353
traceContextInjection: objectHasValue(TraceContextInjection, initConfiguration.traceContextInjection)
342354
? initConfiguration.traceContextInjection
343355
: TraceContextInjection.SAMPLED,
@@ -468,6 +480,7 @@ export function serializeRumConfiguration(configuration: RumInitConfiguration) {
468480
track_resources: configuration.trackResources,
469481
track_long_task: configuration.trackLongTasks,
470482
track_bfcache_views: configuration.trackBfcacheViews,
483+
track_early_requests: configuration.trackEarlyRequests,
471484
plugins: configuration.plugins?.map((plugin) => ({
472485
name: plugin.name,
473486
...plugin.getConfigurationTelemetry?.(),

0 commit comments

Comments
 (0)