Skip to content
Merged
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
27 changes: 27 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,30 @@ bump-chrome-version-scheduled-failure:
- postmessage "#browser-sdk-deploy" "$MESSAGE_TEXT"
dependencies:
- bump-chrome-version-scheduled

########################################################################################################################
# Check expired telemetry
########################################################################################################################

check-expired-telemetry-scheduled:
stage: task
extends: .base-configuration
only:
variables:
- $TARGET_TASK_NAME == "check-expired-telemetry"
script:
- yarn
- yarn build
- MONITOR_UNTIL_COMMENT_EXPIRED_LEVEL=error yarn lint

check-expired-telemetry-scheduled-failure:
extends: .prepare_notification
only:
variables:
- $TARGET_TASK_NAME == "check-expired-telemetry"
when: on_failure
script:
- 'MESSAGE_TEXT=":fire: [*$CI_PROJECT_NAME*] <$BUILD_URL|Expired telemetry detected> :fire:"'
- postmessage "#rum-browser-sdk-ops" "$MESSAGE_TEXT"
dependencies:
- check-expired-telemetry-scheduled
1 change: 1 addition & 0 deletions eslint-local-rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ module.exports = {
'disallow-non-scripts': require('./disallowNonScripts'),
'enforce-prod-deps-imports': require('./enforceProdDepsImports.js'),
'secure-command-execution': require('./secureCommandExecution'),
...require('./monitorUntilCommentRules'),
}
62 changes: 62 additions & 0 deletions eslint-local-rules/monitorUntilCommentRules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const METHODS_TO_CHECK = ['addTelemetryDebug', 'addTelemetryMetrics']
const MONITOR_COMMENT_FORMAT = /^\s*monitor-until: (\d{4}-\d{2}-\d{2}|forever)/

module.exports = {
'enforce-monitor-until-comment': {
meta: {
docs: {
description:
'Force to specify an expiration date to telemetry debug and metrics events in order to clean them regularly',
recommended: false,
},
schema: [],
},
create(context) {
const sourceCode = context.getSourceCode()

return {
CallExpression(node) {
const methodName = node.callee.name
if (!METHODS_TO_CHECK.includes(methodName)) {
return
}

const monitorComment = sourceCode
.getCommentsBefore(node)
.find((comment) => MONITOR_COMMENT_FORMAT.test(comment.value))

if (!monitorComment) {
context.report(node, 'Missing `// monitor-until: YYYY-MM-DD` or `// monitor-until: forever` comment')
}
},
}
},
},
'monitor-until-comment-expired': {
meta: {
docs: {
description: 'Report expired monitor-until comments',
recommended: false,
},
schema: [],
},
create(context) {
return {
Program() {
const now = new Date()
const comments = context.getSourceCode().getAllComments()
comments.forEach((comment) => {
const monitorCommentMatch = comment.value.match(MONITOR_COMMENT_FORMAT)
if (!monitorCommentMatch || monitorCommentMatch[1] === 'forever') {
return
}

if (new Date(monitorCommentMatch[1]) < now) {
context.report(comment, `Expired: ${comment.value}`)
}
})
},
}
},
},
}
3 changes: 3 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import globals from 'globals'
import eslintLocalRules from './eslint-local-rules/index.js'

const SPEC_FILES = '**/*.{spec,specHelper}.{ts,tsx,js}'
const MONITOR_UNTIL_COMMENT_EXPIRED_LEVEL = process.env.MONITOR_UNTIL_COMMENT_EXPIRED_LEVEL || 'warn'

// eslint-disable-next-line import/no-default-export
export default tseslint.config(
Expand Down Expand Up @@ -357,6 +358,8 @@ export default tseslint.config(
files: ['packages/*/src/**/*.ts'],
ignores: [SPEC_FILES],
rules: {
'local-rules/enforce-monitor-until-comment': 'error',
'local-rules/monitor-until-comment-expired': MONITOR_UNTIL_COMMENT_EXPIRED_LEVEL,
'local-rules/disallow-side-effects': 'error',
'local-rules/disallow-zone-js-patched-values': 'error',
'local-rules/disallow-url-constructor-patched-values': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/domain/allowedTrackingOrigins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function isAllowedTrackingOrigins(
display.warn(WARN_DOES_NOT_HAVE_ALLOWED_TRACKING_ORIGIN)

const extensionUrl = extractExtensionUrlFromStack(errorStack)
// monitor-until: 2026-01-01
addTelemetryDebug(WARN_DOES_NOT_HAVE_ALLOWED_TRACKING_ORIGIN, {
extensionUrl: extensionUrl || 'unknown',
})
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/domain/session/sessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ function trackResume(configuration: Configuration, cb: () => void) {

async function reportUnexpectedSessionState() {
const rawSession = retrieveSessionCookie()
// monitor-until: forever, could be handy to troubleshoot issues until session manager rework
addTelemetryDebug('Unexpected session state', {
session: rawSession,
isSyntheticsTest: isSyntheticsTest(),
Expand Down Expand Up @@ -212,6 +213,7 @@ function detectSessionIdChange(configuration: Configuration, initialSessionState
const time = dateNow() - sdkInitTime
getSessionCookies()
.then((cookie) => {
// monitor-until: 2025-10-01, after investigation done
addTelemetryDebug('Session cookie changed', {
time,
session_age: sessionAge,
Expand Down
4 changes: 0 additions & 4 deletions packages/core/src/domain/session/sessionStoreOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { setTimeout } from '../../tools/timer'
import { generateUUID } from '../../tools/utils/stringUtils'
import type { TimeStamp } from '../../tools/utils/timeUtils'
import { elapsed, ONE_SECOND, timeStampNow } from '../../tools/utils/timeUtils'
import { addTelemetryDebug } from '../telemetry'
import type { SessionStoreStrategy } from './storeStrategies/sessionStoreStrategy'
import type { SessionState } from './sessionState'
import { expandSessionState, isSessionInExpiredState } from './sessionState'
Expand Down Expand Up @@ -46,9 +45,6 @@ export function processSessionStoreOperations(
return
}
if (isLockEnabled && numberOfRetries >= LOCK_MAX_TRIES) {
addTelemetryDebug('Aborted session operation after max lock retries', {
currentStore: retrieveStore(),
})
next(sessionStoreStrategy)
return
}
Expand Down
3 changes: 1 addition & 2 deletions packages/logs/src/boot/startLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function startLogs(
const accountContext = startAccountContext(hooks, configuration, LOGS_STORAGE_KEY)
const userContext = startUserContext(hooks, configuration, session, LOGS_STORAGE_KEY)
const globalContext = startGlobalContext(hooks, configuration, LOGS_STORAGE_KEY, false)
const { stop } = startRUMInternalContext(hooks)
startRUMInternalContext(hooks)

startNetworkErrorCollection(configuration, lifeCycle)
startRuntimeErrorCollection(configuration, lifeCycle, bufferedDataObservable)
Expand Down Expand Up @@ -114,7 +114,6 @@ export function startLogs(
userContext,
stop: () => {
cleanupTasks.forEach((task) => task())
stop()
},
}
}
33 changes: 2 additions & 31 deletions packages/logs/src/domain/contexts/rumInternalContext.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import type { RelativeTime } from '@datadog/browser-core'
import { HookNames } from '@datadog/browser-core'
import { mockSyntheticsWorkerValues, startMockTelemetry } from '@datadog/browser-core/test'
import { mockSyntheticsWorkerValues } from '@datadog/browser-core/test'
import type { Hooks } from '../hooks'
import { createHooks } from '../hooks'
import { startRUMInternalContext } from './rumInternalContext'

describe('startRUMInternalContext', () => {
let hooks: Hooks
let stopRUMInternalContext: () => void

beforeEach(() => {
hooks = createHooks()
;({ stop: stopRUMInternalContext } = startRUMInternalContext(hooks))
startRUMInternalContext(hooks)
})

afterEach(() => {
delete window.DD_RUM
delete window.DD_RUM_SYNTHETICS
stopRUMInternalContext()
})

describe('assemble hook', () => {
Expand Down Expand Up @@ -61,33 +59,6 @@ describe('startRUMInternalContext', () => {
})
expect(defaultLogsEventAttributes).toEqual({ foo: 'bar' })
})

it('adds a telemetry debug event when RUM has not been injected yet', async () => {
const telemetry = startMockTelemetry()
hooks.triggerHook(HookNames.Assemble, {
startTime: 0 as RelativeTime,
})
expect(await telemetry.getEvents()).toEqual([
jasmine.objectContaining({
message: 'Logs sent before RUM is injected by the synthetics worker',
status: 'debug',
type: 'log',
testId: 'test-id',
resultId: 'result-id',
}),
])
})

it('adds the telemetry debug event only once', async () => {
const telemetry = startMockTelemetry()
hooks.triggerHook(HookNames.Assemble, {
startTime: 0 as RelativeTime,
})
hooks.triggerHook(HookNames.Assemble, {
startTime: 0 as RelativeTime,
})
expect((await telemetry.getEvents()).length).toEqual(1)
})
})
})

Expand Down
25 changes: 1 addition & 24 deletions packages/logs/src/domain/contexts/rumInternalContext.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import type { RelativeTime, RumInternalContext } from '@datadog/browser-core'
import {
globalObject,
willSyntheticsInjectRum,
addTelemetryDebug,
getSyntheticsTestId,
getSyntheticsResultId,
HookNames,
SKIPPED,
} from '@datadog/browser-core'
import { globalObject, willSyntheticsInjectRum, HookNames, SKIPPED } from '@datadog/browser-core'
import type { Hooks } from '../hooks'

interface Rum {
Expand All @@ -21,7 +13,6 @@ interface BrowserWindow {

export function startRUMInternalContext(hooks: Hooks) {
const browserWindow = globalObject as BrowserWindow
let logsSentBeforeRumInjectionTelemetryAdded = false

hooks.register(HookNames.Assemble, ({ startTime }) => {
const internalContext = getRUMInternalContext(startTime)
Expand Down Expand Up @@ -54,25 +45,11 @@ export function startRUMInternalContext(hooks: Hooks) {
if (rumContext) {
return rumContext
}

if (willSyntheticsInjectRumResult && !logsSentBeforeRumInjectionTelemetryAdded) {
logsSentBeforeRumInjectionTelemetryAdded = true
addTelemetryDebug('Logs sent before RUM is injected by the synthetics worker', {
testId: getSyntheticsTestId(),
resultId: getSyntheticsResultId(),
})
}
}

function getInternalContextFromRumGlobal(startTime?: RelativeTime, rumGlobal?: Rum): RumInternalContext | undefined {
if (rumGlobal && rumGlobal.getInternalContext) {
return rumGlobal.getInternalContext(startTime)
}
}

return {
stop: () => {
logsSentBeforeRumInjectionTelemetryAdded = false
},
}
}
1 change: 1 addition & 0 deletions packages/logs/src/domain/reportError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function startReportError(lifeCycle: LifeCycle) {
status: StatusType.error,
},
})
// monitor-until: forever, to keep an eye on the errors reported to customers
addTelemetryDebug('Error reported to customer', { 'error.message': error.message })
}
}
1 change: 1 addition & 0 deletions packages/rum-core/src/boot/startRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export function startRum(

const reportError = (error: RawError) => {
lifeCycle.notify(LifeCycleEventType.RAW_ERROR_COLLECTED, { error })
// monitor-until: forever, to keep an eye on the errors reported to customers
addTelemetryDebug('Error reported to customer', { 'error.message': error.message })
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export async function fetchAndApplyRemoteConfiguration(
metrics
)
}
// monitor-until: forever
addTelemetryMetrics(TelemetryMetrics.REMOTE_CONFIGURATION_METRIC_NAME, { metrics: metrics.get() })
return rumInitConfiguration
}
Expand Down
1 change: 1 addition & 0 deletions packages/rum-core/src/domain/resource/requestRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function createRequestRegistry(lifeCycle: LifeCycle): RequestRegistry {
const subscription = lifeCycle.subscribe(LifeCycleEventType.REQUEST_COMPLETED, (request) => {
requests.add(request)
if (requests.size > MAX_REQUESTS) {
// monitor-until: 2026-01-01, after early request collection GA
addTelemetryDebug('Too many requests')
requests.delete(requests.values().next().value!)
}
Expand Down
2 changes: 0 additions & 2 deletions packages/rum-core/src/domain/resource/resourceUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Duration, RelativeTime } from '@datadog/browser-core'
import {
addTelemetryDebug,
elapsed,
getPathName,
isValidUrl,
Expand Down Expand Up @@ -50,7 +49,6 @@ const RESOURCE_TYPES: Array<[ResourceType, (initiatorType: string, path: string)
export function computeResourceEntryType(entry: RumPerformanceResourceTiming) {
const url = entry.name
if (!isValidUrl(url)) {
addTelemetryDebug(`Failed to construct URL for "${entry.name}"`)
return ResourceType.OTHER
}
const path = getPathName(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function sendCurrentPeriodMeasures() {
return
}

// monitor-until: forever
addTelemetryMetrics(TelemetryMetrics.CUSTOMER_DATA_METRIC_NAME, currentPeriodMeasures)
initCurrentPeriodMeasures()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function startInitialViewMetricsTelemetry(lifeCycle: LifeCycle, telemetry
// performance issues early in the page load process, and using LCP-at-page-load is a
// good fit for that use case, but it's important to be aware that this is not
// necessarily equivalent to the normal LCP metric.

// monitor-until: 2026-07-01
addTelemetryMetrics(TelemetryMetrics.INITIAL_VIEW_METRICS_TELEMETRY_NAME, {
metrics: createCoreInitialViewMetrics(
initialViewMetrics.largestContentfulPaint,
Expand Down
3 changes: 2 additions & 1 deletion packages/rum/src/boot/profilerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import type {
ProfilerApi,
Hooks,
} from '@datadog/browser-rum-core'
import { addTelemetryDebug, monitorError } from '@datadog/browser-core'
import { isSampled } from '@datadog/browser-rum-core'
import { addTelemetryDebug, monitorError } from '@datadog/browser-core'
import type { RUMProfiler } from '../domain/profiling/types'
import { isProfilingSupported } from '../domain/profiling/profilingSupported'
import { startProfilingContext } from '../domain/profiling/profilingContext'
Expand Down Expand Up @@ -53,6 +53,7 @@ export function makeProfilerApi(): ProfilerApi {
lazyLoadProfiler()
.then((createRumProfiler) => {
if (!createRumProfiler) {
// monitor-until: 2026-01-01, reconsider after profiling GA
addTelemetryDebug('[DD_RUM] Failed to lazy load the RUM Profiler')
profilingContextManager.set({ status: 'error', error_reason: 'failed-to-lazy-load' })
return
Expand Down
1 change: 1 addition & 0 deletions packages/rum/src/boot/startRecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function startRecording(

const reportError = (error: RawError) => {
lifeCycle.notify(LifeCycleEventType.RAW_ERROR_COLLECTED, { error })
// monitor-until: forever, to keep an eye on the errors reported to customers
addTelemetryDebug('Error reported to customer', { 'error.message': error.message })
}

Expand Down
Loading