Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RUMF-804] implement a minimal version of the recorder #670

Merged
merged 46 commits into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
964024e
[RUMF-804] implement the deflate worker
BenoitZugmeyer Dec 17, 2020
00cd89e
[RUMF-804] add sessionReplay endpoint support
BenoitZugmeyer Dec 30, 2020
67cfd0f
[RUMF-804] implement segmentCollection
BenoitZugmeyer Dec 17, 2020
fbfa47d
[RUMF-804] implement segment renewal tracking
BenoitZugmeyer Dec 30, 2020
79ef0b4
[RUMF-804] implement DeflateSegmentWriter
BenoitZugmeyer Dec 30, 2020
c4fc8ee
[RUMF-804] implement the recorder entry point
BenoitZugmeyer Jan 7, 2021
a52d702
✅ [RUMF-804] add support for session replay in E2E tests
BenoitZugmeyer Dec 31, 2020
583a557
🏷️ remove the @types/css-font-loading-module dependency
BenoitZugmeyer Jan 7, 2021
e10600d
Merge branch 'master' into benoit/implement-recorder
BenoitZugmeyer Jan 11, 2021
81373d0
fix merge typo occured while resolving merge conflicts
BenoitZugmeyer Jan 11, 2021
8a76146
👌 fix comments typos and adjust test descriptions
BenoitZugmeyer Jan 11, 2021
e72bb53
✅ fix `isIntakeUrl` tests broken by merging master
BenoitZugmeyer Jan 11, 2021
a296e8f
👷 transpile 'deflateWorker.js'
BenoitZugmeyer Jan 11, 2021
f3d0b4e
✅👌 add a DeflateWorker test where two deflates are completed
BenoitZugmeyer Jan 11, 2021
f8516ef
👌 monitor setTimeout callback
BenoitZugmeyer Jan 11, 2021
a239c16
✅👌 replace 'flushes' by 'writes'
BenoitZugmeyer Jan 11, 2021
272fb57
🚚👌 rename segment.finish() to segment.complete()
BenoitZugmeyer Jan 11, 2021
b7a7fde
📝 add a bit of documentation on segments collection and mouse move ba…
BenoitZugmeyer Jan 11, 2021
5c7c4fe
🚚👌 move record utility functions directly in segment collection
BenoitZugmeyer Jan 11, 2021
dddfc91
Merge remote-tracking branch 'origin/master' into benoit/implement-re…
BenoitZugmeyer Jan 12, 2021
6750054
👌✅ add toFormEntries unit tests
BenoitZugmeyer Jan 12, 2021
ddd26fe
👷👌 move 'allowJs' from tsconfig base to ts-loader config
BenoitZugmeyer Jan 13, 2021
31ef6d2
Update packages/rum-recorder/src/domain/segmentCollection.ts
BenoitZugmeyer Jan 13, 2021
85a1bb1
Update packages/rum-recorder/src/domain/segmentCollection.ts
BenoitZugmeyer Jan 13, 2021
5d16997
✅👌 improve startSegmentCollection tests
BenoitZugmeyer Jan 13, 2021
4bfd755
✅👌 clear the segment expiration timeout
BenoitZugmeyer Jan 13, 2021
bf2420d
✅👌 replace 'throttle' with a simpler 'setTimeout'
BenoitZugmeyer Jan 13, 2021
e4d0272
👌✅ remove internal_ exports and replace with direct import
BenoitZugmeyer Jan 13, 2021
af31724
👌🏗 improve recorder architecture
BenoitZugmeyer Jan 13, 2021
9aeb990
👌 don't create a segment if the session is not tracked
BenoitZugmeyer Jan 14, 2021
7ffabe9
🔥👌 remove mousemove batching logic
BenoitZugmeyer Jan 14, 2021
4cdf7c5
👌 lazily create a segment on first record
BenoitZugmeyer Jan 14, 2021
4f7b300
👌 reword segment 'renew' to 'flush'
BenoitZugmeyer Jan 14, 2021
a683424
👌 reword 'complete' to 'flush'
BenoitZugmeyer Jan 14, 2021
ff0524d
📝👌 improve segmentCollection doc
BenoitZugmeyer Jan 14, 2021
58af718
👌 add doc and monitor log on lost worker response
BenoitZugmeyer Jan 14, 2021
6e6e3f5
👌 add window.setTimeout to simplify typing
BenoitZugmeyer Jan 19, 2021
0e0b266
✅👌 move waitRequests to the end of test cases
BenoitZugmeyer Jan 19, 2021
3425b84
👌 rename 'doGetSegmentContext' to 'computeSegmentContext'
BenoitZugmeyer Jan 19, 2021
ae218f7
✅👌 reword startRecording first test case
BenoitZugmeyer Jan 19, 2021
a0b86c3
👌 add pako to thirdparty licenses
BenoitZugmeyer Jan 19, 2021
dd557de
👌 remove comments
BenoitZugmeyer Jan 19, 2021
daf1360
👌 rename visibility_change to visibility_reason
BenoitZugmeyer Jan 19, 2021
d67bb18
✅ try to make recorder tests less flacky
BenoitZugmeyer Jan 19, 2021
0dbceac
👌✅ split waitRequests and expectNoExtraRequest to be more explicit
BenoitZugmeyer Jan 20, 2021
45a7d0b
Merge remote-tracking branch 'origin/master' into benoit/implement-re…
BenoitZugmeyer Jan 20, 2021
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
3 changes: 2 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ Component,Origin,License,Copyright
require,tslib,Apache-2.0,Copyright Microsoft Corporation
file,rrweb,MIT,Copyright (c) 2018 Contributors (https://github.com/rrweb-io/rrweb/graphs/contributors) and SmartX Inc.
file,tracekit,MIT,Copyright 2013 Onur Can Cakmak and all TraceKit contributors
prod,@types/css-font-loading-module,MIT,Copyright Microsoft Corporation
prod,rrweb-snapshot,MIT,Copyright (c) 2018 Contributors (https://github.com/rrweb-io/rrweb-snapshot/graphs/contributors) and SmartX Inc.
dev,@types/connect-busboy,MIT,Copyright Microsoft Corporation
dev,@types/cors,MIT,Copyright Microsoft Corporation
dev,@types/express,MIT,Copyright Microsoft Corporation
dev,@types/jasmine,MIT,Copyright Microsoft Corporation
Expand All @@ -19,6 +19,7 @@ dev,@wdio/sync,MIT,Copyright JS Foundation and other contributors
dev,ajv,MIT,Copyright 2015-2017 Evgeny Poberezkin
dev,browserstack-local,MIT,Copyright 2016 BrowserStack
dev,codecov,MIT,Copyright 2014 Gregg Caines
dev,connect-busboy,MIT,Copyright Brian White
dev,cors,MIT,Copyright 2013 Troy Goode
dev,emoji-name-map,MIT,Copyright 2016-19 Ionică Bizău <[email protected]> (https://ionicabizau.net)
dev,express,MIT,Copyright 2009-2014 TJ Holowaychuk 2013-2014 Roman Shtylman 2014-2015 Douglas Christopher Wilson
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"rum-events-format:sync": "scripts/cli update_submodule && scripts/cli build_json2type && node scripts/generate-schema-types.js"
},
"devDependencies": {
"@types/connect-busboy": "0.0.2",
"@types/cors": "2.8.7",
"@types/express": "4.17.8",
"@types/jasmine": "3.5.10",
Expand All @@ -42,6 +43,7 @@
"ajv": "6.12.6",
"browserstack-local": "1.4.5",
"codecov": "3.7.1",
"connect-busboy": "0.0.2",
"cors": "2.8.5",
"emoji-name-map": "1.2.8",
"express": "4.17.1",
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/domain/configuration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('configuration', () => {
expect(configuration.rumEndpoint).toEqual('<<< E2E RUM ENDPOINT >>>')
expect(configuration.logsEndpoint).toEqual('<<< E2E LOGS ENDPOINT >>>')
expect(configuration.internalMonitoringEndpoint).toEqual('<<< E2E INTERNAL MONITORING ENDPOINT >>>')
expect(configuration.sessionReplayEndpoint).toEqual('<<< E2E SESSION REPLAY ENDPOINT >>>')
})
})

Expand Down Expand Up @@ -115,6 +116,7 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum-http-intake.logs.datadoghq.eu/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://browser-http-intake.logs.datadoghq.eu/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://public-trace-http-intake.logs.datadoghq.eu/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-datadoghq.eu/v1/input/xxx')).toBe(true)
})

it('should detect intake request for US site', () => {
Expand All @@ -123,13 +125,15 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum-http-intake.logs.datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://browser-http-intake.logs.datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://public-trace-http-intake.logs.datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
})

it('should detect alternate intake domains for US site', () => {
const configuration = buildConfiguration({ clientToken, useAlternateIntakeDomains: true }, usEnv)
expect(configuration.isIntakeUrl('https://rum.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://logs.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://trace.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
})

it('should handle sites with subdomains and classic intake', () => {
Expand All @@ -139,6 +143,9 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://public-trace-http-intake.logs.foo.datadoghq.com/v1/input/xxx')).toBe(
true
)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-foo-datadoghq.com/v1/input/xxx')).toBe(
true
)
})

it('should handle sites with subdomains and alternate intake', () => {
Expand All @@ -149,6 +156,9 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum.browser-intake-foo-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://logs.browser-intake-foo-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://trace.browser-intake-foo-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-foo-datadoghq.com/v1/input/xxx')).toBe(
true
)
})

it('should force alternate intake for us3', () => {
Expand All @@ -159,6 +169,9 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum.browser-intake-us3-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://logs.browser-intake-us3-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://trace.browser-intake-us3-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-us3-datadoghq.com/v1/input/xxx')).toBe(
true
)
})

it('should detect proxy intake request', () => {
Expand Down Expand Up @@ -186,6 +199,7 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum-http-intake.logs.foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://browser-http-intake.logs.foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://public-trace-http-intake.logs.foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-foo.com/v1/input/xxx')).toBe(true)

expect(configuration.isIntakeUrl('https://rum-http-intake.logs.datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://browser-http-intake.logs.datadoghq.com/v1/input/xxx')).toBe(true)
Expand All @@ -199,6 +213,7 @@ describe('configuration', () => {
expect(configuration.isIntakeUrl('https://rum.browser-intake-foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://logs.browser-intake-foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://trace.browser-intake-foo.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://session-replay.browser-intake-foo.com/v1/input/xxx')).toBe(true)

expect(configuration.isIntakeUrl('https://rum.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
expect(configuration.isIntakeUrl('https://logs.browser-intake-datadoghq.com/v1/input/xxx')).toBe(true)
Expand Down
20 changes: 16 additions & 4 deletions packages/core/src/domain/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export type Configuration = typeof DEFAULT_CONFIGURATION & {
logsEndpoint: string
rumEndpoint: string
traceEndpoint: string
sessionReplayEndpoint: string
internalMonitoringEndpoint?: string
proxyHost?: string

Expand Down Expand Up @@ -111,11 +112,14 @@ const ENDPOINTS = {
alternate: {
logs: 'logs',
rum: 'rum',
sessionReplay: 'session-replay',
trace: 'trace',
},
classic: {
logs: 'browser',
rum: 'rum',
// session-replay has no classic endpoint
sessionReplay: undefined,
trace: 'public-trace',
},
}
Expand Down Expand Up @@ -151,6 +155,7 @@ export function buildConfiguration(userConfiguration: UserConfiguration, buildEn
proxyHost: userConfiguration.proxyHost,
rumEndpoint: getEndpoint(intakeType, 'rum', transportConfiguration),
service: userConfiguration.service,
sessionReplayEndpoint: getEndpoint(intakeType, 'sessionReplay', transportConfiguration),
traceEndpoint: getEndpoint(intakeType, 'trace', transportConfiguration),

isIntakeUrl: (url) => intakeUrls.some((intakeUrl) => url.indexOf(intakeUrl) === 0),
Expand Down Expand Up @@ -185,6 +190,7 @@ export function buildConfiguration(userConfiguration: UserConfiguration, buildEn
configuration.internalMonitoringEndpoint = '<<< E2E INTERNAL MONITORING ENDPOINT >>>'
configuration.logsEndpoint = '<<< E2E LOGS ENDPOINT >>>'
configuration.rumEndpoint = '<<< E2E RUM ENDPOINT >>>'
configuration.sessionReplayEndpoint = '<<< E2E SESSION REPLAY ENDPOINT >>>'
}

if (transportConfiguration.buildMode === BuildMode.STAGING) {
Expand Down Expand Up @@ -246,10 +252,16 @@ function getEndpoint(
}

function getHost(intakeType: IntakeType, endpointType: EndpointType, site: string) {
const endpoint = ENDPOINTS[intakeType][endpointType]
if (intakeType === 'classic') {
return `${endpoint}-http-intake.logs.${site}`
}
return (intakeType === 'classic' && getClassicHost(endpointType, site)) || getAlternateHost(endpointType, site)
}

function getClassicHost(endpointType: EndpointType, site: string): string | undefined {
const endpoint = ENDPOINTS.classic[endpointType]
return endpoint && `${endpoint}-http-intake.logs.${site}`
}

function getAlternateHost(endpointType: EndpointType, site: string): string {
const endpoint = ENDPOINTS.alternate[endpointType]
const domainParts = site.split('.')
const extension = domainParts.pop()
const suffix = `${domainParts.join('-')}.${extension}`
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
monitored,
monitor,
addMonitoringMessage,
setDebugMode,
} from './domain/internalMonitoring'
export { Observable } from './tools/observable'
export {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/transport/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const HAS_MULTI_BYTES_CHARACTERS = /[^\u0000-\u007F]/
export class HttpRequest {
constructor(private endpointUrl: string, private bytesLimit: number, private withBatchTime: boolean = false) {}

send(data: string, size: number) {
send(data: string | FormData, size: number) {
const url = this.withBatchTime ? addBatchTime(this.endpointUrl) : this.endpointUrl
if (navigator.sendBeacon && size < this.bytesLimit) {
const isQueued = navigator.sendBeacon(url, data)
Expand Down
3 changes: 3 additions & 0 deletions packages/rum-core/src/boot/rum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export function startRum(userConfiguration: RumUserConfiguration, getCommonConte
addError,
addTiming,
configuration,
lifeCycle,
parentContexts,
session,
getInternalContext: internalContext.get,
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/rum-core/src/boot/rumPublicApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { makeRumPublicApi, RumPublicApi, RumUserConfiguration, StartRum } from '
const configuration: Partial<Configuration> = {
isEnabled: () => false,
}
const noopStartRum = () => ({
const noopStartRum = (): ReturnType<StartRum> => ({
addAction: () => undefined,
addError: () => undefined,
addTiming: () => undefined,
configuration: configuration as Configuration,
getInternalContext: () => undefined,
lifeCycle: {} as any,
parentContexts: {} as any,
session: {} as any,
})
const DEFAULT_INIT_CONFIGURATION = { applicationId: 'xxx', clientToken: 'xxx' }

Expand Down
4 changes: 4 additions & 0 deletions packages/rum-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ export {
RumResourceEvent,
RumLongTaskEvent,
} from './rumEvent.types'
export { ViewContext, CommonContext } from './rawRumEvent.types'
export { startRum } from './boot/rum'
export { LifeCycle, LifeCycleEventType } from './domain/lifeCycle'
export { ParentContexts } from './domain/parentContexts'
export { RumSession } from './domain/rumSession'
1 change: 1 addition & 0 deletions packages/rum-core/src/rawRumEvent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,5 @@ export interface User {
export interface CommonContext {
user: User
context: Context
hasReplay?: boolean
}
3 changes: 1 addition & 2 deletions packages/rum-recorder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
},
"dependencies": {
"@datadog/browser-core": "2.2.0",
"@datadog/browser-rum": "2.2.0",
"@types/css-font-loading-module": "0.0.4",
"@datadog/browser-rum-core": "2.2.0",
"rrweb-snapshot": "1.0.1",
"tslib": "^1.10.0"
},
Expand Down
30 changes: 29 additions & 1 deletion packages/rum-recorder/src/boot/recorder.entry.ts
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
export * from '@datadog/browser-rum'
import { defineGlobal, getGlobalObject } from '@datadog/browser-core'
import {
CommonContext,
makeRumPublicApi,
RumPublicApi,
RumUserConfiguration,
startRum,
} from '@datadog/browser-rum-core'

import { startRecording } from './recorder'

function startRumAndRecording(userConfiguration: RumUserConfiguration, getCommonContext: () => CommonContext) {
const startRumResult = startRum(userConfiguration, () => ({
...getCommonContext(),
hasReplay: true,
}))

const { lifeCycle, parentContexts, configuration, session } = startRumResult
startRecording(lifeCycle, userConfiguration.applicationId, configuration, session, parentContexts)

return startRumResult
}

export const datadogRum = makeRumPublicApi(startRumAndRecording)

interface BrowserWindow extends Window {
DD_RUM?: RumPublicApi
}
defineGlobal(getGlobalObject<BrowserWindow>(), 'DD_RUM', datadogRum)
Loading