Skip to content

Commit

Permalink
[REPLAY] Improve subdomain handling in replay link
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibautGeriz committed Mar 3, 2023
1 parent 1635224 commit f37d429
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 74 deletions.
12 changes: 6 additions & 6 deletions packages/rum-core/src/boot/rumPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ export interface RecorderApi {
) => void
isRecording: () => boolean
getReplayStats: (viewId: string) => ReplayStats | undefined
getReplayLink: (
getSessionReplayLink: (
configuration: RumConfiguration,
sessionManager: RumSessionManager,
viewContexts: ViewContexts,
subdomain: string
subdomain?: string
) => string | undefined
}
interface RumPublicApiOptions {
Expand All @@ -70,7 +70,7 @@ export function makeRumPublicApi(

let getInternalContextStrategy: StartRumResult['getInternalContext'] = () => undefined
let getInitConfigurationStrategy = (): InitConfiguration | undefined => undefined
let getReplayLinkStrategy: (subdomain: string) => string | undefined = () => undefined
let getSessionReplayLinkStrategy: (subdomain?: string) => string | undefined = () => undefined

let bufferApiCalls = new BoundedBuffer()
let addTimingStrategy: StartRumResult['addTiming'] = (name, time = timeStampNow()) => {
Expand Down Expand Up @@ -160,8 +160,8 @@ export function makeRumPublicApi(
userContextManager,
initialViewOptions
)
getReplayLinkStrategy = (subdomain: string) =>
recorderApi.getReplayLink(configuration, startRumResults.session, startRumResults.viewContexts, subdomain)
getSessionReplayLinkStrategy = (subdomain?: string) =>
recorderApi.getSessionReplayLink(configuration, startRumResults.session, startRumResults.viewContexts, subdomain)
;({
startView: startViewStrategy,
addAction: addActionStrategy,
Expand Down Expand Up @@ -260,7 +260,7 @@ export function makeRumPublicApi(

startSessionReplayRecording: monitor(recorderApi.start),
stopSessionReplayRecording: monitor(recorderApi.stop),
getReplayLink: monitor((subdomain = 'app') => getReplayLinkStrategy(subdomain)),
getSessionReplayLink: monitor((subdomain?: string) => getSessionReplayLinkStrategy(subdomain)),
})

return rumPublicApi
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-core/test/specHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export const noopRecorderApi: RecorderApi = {
isRecording: () => false,
onRumStart: noop,
getReplayStats: () => undefined,
getReplayLink: () => undefined,
getSessionReplayLink: () => undefined,
}

export function mockCiVisibilityWindowValues(traceId?: unknown) {
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-slim/src/entries/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const datadogRum = makeRumPublicApi(startRum, {
onRumStart: noop,
isRecording: () => false,
getReplayStats: () => undefined,
getReplayLink: () => undefined,
getSessionReplayLink: () => undefined,
})

interface BrowserWindow extends Window {
Expand Down
6 changes: 3 additions & 3 deletions packages/rum/src/boot/recorderApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
} from '@datadog/browser-rum-core'
import { LifeCycleEventType } from '@datadog/browser-rum-core'
import { getReplayStats } from '../domain/replayStats'
import { getReplayLink } from '../domain/getReplayLink'
import { getSessionReplayLink } from '../domain/getSessionReplayLink'
import { startDeflateWorker } from '../domain/segmentCollection'

import type { startRecording } from './startRecording'
Expand Down Expand Up @@ -52,7 +52,7 @@ export function makeRecorderApi(
getReplayStats: () => undefined,
onRumStart: noop,
isRecording: () => false,
getReplayLink: () => undefined,
getSessionReplayLink: () => undefined,
}
}

Expand All @@ -70,7 +70,7 @@ export function makeRecorderApi(
start: () => startStrategy(),
stop: () => stopStrategy(),
getReplayStats,
getReplayLink,
getSessionReplayLink,
onRumStart: (
lifeCycle: LifeCycle,
configuration: RumConfiguration,
Expand Down
43 changes: 0 additions & 43 deletions packages/rum/src/domain/getReplayLink.spec.ts

This file was deleted.

20 changes: 0 additions & 20 deletions packages/rum/src/domain/getReplayLink.ts

This file was deleted.

58 changes: 58 additions & 0 deletions packages/rum/src/domain/getSessionReplayLink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { RumConfiguration, ViewContexts } from '@datadog/browser-rum-core'
import { createRumSessionManagerMock } from '../../../rum-core/test/mockRumSessionManager'
import { getSessionReplayLink } from './getSessionReplayLink'

const DEFAULT_CONFIGURATION = {
site: 'datad0g.com',
} as RumConfiguration

describe('getReplayLink', () => {
it('should return undefined if there is no session', () => {
const sessionManager = createRumSessionManagerMock().setNotTracked()
const viewContexts = {} as ViewContexts

const link = getSessionReplayLink(DEFAULT_CONFIGURATION, sessionManager, viewContexts, 'app')

expect(link).toBeUndefined()
})

it('should return url without query param if no view', () => {
const sessionManager = createRumSessionManagerMock().setId('session-id-1')
const viewContexts = { findView: () => undefined } as ViewContexts

const link = getSessionReplayLink(DEFAULT_CONFIGURATION, sessionManager, viewContexts, 'app')

expect(link).toBe('https://app.datad0g.com/rum/replay/sessions/session-id-1')
})

const parameters: Array<[string, string | undefined, string]> = [
['datadoghq.com', undefined, 'app.datadoghq.com'],
['datadoghq.com', 'toto', 'toto.datadoghq.com'],
['datad0g.com', undefined, 'dd.datad0g.com'],
['datad0g.com', 'toto', 'toto.datad0g.com'],
['us3.datadoghq.com', undefined, 'us3.datadoghq.com'],
['us3.datadoghq.com', 'toto', 'toto.us3.datadoghq.com'],
['us5.datadoghq.com', undefined, 'us5.datadoghq.com'],
['us5.datadoghq.com', 'toto', 'toto.us5.datadoghq.com'],
]

parameters.forEach(([site, subdomain, host]) => {
it(`should return ${host} for subdomain "${
subdomain ?? 'undefined'
}" on "${site}" with query params if view is found`, () => {
const sessionManager = createRumSessionManagerMock().setId('session-id-1')
const viewContexts = {
findView: () => ({
id: 'view-id-1',
startClocks: {
timeStamp: 123456,
},
}),
} as ViewContexts

const link = getSessionReplayLink({ ...DEFAULT_CONFIGURATION, site }, sessionManager, viewContexts, subdomain)

expect(link).toBe(`https://${host}/rum/replay/sessions/session-id-1?seed=view-id-1&from=123456`)
})
})
})
34 changes: 34 additions & 0 deletions packages/rum/src/domain/getSessionReplayLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { RumConfiguration, RumSessionManager, ViewContexts } from '@datadog/browser-rum-core'

export function getSessionReplayLink(
configuration: RumConfiguration,
sessionManager: RumSessionManager,
viewContexts: ViewContexts,
subdomain = getDefaultSubdomain(configuration)
): string | undefined {
const site = configuration.site
const session = sessionManager.findTrackedSession()
if (!session) {
return undefined
}
const sessionId = session.id
const view = viewContexts.findView()
const url = `https://${subdomain ? `${subdomain}.` : ''}${site}/rum/replay/sessions/${sessionId}`
if (!view) {
return url
}
return `${url}?seed=${view.id}&from=${view.startClocks.timeStamp}`
}

function getDefaultSubdomain(configuration: RumConfiguration): string | undefined {
switch (configuration.site) {
case 'datadoghq.com':
return 'app'
case 'datadoghq.eu':
return 'app'
case 'datad0g.com':
return 'dd'
default:
return undefined
}
}

0 comments on commit f37d429

Please sign in to comment.