Skip to content

Commit

Permalink
Merge branch 'main' into benoit/frustration-signals-1
Browse files Browse the repository at this point in the history
  • Loading branch information
BenoitZugmeyer authored Apr 28, 2022
2 parents 125a6df + 97aecd9 commit 6b75376
Show file tree
Hide file tree
Showing 59 changed files with 1,117 additions and 827 deletions.
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ updates:
# update node-fetch: RUMF-1167
- dependency-name: 'node-fetch'
update-types: ['version-update:semver-major']
- dependency-name: '*'
update-types: ['version-update:semver-minor', 'version-update:semver-patch']
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-15
CURRENT_STAGING: staging-18
APP: 'browser-sdk'
CURRENT_CI_IMAGE: 31
BUILD_STABLE_REGISTRY: '486234852809.dkr.ecr.us-east-1.amazonaws.com'
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@
---

## v4.8.0

-[RUMF-1192] forward Reports to Datadog ([#1506](https://github.com/DataDog/browser-sdk/pull/1506))
-[RUMF-1192] forward `console.*` logs to Datadog ([#1505](https://github.com/DataDog/browser-sdk/pull/1505))
- 📝 fix documentation for `proxyUrl` documentation ([#1503](https://github.com/DataDog/browser-sdk/pull/1503))
-[RUMF-1237] The event bridge allowed hosts should also match subdomains ([#1499](https://github.com/DataDog/browser-sdk/pull/1499))
- 📝 add `replaySampleRate` to README examples ([#1370](https://github.com/DataDog/browser-sdk/pull/1370))

## v4.7.1

- 🐛 Adjust records generated during view change so their date matches the view date ([#1486](https://github.com/DataDog/browser-sdk/pull/1486))
- ⚗✨ [RUMF-1224] remove console APIs prefix ([#1479](https://github.com/DataDog/browser-sdk/pull/1479))
- ♻️ [RUMF-1178] improve logs assembly part 2 ([#1463](https://github.com/DataDog/browser-sdk/pull/1463))
- ⚗✨ Allow update service version with start view ([#1448](https://github.com/DataDog/browser-sdk/pull/1448))
- ⚗✨ [RUMF-1208] don't discard automatic action on view creation ([#1451](https://github.com/DataDog/browser-sdk/pull/1451))
- ⚗✨ [RUMF-1207] collect concurrent actions ([#1434](https://github.com/DataDog/browser-sdk/pull/1434))
- ♻️ [RUMF-1207] collect concurrent actions groundwork - move action history closer to action collection ([#1432](https://github.com/DataDog/browser-sdk/pull/1432))

## v4.7.0

Note: The Logs Browser SDK 3.10.1 (released on December 21th, 2021) unexpectedly changed the initialization parameter `forwardErrorsToLogs` default value from `true` to `false`. This release restores the default value to `true`, so Logs Browser SDK users who don't specify this parameter will have errors forwarded as logs.
Expand Down
10 changes: 5 additions & 5 deletions developer-extension/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "@datadog/browser-sdk-developer-extension",
"version": "4.7.0",
"version": "4.8.0",
"private": true,
"scripts": {
"build": "rm -rf dist && webpack --mode production",
"dev": "webpack --mode development --watch"
},
"devDependencies": {
"@types/chrome": "0.0.180",
"@types/react": "17.0.43",
"@types/react-dom": "17.0.14",
"@types/react": "18.0.1",
"@types/react-dom": "18.0.0",
"copy-webpack-plugin": "8.1.0",
"html-webpack-plugin": "5.3.1",
"webpack": "5.28.0",
Expand All @@ -18,8 +18,8 @@
"dependencies": {
"@mantine/core": "4.1.2",
"@mantine/hooks": "4.1.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "18.0.0",
"react-dom": "18.0.0",
"react-json-view": "1.21.3"
}
}
7 changes: 5 additions & 2 deletions developer-extension/src/panel/components/eventsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Badge, Group, SegmentedControl, Space, Table, TextInput } from '@mantine/core'
import { useColorScheme } from '@mantine/hooks'
import React from 'react'
import ReactJson from 'react-json-view'
import type { RumEvent } from '../../../../packages/rum-core/src/rumEvent.types'
Expand All @@ -11,6 +12,7 @@ const RUM_EVENT_TYPE_COLOR = {
long_task: 'yellow',
view: 'blue',
resource: 'cyan',
telemetry: 'teal',
}

const LOG_STATUS_COLOR = {
Expand All @@ -27,6 +29,7 @@ interface EventTabProps {
}

export function EventTab({ events, filters, onFiltered }: EventTabProps) {
const colorScheme = useColorScheme()
return (
events && (
<>
Expand All @@ -40,7 +43,7 @@ export function EventTab({ events, filters, onFiltered }: EventTabProps) {
]}
/>
<TextInput
placeholder="Filter your events"
placeholder="Filter your events, syntax: 'type:view application.id:40d8ca4b'"
value={filters.query}
style={{ flexGrow: 1 }}
onChange={(event) => onFiltered({ ...filters, query: event.currentTarget.value })}
Expand All @@ -67,7 +70,7 @@ export function EventTab({ events, filters, onFiltered }: EventTabProps) {
<ReactJson
src={event}
collapsed={true}
theme="monokai"
theme={colorScheme === 'dark' ? 'monokai' : 'bright:inverted'}
name={jsonOverview(event)}
displayDataTypes={false}
/>
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "4.7.0",
"version": "4.8.0",
"publishConfig": {
"access": "public"
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
"eslint-module-utils": "2.7.3",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-jasmine": "4.1.3",
"eslint-plugin-jsdoc": "38.1.6",
"eslint-plugin-jsdoc": "39.1.1",
"eslint-plugin-local-rules": "1.1.0",
"eslint-plugin-prefer-arrow": "1.2.3",
"eslint-plugin-unicorn": "42.0.0",
"express": "4.17.3",
"glob": "7.2.0",
"glob": "8.0.1",
"jasmine-core": "3.6.0",
"js-polyfills": "0.1.43",
"json-schema-to-typescript": "bcaudan/json-schema-to-typescript#bcaudan/add-readonly-support",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@datadog/browser-core",
"version": "4.7.0",
"version": "4.8.0",
"license": "Apache-2.0",
"main": "cjs/index.js",
"module": "esm/index.js",
Expand Down
25 changes: 23 additions & 2 deletions packages/core/src/domain/configuration/configuration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ describe('validateAndBuildConfiguration', () => {
expect(displaySpy).toHaveBeenCalledOnceWith('Client Token is not configured, we will not send any data.')
})

it("shouldn't display any error if the configuration is correct", () => {
validateAndBuildConfiguration({ clientToken: 'yes' })
expect(displaySpy).not.toHaveBeenCalled()
})

it('requires sampleRate to be a percentage', () => {
expect(
validateAndBuildConfiguration({ clientToken, sampleRate: 'foo' } as unknown as InitConfiguration)
Expand All @@ -44,12 +49,28 @@ describe('validateAndBuildConfiguration', () => {
validateAndBuildConfiguration({ clientToken, sampleRate: 200 } as unknown as InitConfiguration)
).toBeUndefined()
expect(displaySpy).toHaveBeenCalledOnceWith('Sample Rate should be a number between 0 and 100')
})

it("shouldn't display any error if the configuration is correct", () => {
displaySpy.calls.reset()
validateAndBuildConfiguration({ clientToken: 'yes', sampleRate: 1 })
expect(displaySpy).not.toHaveBeenCalled()
})

it('requires telemetrySampleRate to be a percentage', () => {
expect(
validateAndBuildConfiguration({ clientToken, telemetrySampleRate: 'foo' } as unknown as InitConfiguration)
).toBeUndefined()
expect(displaySpy).toHaveBeenCalledOnceWith('Telemetry Sample Rate should be a number between 0 and 100')

displaySpy.calls.reset()
expect(
validateAndBuildConfiguration({ clientToken, telemetrySampleRate: 200 } as unknown as InitConfiguration)
).toBeUndefined()
expect(displaySpy).toHaveBeenCalledOnceWith('Telemetry Sample Rate should be a number between 0 and 100')

displaySpy.calls.reset()
validateAndBuildConfiguration({ clientToken: 'yes', telemetrySampleRate: 1 })
expect(displaySpy).not.toHaveBeenCalled()
})
})

describe('cookie options', () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface InitConfiguration {
clientToken: string
beforeSend?: GenericBeforeSendCallback | undefined
sampleRate?: number | undefined
telemetrySampleRate?: number | undefined
silentMultipleInit?: boolean | undefined

// transport options
Expand Down Expand Up @@ -56,6 +57,7 @@ export interface Configuration extends TransportConfiguration {
beforeSend: GenericBeforeSendCallback | undefined
cookieOptions: CookieOptions
sampleRate: number
telemetrySampleRate: number
service: string | undefined
silentMultipleInit: boolean

Expand All @@ -81,6 +83,11 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
return
}

if (initConfiguration.telemetrySampleRate !== undefined && !isPercentage(initConfiguration.telemetrySampleRate)) {
display.error('Telemetry Sample Rate should be a number between 0 and 100')
return
}

// Set the experimental feature flags as early as possible, so we can use them in most places
updateExperimentalFeatures(initConfiguration.enableExperimentalFeatures)

Expand All @@ -90,6 +97,7 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
initConfiguration.beforeSend && catchUserErrors(initConfiguration.beforeSend, 'beforeSend threw an error:'),
cookieOptions: buildCookieOptions(initConfiguration),
sampleRate: initConfiguration.sampleRate ?? 100,
telemetrySampleRate: initConfiguration.telemetrySampleRate ?? 20,
service: initConfiguration.service,
silentMultipleInit: !!initConfiguration.silentMultipleInit,

Expand Down
132 changes: 68 additions & 64 deletions packages/core/src/domain/console/consoleObservable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,71 +6,75 @@ import { ConsoleApiName, initConsoleObservable } from './consoleObservable'

// prettier: avoid formatting issue
// cf https://github.com/prettier/prettier/issues/12211
;[ConsoleApiName.log, ConsoleApiName.info, ConsoleApiName.warn, ConsoleApiName.debug, ConsoleApiName.error].forEach(
(api) => {
describe(`console ${api} observable`, () => {
let consoleStub: jasmine.Spy
let consoleSubscription: Subscription
let notifyLog: jasmine.Spy

beforeEach(() => {
consoleStub = spyOn(console, api)
notifyLog = jasmine.createSpy('notifyLog')

consoleSubscription = initConsoleObservable([api]).subscribe(notifyLog)
})

afterEach(() => {
consoleSubscription.unsubscribe()
})

it(`should notify ${api}`, () => {
console[api]('foo', 'bar')

const consoleLog = notifyLog.calls.mostRecent().args[0]

expect(consoleLog).toEqual(
jasmine.objectContaining({
message: `console ${api}: foo bar`,
api,
})
)
})

it('should keep original behavior', () => {
console[api]('foo', 'bar')

expect(consoleStub).toHaveBeenCalledWith('foo', 'bar')
})

it('should format error instance', () => {
console[api](new TypeError('hello'))
const consoleLog = notifyLog.calls.mostRecent().args[0]
expect(consoleLog.message).toBe(`console ${api}: TypeError: hello`)
})

it('should stringify object parameters', () => {
console[api]('Hello', { foo: 'bar' })
const consoleLog = notifyLog.calls.mostRecent().args[0]
expect(consoleLog.message).toBe(`console ${api}: Hello {\n "foo": "bar"\n}`)
})

it('should allow multiple callers', () => {
const notifyOtherCaller = jasmine.createSpy('notifyOtherCaller')
const instrumentedConsoleApi = console[api]
const otherConsoleSubscription = initConsoleObservable([api]).subscribe(notifyOtherCaller)

console[api]('foo', 'bar')

expect(instrumentedConsoleApi).toEqual(console[api])
expect(notifyLog).toHaveBeenCalledTimes(1)
expect(notifyOtherCaller).toHaveBeenCalledTimes(1)

otherConsoleSubscription.unsubscribe()
})
;[
{ api: ConsoleApiName.log, prefix: '' },
{ api: ConsoleApiName.info, prefix: '' },
{ api: ConsoleApiName.warn, prefix: '' },
{ api: ConsoleApiName.debug, prefix: '' },
{ api: ConsoleApiName.error, prefix: 'console error: ' },
].forEach(({ api, prefix }) => {
describe(`console ${api} observable`, () => {
let consoleStub: jasmine.Spy
let consoleSubscription: Subscription
let notifyLog: jasmine.Spy

beforeEach(() => {
consoleStub = spyOn(console, api)
notifyLog = jasmine.createSpy('notifyLog')

consoleSubscription = initConsoleObservable([api]).subscribe(notifyLog)
})
}
)

afterEach(() => {
consoleSubscription.unsubscribe()
})

it(`should notify ${api}`, () => {
console[api]('foo', 'bar')

const consoleLog = notifyLog.calls.mostRecent().args[0]

expect(consoleLog).toEqual(
jasmine.objectContaining({
message: `${prefix}foo bar`,
api,
})
)
})

it('should keep original behavior', () => {
console[api]('foo', 'bar')

expect(consoleStub).toHaveBeenCalledWith('foo', 'bar')
})

it('should format error instance', () => {
console[api](new TypeError('hello'))
const consoleLog = notifyLog.calls.mostRecent().args[0]
expect(consoleLog.message).toBe(`${prefix}TypeError: hello`)
})

it('should stringify object parameters', () => {
console[api]('Hello', { foo: 'bar' })
const consoleLog = notifyLog.calls.mostRecent().args[0]
expect(consoleLog.message).toBe(`${prefix}Hello {\n "foo": "bar"\n}`)
})

it('should allow multiple callers', () => {
const notifyOtherCaller = jasmine.createSpy('notifyOtherCaller')
const instrumentedConsoleApi = console[api]
const otherConsoleSubscription = initConsoleObservable([api]).subscribe(notifyOtherCaller)

console[api]('foo', 'bar')

expect(instrumentedConsoleApi).toEqual(console[api])
expect(notifyLog).toHaveBeenCalledTimes(1)
expect(notifyOtherCaller).toHaveBeenCalledTimes(1)

otherConsoleSubscription.unsubscribe()
})
})
})

describe('console error observable', () => {
let consoleSubscription: Subscription
Expand Down
21 changes: 11 additions & 10 deletions packages/core/src/domain/console/consoleObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,22 @@ function createConsoleObservable(api: ConsoleApiName) {
}

function buildConsoleLog(params: unknown[], api: ConsoleApiName, handlingStack: string): ConsoleLog {
const log: ConsoleLog = {
message: [`console ${api}:` as unknown]
.concat(params)
.map((param) => formatConsoleParameters(param))
.join(' '),
api,
}
// Todo: remove console error prefix in the next major version
let message = params.map((param) => formatConsoleParameters(param)).join(' ')
let stack

if (api === ConsoleApiName.error) {
const firstErrorParam = find(params, (param: unknown): param is Error => param instanceof Error)
log.stack = firstErrorParam ? toStackTraceString(computeStackTrace(firstErrorParam)) : undefined
log.handlingStack = handlingStack
stack = firstErrorParam ? toStackTraceString(computeStackTrace(firstErrorParam)) : undefined
message = `console error: ${message}`
}

return log
return {
api,
message,
stack,
handlingStack,
}
}

function formatConsoleParameters(param: unknown) {
Expand Down
Loading

0 comments on commit 6b75376

Please sign in to comment.