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

✨ [RUM-4014] DD_LOGS: add handling stack in beforeSend context #2786

Merged
merged 37 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
184a20f
✨ [RUM-4013] add handling stack in beforeSend context
thomas-lebeau Apr 26, 2024
60046eb
add handling stack for addErrors and addAction
thomas-lebeau Apr 30, 2024
8751cec
🧪 add e2e tests
thomas-lebeau May 15, 2024
626d7a7
add e2e and loose up unit tests
thomas-lebeau May 16, 2024
1c2e2e3
remove unused variable
thomas-lebeau May 16, 2024
58e89ad
Merge branch 'main' into thomas.lebeau/micro-frontend-rum
thomas-lebeau May 16, 2024
7a80140
🧪 add missing test coverage
thomas-lebeau May 17, 2024
4625f07
✅ add e2e test for console errors
thomas-lebeau May 17, 2024
706655b
Merge branch 'main' into thomas.lebeau/micro-frontend-rum
thomas-lebeau May 22, 2024
29373f2
Merge branch 'main' into thomas.lebeau/micro-frontend-rum
thomas-lebeau May 23, 2024
0db8ccf
fix missing imports
thomas-lebeau May 23, 2024
11bfe46
remove unused imports
thomas-lebeau May 23, 2024
7cfb9e0
👌 add type to e2e tests
thomas-lebeau May 24, 2024
8a3328f
👌 fix pr comments
thomas-lebeau May 27, 2024
c84c8b1
✨ [RUM-4014] add handling stack in beforeSend context
thomas-lebeau May 28, 2024
8c095c2
Merge branch 'main' into thomas.lebeau/micro-frontend-rum
thomas-lebeau May 28, 2024
169fa16
Merge branch 'thomas.lebeau/micro-frontend-rum' into thomas.lebeau/mi…
thomas-lebeau May 28, 2024
a070bbb
only pass handling stack if FF is enabled
thomas-lebeau May 28, 2024
272682b
Merge branch 'main' into thomas.lebeau/micro-frontend-service-logs
thomas-lebeau May 30, 2024
fbae491
✨ generate handlingStack for the logger api
thomas-lebeau May 30, 2024
23ae6a2
fix type errors
thomas-lebeau May 30, 2024
82c0d37
fix async page setup snippet
thomas-lebeau May 31, 2024
9e26385
feat: improve handling stack for logger API
thomas-lebeau May 31, 2024
a6825b8
fix: typo
thomas-lebeau May 31, 2024
beb91c0
Merge branch 'main' into thomas.lebeau/micro-frontend-service-logs
thomas-lebeau Jun 4, 2024
736e7e9
Merge branch 'main' into thomas.lebeau/micro-frontend-service-logs
thomas-lebeau Jun 5, 2024
6bc876c
feat: update RUM configuration in microfrontend scenario test
thomas-lebeau Jun 5, 2024
709352f
feat: Refactor logInitArgs formatting in pageSetups.ts
thomas-lebeau Jun 5, 2024
41ec29d
Merge branch 'main' into thomas.lebeau/micro-frontend-service-logs
thomas-lebeau Jun 7, 2024
522dc2e
feat: Update logger APIs in microfrontend scenario test
thomas-lebeau Jun 7, 2024
65c6d01
fix status type of new logger methods
thomas-lebeau Jun 7, 2024
76f80e0
fix test for logger.ok()
thomas-lebeau Jun 7, 2024
8377d6b
🧪 test only one of logger and console method
thomas-lebeau Jun 10, 2024
0eddd58
👌 Simplify network error handling code
thomas-lebeau Jun 10, 2024
6285b92
♻️ refactor Logger to reduce bundle size
thomas-lebeau Jun 11, 2024
383b43a
♻️ refactor Logger method types declaration to reduce bundle size
thomas-lebeau Jun 11, 2024
ef8878c
🧪 add test for domain context without FF
thomas-lebeau Jun 11, 2024
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
2 changes: 1 addition & 1 deletion packages/core/src/domain/console/consoleObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface ConsoleLog {
message: string
api: ConsoleApiName
stack?: string
handlingStack?: string
handlingStack: string
fingerprint?: string
causes?: RawErrorCause[]
}
Expand Down
3 changes: 2 additions & 1 deletion packages/logs/src/boot/logsPublicApi.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { TimeStamp } from '@datadog/browser-core'
import { monitor, display, removeStorageListeners } from '@datadog/browser-core'
import type { Logger, LogsMessage } from '../domain/logger'
import { HandlerType, StatusType } from '../domain/logger'
import { HandlerType } from '../domain/logger'
import { StatusType } from '../domain/logger/isAuthorized'
import type { CommonContext } from '../rawLogsEvent.types'
import type { LogsPublicApi } from './logsPublicApi'
import { makeLogsPublicApi } from './logsPublicApi'
Expand Down
3 changes: 2 additions & 1 deletion packages/logs/src/boot/logsPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
createTrackingConsentState,
} from '@datadog/browser-core'
import type { LogsInitConfiguration } from '../domain/configuration'
import type { HandlerType, StatusType } from '../domain/logger'
import type { HandlerType } from '../domain/logger'
import type { StatusType } from '../domain/logger/isAuthorized'
import { Logger } from '../domain/logger'
import { buildCommonContext } from '../domain/contexts/commonContext'
import type { InternalContext } from '../domain/contexts/internalContext'
Expand Down
7 changes: 4 additions & 3 deletions packages/logs/src/boot/preStartLogs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type { TimeStamp, TrackingConsentState } from '@datadog/browser-core'
import { ONE_SECOND, TrackingConsent, createTrackingConsentState, display } from '@datadog/browser-core'
import type { CommonContext } from '../rawLogsEvent.types'
import type { HybridInitConfiguration, LogsConfiguration, LogsInitConfiguration } from '../domain/configuration'
import { StatusType, type Logger } from '../domain/logger'
import type { Logger } from '../domain/logger'
import { StatusType } from '../domain/logger/isAuthorized'
import type { Strategy } from './logsPublicApi'
import { createPreStartStrategy } from './preStartLogs'
import type { StartLogsResult } from './startLogs'
Expand All @@ -21,8 +22,8 @@ describe('preStartLogs', () => {
let clock: Clock

function getLoggedMessage(index: number) {
const [message, logger, savedCommonContext, savedDate] = handleLogSpy.calls.argsFor(index)
return { message, logger, savedCommonContext, savedDate }
const [message, logger, handlingStack, savedCommonContext, savedDate] = handleLogSpy.calls.argsFor(index)
return { message, logger, handlingStack, savedCommonContext, savedDate }
}

beforeEach(() => {
Expand Down
6 changes: 4 additions & 2 deletions packages/logs/src/boot/preStartLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ export function createPreStartStrategy(

getInternalContext: noop as () => undefined,

handleLog(message, statusType, context = getCommonContext(), date = timeStampNow()) {
bufferApiCalls.add((startLogsResult) => startLogsResult.handleLog(message, statusType, context, date))
handleLog(message, statusType, handlingStack, context = getCommonContext(), date = timeStampNow()) {
bufferApiCalls.add((startLogsResult) =>
startLogsResult.handleLog(message, statusType, handlingStack, context, date)
)
},
}
}
Expand Down
10 changes: 8 additions & 2 deletions packages/logs/src/boot/startLogs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {

import type { LogsConfiguration } from '../domain/configuration'
import { validateAndBuildLogsConfiguration } from '../domain/configuration'
import { HandlerType, Logger, StatusType } from '../domain/logger'
import { HandlerType, Logger } from '../domain/logger'
import { StatusType } from '../domain/logger/isAuthorized'
import type { startLoggerCollection } from '../domain/logger/loggerCollection'
import type { LogsEvent } from '../logsEvent.types'
import { startLogs } from './startLogs'
Expand Down Expand Up @@ -94,7 +95,12 @@ describe('logs', () => {
))
registerCleanupTask(stopLogs)

handleLog({ message: 'message', status: StatusType.warn, context: { foo: 'bar' } }, logger, COMMON_CONTEXT)
handleLog(
{ message: 'message', status: StatusType.warn, context: { foo: 'bar' } },
logger,
'fake-handling-stack',
COMMON_CONTEXT
)

expect(requests.length).toEqual(1)
expect(requests[0].url).toContain(baseConfiguration.logsEndpointBuilder.build('xhr', DEFAULT_PAYLOAD))
Expand Down
3 changes: 2 additions & 1 deletion packages/logs/src/domain/assembly.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import type { CommonContext } from '../rawLogsEvent.types'
import { startLogsAssembly } from './assembly'
import type { LogsConfiguration } from './configuration'
import { validateAndBuildLogsConfiguration } from './configuration'
import { Logger, StatusType } from './logger'
import { Logger } from './logger'
import { StatusType } from './logger/isAuthorized'
import type { LogsSessionManager } from './logsSessionManager'
import { LifeCycle, LifeCycleEventType } from './lifeCycle'

Expand Down
24 changes: 23 additions & 1 deletion packages/logs/src/domain/console/consoleCollection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ErrorWithCause } from '@datadog/browser-core'
import { ErrorSource, noop, objectEntries } from '@datadog/browser-core'
import { ErrorSource, ExperimentalFeature, noop, objectEntries } from '@datadog/browser-core'
import { mockExperimentalFeatures } from '@datadog/browser-core/test'
import type { RawConsoleLogsEvent } from '../../rawLogsEvent.types'
import { validateAndBuildLogsConfiguration } from '../configuration'
import type { RawLogsEventCollectedData } from '../lifeCycle'
Expand Down Expand Up @@ -51,6 +52,27 @@ describe('console collection', () => {
error: whatever(),
})

expect(rawLogsEvents[0].domainContext).not.toBeDefined()

expect(consoleSpies[api]).toHaveBeenCalled()
})
})

objectEntries(LogStatusForApi).forEach(([api]) => {
it(`should add domainContext to logs from console.${api}`, () => {
mockExperimentalFeatures([ExperimentalFeature.MICRO_FRONTEND])
;({ stop: stopConsoleCollection } = startConsoleCollection(
validateAndBuildLogsConfiguration({ ...initConfiguration, forwardConsoleLogs: 'all' })!,
lifeCycle
))

/* eslint-disable-next-line no-console */
console[api as keyof typeof LogStatusForApi]('foo', 'bar')

expect(rawLogsEvents[0].domainContext).toEqual({
handlingStack: jasmine.any(String),
})
BenoitZugmeyer marked this conversation as resolved.
Show resolved Hide resolved

expect(consoleSpies[api]).toHaveBeenCalled()
})
})
Expand Down
26 changes: 21 additions & 5 deletions packages/logs/src/domain/console/consoleCollection.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import type { Context, ClocksState, ConsoleLog } from '@datadog/browser-core'
import { timeStampNow, ConsoleApiName, ErrorSource, initConsoleObservable } from '@datadog/browser-core'
import {
timeStampNow,
ConsoleApiName,
ErrorSource,
initConsoleObservable,
isExperimentalFeatureEnabled,
ExperimentalFeature,
} from '@datadog/browser-core'
import type { LogsConfiguration } from '../configuration'
import type { LifeCycle } from '../lifeCycle'
import type { LifeCycle, RawLogsEventCollectedData } from '../lifeCycle'
import { LifeCycleEventType } from '../lifeCycle'
import { StatusType } from '../logger'
import { StatusType } from '../logger/isAuthorized'
import type { RawLogsEvent } from '../../rawLogsEvent.types'

export interface ProvidedError {
startClocks: ClocksState
Expand All @@ -21,7 +29,7 @@ export const LogStatusForApi = {
}
export function startConsoleCollection(configuration: LogsConfiguration, lifeCycle: LifeCycle) {
const consoleSubscription = initConsoleObservable(configuration.forwardConsoleLogs).subscribe((log: ConsoleLog) => {
lifeCycle.notify(LifeCycleEventType.RAW_LOG_COLLECTED, {
const collectedData: RawLogsEventCollectedData<RawLogsEvent> = {
rawLogsEvent: {
date: timeStampNow(),
message: log.message,
Expand All @@ -36,7 +44,15 @@ export function startConsoleCollection(configuration: LogsConfiguration, lifeCyc
: undefined,
status: LogStatusForApi[log.api],
},
})
}

if (isExperimentalFeatureEnabled(ExperimentalFeature.MICRO_FRONTEND)) {
collectedData.domainContext = {
handlingStack: log.handlingStack,
}
}

lifeCycle.notify(LifeCycleEventType.RAW_LOG_COLLECTED, collectedData)
})

return {
Expand Down
42 changes: 40 additions & 2 deletions packages/logs/src/domain/logger.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { ErrorWithCause } from '@datadog/browser-core'
import { NO_ERROR_STACK_PRESENT_MESSAGE, createCustomerDataTracker, noop } from '@datadog/browser-core'
import type { LogsMessage } from './logger'
import { HandlerType, Logger, STATUSES, StatusType } from './logger'
import { HandlerType, Logger, STATUSES } from './logger'
import { StatusType } from './logger/isAuthorized'

describe('Logger', () => {
let logger: Logger
let handleLogSpy: jasmine.Spy<(message: LogsMessage, logger: Logger) => void>
let handleLogSpy: jasmine.Spy<(message: LogsMessage, logger: Logger, handlingStack?: string) => void>

function getLoggedMessage(index: number) {
return handleLogSpy.calls.argsFor(index)[0]
Expand All @@ -15,12 +16,20 @@ describe('Logger', () => {
return handleLogSpy.calls.argsFor(index)[1]
}

function getLoggedHandlingStack(index: number) {
return handleLogSpy.calls.argsFor(index)[2]
}

beforeEach(() => {
handleLogSpy = jasmine.createSpy()
logger = new Logger(handleLogSpy, createCustomerDataTracker(noop))
})

describe('log methods', () => {
beforeEach(() => {
logger.setLevel(StatusType.ok)
})

it("'logger.log' should have info status by default", () => {
logger.log('message')

Expand All @@ -45,6 +54,35 @@ describe('Logger', () => {
},
})
})

it(`'logger.${status}' should create an handling stack`, () => {
logger[status]('message')

expect(getLoggedHandlingStack(0)).toBeDefined()
})

it(`'logger.${status}' should not create an handling stack if the handler is 'console'`, () => {
logger.setHandler(HandlerType.console)
logger[status]('message')

expect(getLoggedHandlingStack(0)).not.toBeDefined()
})

it(`'logger.${status}' should not create an handling stack if the handler is 'silent'`, () => {
logger.setHandler(HandlerType.silent)
logger[status]('message')

expect(getLoggedHandlingStack(0)).not.toBeDefined()
})
})

it('should not create an handling stack if level is below the logger level', () => {
logger.setLevel(StatusType.warn)
logger.log('message')
logger.warn('message')

expect(getLoggedHandlingStack(0)).not.toBeDefined()
expect(getLoggedHandlingStack(1)).toBeDefined()
})

it("'logger.log' should send the log message", () => {
Expand Down
Loading