diff --git a/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.spec.ts b/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.spec.ts index 38898e7e36..4e79154f9c 100644 --- a/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.spec.ts +++ b/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.spec.ts @@ -36,6 +36,15 @@ describe('network error collection', () => { url: FAKE_URL, } + function startCollection(forwardErrorsToLogs = true) { + fetchStubManager = stubFetch() + ;({ stop: stopNetworkErrorCollection } = startNetworkErrorCollection( + { ...CONFIGURATION, forwardErrorsToLogs }, + lifeCycle + )) + fetchStub = window.fetch as FetchStub + } + beforeEach(() => { if (isIE()) { pending('no fetch support') @@ -45,9 +54,6 @@ describe('network error collection', () => { lifeCycle.subscribe(LifeCycleEventType.RAW_LOG_COLLECTED, (rawLogsEvent) => rawLogsEvents.push(rawLogsEvent as RawLogsEventCollectedData) ) - fetchStubManager = stubFetch() - ;({ stop: stopNetworkErrorCollection } = startNetworkErrorCollection(CONFIGURATION, lifeCycle)) - fetchStub = window.fetch as FetchStub }) afterEach(() => { @@ -56,6 +62,7 @@ describe('network error collection', () => { }) it('should track server error', (done) => { + startCollection() fetchStub(FAKE_URL).resolveWith(DEFAULT_REQUEST) fetchStubManager.whenAllComplete(() => { @@ -78,7 +85,18 @@ describe('network error collection', () => { }) }) + it('should not track network error when forwardErrorsToLogs is false', (done) => { + startCollection(false) + fetchStub(FAKE_URL).resolveWith(DEFAULT_REQUEST) + + fetchStubManager.whenAllComplete(() => { + expect(rawLogsEvents.length).toEqual(0) + done() + }) + }) + it('should not track intake error', (done) => { + startCollection() fetchStub('https://logs-intake.com/v1/input/send?foo=bar').resolveWith(DEFAULT_REQUEST) fetchStubManager.whenAllComplete(() => { @@ -88,6 +106,7 @@ describe('network error collection', () => { }) it('should track aborted requests', (done) => { + startCollection() fetchStub(FAKE_URL).abort() fetchStubManager.whenAllComplete(() => { @@ -97,6 +116,7 @@ describe('network error collection', () => { }) it('should track refused request', (done) => { + startCollection() fetchStub(FAKE_URL).resolveWith({ ...DEFAULT_REQUEST, status: 0 }) fetchStubManager.whenAllComplete(() => { @@ -106,6 +126,7 @@ describe('network error collection', () => { }) it('should not track client error', (done) => { + startCollection() fetchStub(FAKE_URL).resolveWith({ ...DEFAULT_REQUEST, status: 400 }) fetchStubManager.whenAllComplete(() => { @@ -115,6 +136,7 @@ describe('network error collection', () => { }) it('should not track successful request', (done) => { + startCollection() fetchStub(FAKE_URL).resolveWith({ ...DEFAULT_REQUEST, status: 200 }) fetchStubManager.whenAllComplete(() => { @@ -124,6 +146,7 @@ describe('network error collection', () => { }) it('uses a fallback when the response text is empty', (done) => { + startCollection() fetchStub(FAKE_URL).resolveWith({ ...DEFAULT_REQUEST, responseText: '' }) fetchStubManager.whenAllComplete(() => { diff --git a/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.ts b/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.ts index 9966080125..ebe595fb0d 100644 --- a/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.ts +++ b/packages/logs/src/domain/logsCollection/networkError/networkErrorCollection.ts @@ -16,6 +16,10 @@ import { LifeCycleEventType } from '../../lifeCycle' import { StatusType } from '../../logger' export function startNetworkErrorCollection(configuration: LogsConfiguration, lifeCycle: LifeCycle) { + if (!configuration.forwardErrorsToLogs) { + return { stop: noop } + } + const xhrSubscription = initXhrObservable().subscribe((context) => { if (context.state === 'complete') { handleCompleteRequest(RequestType.XHR, context) diff --git a/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.spec.ts b/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.spec.ts index ef354deff0..f2c5ce4190 100644 --- a/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.spec.ts +++ b/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.spec.ts @@ -1,5 +1,4 @@ -import { ErrorSource, Observable } from '@datadog/browser-core' -import type { RawError, RelativeTime, TimeStamp } from '@datadog/browser-core' +import { ErrorSource } from '@datadog/browser-core' import type { RawRuntimeLogsEvent } from '../../../rawLogsEvent.types' import type { LogsConfiguration } from '../../configuration' import { StatusType } from '../../logger' @@ -8,43 +7,60 @@ import { LifeCycle, LifeCycleEventType } from '../../lifeCycle' import { startRuntimeErrorCollection } from './runtimeErrorCollection' describe('runtime error collection', () => { - let rawErrorObservable: Observable + const configuration = { forwardErrorsToLogs: true } as LogsConfiguration let lifeCycle: LifeCycle let stopRuntimeErrorCollection: () => void let rawLogsEvents: Array> + let onErrorSpy: jasmine.Spy + let originalOnErrorHandler: OnErrorEventHandler beforeEach(() => { + originalOnErrorHandler = window.onerror + onErrorSpy = jasmine.createSpy() + window.onerror = onErrorSpy rawLogsEvents = [] - rawErrorObservable = new Observable() lifeCycle = new LifeCycle() lifeCycle.subscribe(LifeCycleEventType.RAW_LOG_COLLECTED, (rawLogsEvent) => rawLogsEvents.push(rawLogsEvent as RawLogsEventCollectedData) ) - ;({ stop: stopRuntimeErrorCollection } = startRuntimeErrorCollection( - {} as LogsConfiguration, - lifeCycle, - rawErrorObservable - )) }) afterEach(() => { stopRuntimeErrorCollection() + window.onerror = originalOnErrorHandler }) - it('should send runtime errors', () => { - rawErrorObservable.notify({ - message: 'error!', - source: ErrorSource.SOURCE, - startClocks: { relative: 1234 as RelativeTime, timeStamp: 123456789 as TimeStamp }, - type: 'Error', + it('should send runtime errors', (done) => { + ;({ stop: stopRuntimeErrorCollection } = startRuntimeErrorCollection(configuration, lifeCycle)) + setTimeout(() => { + throw new Error('error!') }) - expect(rawLogsEvents[0].rawLogsEvent).toEqual({ - date: 123456789 as TimeStamp, - error: { origin: ErrorSource.SOURCE, kind: 'Error', stack: undefined }, - message: 'error!', - status: StatusType.error, - origin: ErrorSource.SOURCE, + setTimeout(() => { + expect(rawLogsEvents[0].rawLogsEvent).toEqual({ + date: jasmine.any(Number), + error: { origin: ErrorSource.SOURCE, kind: 'Error', stack: jasmine.any(String) }, + message: 'error!', + status: StatusType.error, + origin: ErrorSource.SOURCE, + }) + done() + }, 10) + }) + + it('should not send runtime errors when forwardErrorsToLogs is false', (done) => { + ;({ stop: stopRuntimeErrorCollection } = startRuntimeErrorCollection( + { ...configuration, forwardErrorsToLogs: false }, + lifeCycle + )) + + setTimeout(() => { + throw new Error('error!') }) + + setTimeout(() => { + expect(rawLogsEvents.length).toEqual(0) + done() + }, 10) }) }) diff --git a/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.ts b/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.ts index 6b970c1b7b..db029570b4 100644 --- a/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.ts +++ b/packages/logs/src/domain/logsCollection/runtimeError/runtimeErrorCollection.ts @@ -1,5 +1,5 @@ import type { Context, RawError, ClocksState } from '@datadog/browser-core' -import { ErrorSource, trackRuntimeError, Observable } from '@datadog/browser-core' +import { noop, ErrorSource, trackRuntimeError, Observable } from '@datadog/browser-core' import type { RawRuntimeLogsEvent } from '../../../rawLogsEvent.types' import type { LogsConfiguration } from '../../configuration' import type { LifeCycle } from '../../lifeCycle' @@ -13,15 +13,15 @@ export interface ProvidedError { handlingStack: string } -export function startRuntimeErrorCollection( - configuration: LogsConfiguration, - lifeCycle: LifeCycle, - rawErrorObservable = new Observable() -) { - if (configuration.forwardErrorsToLogs) { - trackRuntimeError(rawErrorObservable) +export function startRuntimeErrorCollection(configuration: LogsConfiguration, lifeCycle: LifeCycle) { + if (!configuration.forwardErrorsToLogs) { + return { stop: noop } } + const rawErrorObservable = new Observable() + + const { stop: stopRuntimeErrorTracking } = trackRuntimeError(rawErrorObservable) + const rawErrorSubscription = rawErrorObservable.subscribe((rawError) => { lifeCycle.notify(LifeCycleEventType.RAW_LOG_COLLECTED, { rawLogsEvent: { @@ -40,6 +40,7 @@ export function startRuntimeErrorCollection( return { stop: () => { + stopRuntimeErrorTracking() rawErrorSubscription.unsubscribe() }, }