Skip to content

Commit

Permalink
Merge branch 'main' into prerelease-v5
Browse files Browse the repository at this point in the history
  • Loading branch information
amortemousque committed Sep 19, 2023
2 parents eddca77 + 52728dc commit f69f12e
Show file tree
Hide file tree
Showing 24 changed files with 441 additions and 383 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
variables:
CURRENT_STAGING: staging-37
CURRENT_STAGING: staging-38
APP: 'browser-sdk'
CURRENT_CI_IMAGE: 53
BUILD_STABLE_REGISTRY: '486234852809.dkr.ecr.us-east-1.amazonaws.com'
Expand Down
73 changes: 53 additions & 20 deletions packages/core/src/domain/configuration/endpointBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import {
addExperimentalFeatures,
} from '../../tools/experimentalFeatures'
import { startsWith } from '../../tools/utils/polyfills'
import type { Payload } from '../../transport'
import type { InitConfiguration } from './configuration'
import { createEndpointBuilder } from './endpointBuilder'

const DEFAULT_PAYLOAD = {} as Payload

describe('endpointBuilder', () => {
const clientToken = 'some_client_token'
let initConfiguration: InitConfiguration
Expand All @@ -20,23 +23,36 @@ describe('endpointBuilder', () => {

describe('query parameters', () => {
it('should add intake query parameters', () => {
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr')).toMatch(
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', DEFAULT_PAYLOAD)).toMatch(
`&dd-api-key=${clientToken}&dd-evp-origin-version=(.*)&dd-evp-origin=browser&dd-request-id=(.*)`
)
})

it('should add batch_time for rum endpoint', () => {
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr')).toContain('&batch_time=')
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', DEFAULT_PAYLOAD)).toContain(
'&batch_time='
)
})

it('should not add batch_time for logs and replay endpoints', () => {
expect(createEndpointBuilder(initConfiguration, 'logs', []).build('xhr')).not.toContain('&batch_time=')
expect(createEndpointBuilder(initConfiguration, 'replay', []).build('xhr')).not.toContain('&batch_time=')
expect(createEndpointBuilder(initConfiguration, 'logs', []).build('xhr', DEFAULT_PAYLOAD)).not.toContain(
'&batch_time='
)
expect(createEndpointBuilder(initConfiguration, 'replay', []).build('xhr', DEFAULT_PAYLOAD)).not.toContain(
'&batch_time='
)
})

it('should add the provided encoding', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', { ...DEFAULT_PAYLOAD, encoding: 'deflate' })
).toContain('&dd-evp-encoding=deflate')
})

it('should not start with ddsource for internal analytics mode', () => {
const url = createEndpointBuilder({ ...initConfiguration, internalAnalyticsSubdomain: 'foo' }, 'rum', []).build(
'xhr'
'xhr',
DEFAULT_PAYLOAD
)
expect(url).not.toContain('/rum?ddsource')
expect(url).toContain('ddsource=browser')
Expand All @@ -46,7 +62,10 @@ describe('endpointBuilder', () => {
describe('proxy configuration', () => {
it('should replace the intake endpoint by the proxy and set the intake path and parameters in the attribute ddforward', () => {
expect(
createEndpointBuilder({ ...initConfiguration, proxy: 'https://proxy.io/path' }, 'rum', []).build('xhr')
createEndpointBuilder({ ...initConfiguration, proxy: 'https://proxy.io/path' }, 'rum', []).build(
'xhr',
DEFAULT_PAYLOAD
)
).toMatch(
`https://proxy.io/path\\?ddforward=${encodeURIComponent(
`/api/v2/rum?ddsource=(.*)&ddtags=(.*)&dd-api-key=${clientToken}` +
Expand All @@ -58,7 +77,7 @@ describe('endpointBuilder', () => {
it('normalizes the proxy url', () => {
expect(
startsWith(
createEndpointBuilder({ ...initConfiguration, proxy: '/path' }, 'rum', []).build('xhr'),
createEndpointBuilder({ ...initConfiguration, proxy: '/path' }, 'rum', []).build('xhr', DEFAULT_PAYLOAD),
`${location.origin}/path?ddforward`
)
).toBeTrue()
Expand All @@ -67,39 +86,53 @@ describe('endpointBuilder', () => {

describe('tags', () => {
it('should contain sdk version', () => {
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr')).toContain('sdk_version%3Asome_version')
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', DEFAULT_PAYLOAD)).toContain(
'sdk_version%3Asome_version'
)
})

it('should contain api', () => {
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr')).toContain('api%3Axhr')
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', DEFAULT_PAYLOAD)).toContain('api%3Axhr')
})

it('should be encoded', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum', ['service:bar:foo', 'datacenter:us1.prod.dog']).build('xhr')
createEndpointBuilder(initConfiguration, 'rum', ['service:bar:foo', 'datacenter:us1.prod.dog']).build(
'xhr',
DEFAULT_PAYLOAD
)
).toContain('service%3Abar%3Afoo%2Cdatacenter%3Aus1.prod.dog')
})

it('should contain retry infos', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', 'bytes_limit', {
count: 5,
lastFailureStatus: 408,
createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', {
...DEFAULT_PAYLOAD,
retry: {
count: 5,
lastFailureStatus: 408,
},
})
).toContain('retry_count%3A5%2Cretry_after%3A408')
})

it('should contain flush reason when ff collect_flush_reason is enabled', () => {
addExperimentalFeatures([ExperimentalFeature.COLLECT_FLUSH_REASON])
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', 'bytes_limit')).toContain(
'flush_reason%3Abytes_limit'
)
expect(
createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', {
...DEFAULT_PAYLOAD,
flushReason: 'bytes_limit',
})
).toContain('flush_reason%3Abytes_limit')
})

it('should not contain flush reason when ff collect_flush_reason is disnabled', () => {
expect(createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', 'bytes_limit')).not.toContain(
'flush_reason'
)
it('should not contain flush reason when ff collect_flush_reason is disabled', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum', []).build('xhr', {
...DEFAULT_PAYLOAD,
flushReason: 'bytes_limit',
})
).not.toContain('flush_reason')
})
})
})
22 changes: 10 additions & 12 deletions packages/core/src/domain/configuration/endpointBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RetryInfo, FlushReason } from '../../transport'
import type { Payload } from '../../transport'
import { timeStampNow } from '../../tools/utils/timeUtils'
import { normalizeUrl } from '../../tools/utils/urlPolyfill'
import { ExperimentalFeature, isExperimentalFeatureEnabled } from '../../tools/experimentalFeatures'
Expand All @@ -21,15 +21,8 @@ export function createEndpointBuilder(
const buildUrlWithParameters = createEndpointUrlWithParametersBuilder(initConfiguration, trackType)

return {
build(api: 'xhr' | 'fetch' | 'beacon', flushReason?: FlushReason, retry?: RetryInfo) {
const parameters = buildEndpointParameters(
initConfiguration,
trackType,
configurationTags,
api,
flushReason,
retry
)
build(api: 'xhr' | 'fetch' | 'beacon', payload: Payload) {
const parameters = buildEndpointParameters(initConfiguration, trackType, configurationTags, api, payload)
return buildUrlWithParameters(parameters)
},
urlPrefix: buildUrlWithParameters(''),
Expand Down Expand Up @@ -77,8 +70,7 @@ function buildEndpointParameters(
trackType: TrackType,
configurationTags: string[],
api: 'xhr' | 'fetch' | 'beacon',
flushReason: FlushReason | undefined,
retry: RetryInfo | undefined
{ retry, flushReason, encoding }: Payload
) {
const tags = [`sdk_version:${__BUILD_ENV__SDK_VERSION__}`, `api:${api}`].concat(configurationTags)
if (flushReason && isExperimentalFeatureEnabled(ExperimentalFeature.COLLECT_FLUSH_REASON)) {
Expand All @@ -87,6 +79,7 @@ function buildEndpointParameters(
if (retry) {
tags.push(`retry_count:${retry.count}`, `retry_after:${retry.lastFailureStatus}`)
}

const parameters = [
'ddsource=browser',
`ddtags=${encodeURIComponent(tags.join(','))}`,
Expand All @@ -96,9 +89,14 @@ function buildEndpointParameters(
`dd-request-id=${generateUUID()}`,
]

if (encoding) {
parameters.push(`dd-evp-encoding=${encoding}`)
}

if (trackType === 'rum') {
parameters.push(`batch_time=${timeStampNow()}`)
}

if (internalAnalyticsSubdomain) {
parameters.reverse()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import type { Payload } from '../../transport'
import { computeTransportConfiguration } from './transportConfiguration'

const DEFAULT_PAYLOAD = {} as Payload

describe('transportConfiguration', () => {
const clientToken = 'some_client_token'
const internalAnalyticsSubdomain = 'ia-rum-intake'
describe('site', () => {
it('should use US site by default', () => {
const configuration = computeTransportConfiguration({ clientToken })
expect(configuration.rumEndpointBuilder.build('xhr')).toContain('datadoghq.com')
expect(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD)).toContain('datadoghq.com')
expect(configuration.site).toBe('datadoghq.com')
})

it('should use site value when set', () => {
const configuration = computeTransportConfiguration({ clientToken, site: 'foo.com' })
expect(configuration.rumEndpointBuilder.build('xhr')).toContain('foo.com')
expect(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD)).toContain('foo.com')
expect(configuration.site).toBe('foo.com')
})
})
Expand All @@ -23,7 +26,7 @@ describe('transportConfiguration', () => {
clientToken,
internalAnalyticsSubdomain,
})
expect(configuration.rumEndpointBuilder.build('xhr')).toContain(internalAnalyticsSubdomain)
expect(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD)).toContain(internalAnalyticsSubdomain)
})

it('should not use internal analytics subdomain value when set for other sites', () => {
Expand All @@ -32,30 +35,42 @@ describe('transportConfiguration', () => {
site: 'foo.bar',
internalAnalyticsSubdomain,
})
expect(configuration.rumEndpointBuilder.build('xhr')).not.toContain(internalAnalyticsSubdomain)
expect(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD)).not.toContain(internalAnalyticsSubdomain)
})
})

describe('sdk_version, env, version and service', () => {
it('should not modify the logs and rum endpoints tags when not defined', () => {
const configuration = computeTransportConfiguration({ clientToken })
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr'))).not.toContain(',env:')
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr'))).not.toContain(',service:')
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr'))).not.toContain(',version:')
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr'))).not.toContain(',datacenter:')

expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr'))).not.toContain(',env:')
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr'))).not.toContain(',service:')
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr'))).not.toContain(',version:')
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr'))).not.toContain(',datacenter:')
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(',env:')
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',service:'
)
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',version:'
)
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',datacenter:'
)

expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(',env:')
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',service:'
)
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',version:'
)
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).not.toContain(
',datacenter:'
)
})

it('should be set as tags in the logs and rum endpoints', () => {
const configuration = computeTransportConfiguration({ clientToken, env: 'foo', service: 'bar', version: 'baz' })
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr'))).toContain(
expect(decodeURIComponent(configuration.rumEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).toContain(
'env:foo,service:bar,version:baz'
)
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr'))).toContain(
expect(decodeURIComponent(configuration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))).toContain(
'env:foo,service:bar,version:baz'
)
})
Expand Down
29 changes: 15 additions & 14 deletions packages/core/src/transport/httpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface Payload {
bytesCount: number
retry?: RetryInfo
flushReason?: FlushReason
encoding?: 'deflate'
}

export interface RetryInfo {
Expand Down Expand Up @@ -63,13 +64,13 @@ function sendBeaconStrategy(
configuration: Configuration,
endpointBuilder: EndpointBuilder,
bytesLimit: number,
{ data, bytesCount, flushReason }: Payload
payload: Payload
) {
const canUseBeacon = !!navigator.sendBeacon && bytesCount < bytesLimit
const canUseBeacon = !!navigator.sendBeacon && payload.bytesCount < bytesLimit
if (canUseBeacon) {
try {
const beaconUrl = endpointBuilder.build('beacon', flushReason)
const isQueued = navigator.sendBeacon(beaconUrl, data)
const beaconUrl = endpointBuilder.build('beacon', payload)
const isQueued = navigator.sendBeacon(beaconUrl, payload.data)

if (isQueued) {
return
Expand All @@ -79,8 +80,8 @@ function sendBeaconStrategy(
}
}

const xhrUrl = endpointBuilder.build('xhr', flushReason)
sendXHR(configuration, xhrUrl, data)
const xhrUrl = endpointBuilder.build('xhr', payload)
sendXHR(configuration, xhrUrl, payload.data)
}

let hasReportedBeaconError = false
Expand All @@ -96,23 +97,23 @@ export function fetchKeepAliveStrategy(
configuration: Configuration,
endpointBuilder: EndpointBuilder,
bytesLimit: number,
{ data, bytesCount, flushReason, retry }: Payload,
payload: Payload,
onResponse?: (r: HttpResponse) => void
) {
const canUseKeepAlive = isKeepAliveSupported() && bytesCount < bytesLimit
const canUseKeepAlive = isKeepAliveSupported() && payload.bytesCount < bytesLimit
if (canUseKeepAlive) {
const fetchUrl = endpointBuilder.build('fetch', flushReason, retry)
fetch(fetchUrl, { method: 'POST', body: data, keepalive: true, mode: 'cors' }).then(
const fetchUrl = endpointBuilder.build('fetch', payload)
fetch(fetchUrl, { method: 'POST', body: payload.data, keepalive: true, mode: 'cors' }).then(
monitor((response: Response) => onResponse?.({ status: response.status, type: response.type })),
monitor(() => {
const xhrUrl = endpointBuilder.build('xhr', flushReason, retry)
const xhrUrl = endpointBuilder.build('xhr', payload)
// failed to queue the request
sendXHR(configuration, xhrUrl, data, onResponse)
sendXHR(configuration, xhrUrl, payload.data, onResponse)
})
)
} else {
const xhrUrl = endpointBuilder.build('xhr', flushReason, retry)
sendXHR(configuration, xhrUrl, data, onResponse)
const xhrUrl = endpointBuilder.build('xhr', payload)
sendXHR(configuration, xhrUrl, payload.data, onResponse)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const SPEC_ENDPOINTS = {
}

export function stubEndpointBuilder(url: string) {
return { build: (_: any) => url } as EndpointBuilder
return { build: (..._: any) => url } as EndpointBuilder
}

export interface Request {
Expand Down
4 changes: 3 additions & 1 deletion packages/logs/src/boot/startLogs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Payload } from '@datadog/browser-core'
import { ErrorSource, display, stopSessionManager, getCookie, SESSION_STORE_KEY } from '@datadog/browser-core'
import type { Request } from '@datadog/browser-core/test'
import {
Expand Down Expand Up @@ -37,6 +38,7 @@ const COMMON_CONTEXT = {
context: {},
user: {},
}
const DEFAULT_PAYLOAD = {} as Payload

describe('logs', () => {
const initConfiguration = { clientToken: 'xxx', service: 'service', telemetrySampleRate: 0 }
Expand Down Expand Up @@ -77,7 +79,7 @@ describe('logs', () => {
handleLog({ message: 'message', status: StatusType.warn, context: { foo: 'bar' } }, logger, COMMON_CONTEXT)

expect(requests.length).toEqual(1)
expect(requests[0].url).toContain(baseConfiguration.logsEndpointBuilder.build('xhr'))
expect(requests[0].url).toContain(baseConfiguration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))
expect(getLoggedMessage(requests, 0)).toEqual({
date: jasmine.any(Number),
foo: 'bar',
Expand Down
Loading

0 comments on commit f69f12e

Please sign in to comment.