diff --git a/packages/core/src/internalMonitoring.ts b/packages/core/src/internalMonitoring.ts index fe102a3bcb..96c4cdb1e3 100644 --- a/packages/core/src/internalMonitoring.ts +++ b/packages/core/src/internalMonitoring.ts @@ -14,7 +14,6 @@ enum StatusType { } export interface MonitoringMessage { - entryType: 'internal' message: string status: StatusType error?: { @@ -47,8 +46,7 @@ export function startInternalMonitoring(configuration: Configuration) { referrer: document.referrer, url: window.location.href, }, - }), - utils.withSnakeCaseKeys + }) ) lodashAssign(monitoringConfiguration, { @@ -88,7 +86,6 @@ export function monitor(fn: T): T { export function addMonitoringMessage(message: string) { addToMonitoringBatch({ message, - entryType: 'internal', status: StatusType.info, }) } @@ -96,7 +93,6 @@ export function addMonitoringMessage(message: string) { function addErrorToMonitoringBatch(e: unknown) { addToMonitoringBatch({ ...formatError(e), - entryType: 'internal', status: StatusType.error, }) } diff --git a/packages/core/src/transport.ts b/packages/core/src/transport.ts index 1a14eb1c9e..bce44b7f88 100644 --- a/packages/core/src/transport.ts +++ b/packages/core/src/transport.ts @@ -39,8 +39,7 @@ export class Batch { private bytesLimit: number, private maxMessageSize: number, private flushTimeout: number, - private contextProvider: () => Context, - private messageProcessor?: (message: Context) => Context + private contextProvider: () => Context ) { this.flushOnVisibilityHidden() this.flushPeriodically() @@ -82,10 +81,7 @@ export class Batch { } private process(message: T) { - let contextualizedMessage = lodashMerge({}, this.contextProvider(), message) as Context - if (this.messageProcessor) { - contextualizedMessage = this.messageProcessor(contextualizedMessage) - } + const contextualizedMessage = lodashMerge({}, this.contextProvider(), message) as Context const processedMessage = jsonStringify(contextualizedMessage)! const messageBytesSize = this.sizeInBytes(processedMessage) return { processedMessage, messageBytesSize } diff --git a/packages/core/test/internalMonitoring.spec.ts b/packages/core/test/internalMonitoring.spec.ts index 3c2077a705..af7d2470ec 100644 --- a/packages/core/test/internalMonitoring.spec.ts +++ b/packages/core/test/internalMonitoring.spec.ts @@ -173,7 +173,6 @@ describe('internal monitoring', () => { expect(JSON.parse(server.requests[0].requestBody)).toEqual({ date: FAKE_DATE, - entry_type: 'internal', error: jasmine.anything(), message: 'message', status: 'error', diff --git a/packages/core/test/transport.spec.ts b/packages/core/test/transport.spec.ts index 15aeac1bce..588e7d273c 100644 --- a/packages/core/test/transport.spec.ts +++ b/packages/core/test/transport.spec.ts @@ -162,24 +162,4 @@ describe('batch', () => { expect(transport.send).not.toHaveBeenCalled() warnStub.restore() }) - - it('should allow to add a custom message processor', () => { - batch = new Batch( - transport, - MAX_SIZE, - BATCH_BYTES_LIMIT, - MESSAGE_BYTES_LIMIT, - FLUSH_TIMEOUT, - () => ({}), - (message: Context) => { - message.message = `*** ${message.message} ***` - return message - } - ) - - batch.add({ message: 'hello' }) - batch.flush() - - expect(transport.send).toHaveBeenCalledWith(`{"message":"*** hello ***"}`, jasmine.any(Number)) - }) }) diff --git a/packages/rum/src/rum.ts b/packages/rum/src/rum.ts index 2804031566..a9c94915f8 100644 --- a/packages/rum/src/rum.ts +++ b/packages/rum/src/rum.ts @@ -134,45 +134,32 @@ export function startRum( ): Omit { let globalContext: Context = {} - const batch = new Batch( - new HttpRequest(configuration.rumEndpoint, configuration.batchBytesLimit), - configuration.maxBatchSize, - configuration.batchBytesLimit, - configuration.maxMessageSize, - configuration.flushTimeout, - () => - lodashMerge( - { - applicationId, - date: new Date().getTime(), - screen: { - // needed for retro compatibility - id: viewId, - url: viewLocation.href, - }, - sessionId: session.getId(), - view: { - id: viewId, - referrer: document.referrer, - url: viewLocation.href, - }, - }, - globalContext - ), - withSnakeCaseKeys + const batch = startRumBatch( + configuration, + session, + () => ({ + applicationId, + date: new Date().getTime(), + screen: { + // needed for retro compatibility + id: viewId, + url: viewLocation.href, + }, + sessionId: session.getId(), + view: { + id: viewId, + referrer: document.referrer, + url: viewLocation.href, + }, + }), + () => globalContext ) - const addRumEvent = (event: RumEvent) => { - if (session.isTracked()) { - batch.add(event) - } - } - - trackView(batch, window.location, lifeCycle, addRumEvent) - trackErrors(lifeCycle, addRumEvent) - trackRequests(configuration, lifeCycle, session, addRumEvent) - trackPerformanceTiming(configuration, lifeCycle, addRumEvent) - trackUserAction(lifeCycle, addRumEvent) + trackView(window.location, lifeCycle, batch.addRumEvent, batch.beforeFlushOnUnload) + trackErrors(lifeCycle, batch.addRumEvent) + trackRequests(configuration, lifeCycle, session, batch.addRumEvent) + trackPerformanceTiming(configuration, lifeCycle, batch.addRumEvent) + trackUserAction(lifeCycle, batch.addUserEvent) return { addRumGlobalContext: monitor((key: string, value: ContextValue) => { @@ -196,6 +183,35 @@ export function startRum( } } +function startRumBatch( + configuration: Configuration, + session: RumSession, + rumContextProvider: () => Context, + globalContextProvider: () => Context +) { + const batch = new Batch( + new HttpRequest(configuration.rumEndpoint, configuration.batchBytesLimit), + configuration.maxBatchSize, + configuration.batchBytesLimit, + configuration.maxMessageSize, + configuration.flushTimeout, + () => lodashMerge(withSnakeCaseKeys(rumContextProvider()), globalContextProvider()) + ) + return { + addRumEvent: (event: RumEvent) => { + if (session.isTracked()) { + batch.add(withSnakeCaseKeys(event as Context)) + } + }, + addUserEvent: (event: RumUserAction) => { + if (session.isTracked()) { + batch.add(event as Context) + } + }, + beforeFlushOnUnload: (handler: () => void) => batch.beforeFlushOnUnload(handler), + } +} + function trackErrors(lifeCycle: LifeCycle, addRumEvent: (event: RumEvent) => void) { lifeCycle.subscribe(LifeCycleEventType.error, ({ message, context }: ErrorMessage) => { addRumEvent({ @@ -211,9 +227,9 @@ function trackErrors(lifeCycle: LifeCycle, addRumEvent: (event: RumEvent) => voi }) } -function trackUserAction(lifeCycle: LifeCycle, addRumEvent: (event: RumEvent) => void) { +function trackUserAction(lifeCycle: LifeCycle, addUserEvent: (event: RumUserAction) => void) { lifeCycle.subscribe(LifeCycleEventType.userAction, ({ name, context }) => { - addRumEvent({ + addUserEvent({ ...context, evt: { name, diff --git a/packages/rum/src/viewTracker.ts b/packages/rum/src/viewTracker.ts index 081a7bfb22..adba5a2ed5 100644 --- a/packages/rum/src/viewTracker.ts +++ b/packages/rum/src/viewTracker.ts @@ -24,10 +24,10 @@ let documentVersion: number let viewMeasures: ViewMeasures export function trackView( - batch: Batch, location: Location, lifeCycle: LifeCycle, - addRumEvent: (event: RumEvent) => void + addRumEvent: (event: RumEvent) => void, + beforeFlushOnUnload: (handler: () => void) => void ) { const scheduleViewUpdate = throttle(monitor(() => updateView(addRumEvent)), THROTTLE_VIEW_UPDATE_PERIOD, { leading: false, @@ -38,7 +38,7 @@ export function trackView( trackMeasures(lifeCycle, scheduleViewUpdate) trackRenewSession(location, lifeCycle, addRumEvent) - batch.beforeFlushOnUnload(() => updateView(addRumEvent)) + beforeFlushOnUnload(() => updateView(addRumEvent)) } function newView(location: Location, addRumEvent: (event: RumEvent) => void) { diff --git a/packages/rum/test/rum.spec.ts b/packages/rum/test/rum.spec.ts index 63781626d8..43ab6ed73f 100644 --- a/packages/rum/test/rum.spec.ts +++ b/packages/rum/test/rum.spec.ts @@ -10,7 +10,7 @@ import sinon from 'sinon' import { LifeCycle, LifeCycleEventType } from '../src/lifeCycle' import { startPerformanceCollection } from '../src/performanceCollection' -import { handleResourceEntry, RumEvent, RumResourceEvent, startRum } from '../src/rum' +import { handleResourceEntry, RumEvent, RumResourceEvent, startRum, UserAction } from '../src/rum' import { RumGlobal } from '../src/rum.entry' function getEntry(addRumEvent: (event: RumEvent) => void, index: number) { @@ -143,6 +143,7 @@ describe('rum session', () => { const FAKE_ERROR: Partial = { message: 'test' } const FAKE_RESOURCE: Partial = { name: 'http://foo.com', entryType: 'resource' } const FAKE_REQUEST: Partial = { url: 'http://foo.com' } + const FAKE_USER_ACTION: UserAction = { name: 'action', context: { foo: 'bar' } } let server: sinon.SinonFakeServer let original: PerformanceObserver | undefined let stubBuilder: PerformanceObserverStubBuilder @@ -176,8 +177,9 @@ describe('rum session', () => { stubBuilder.fakeEntry(FAKE_RESOURCE as PerformanceEntry, 'resource') lifeCycle.notify(LifeCycleEventType.error, FAKE_ERROR as ErrorMessage) lifeCycle.notify(LifeCycleEventType.request, FAKE_REQUEST as RequestDetails) + lifeCycle.notify(LifeCycleEventType.userAction, FAKE_USER_ACTION) - expect(server.requests.length).toEqual(3) + expect(server.requests.length).toEqual(4) }) it('when tracked without resources should not track resources', () => { @@ -213,6 +215,7 @@ describe('rum session', () => { stubBuilder.fakeEntry(FAKE_RESOURCE as PerformanceEntry, 'resource') lifeCycle.notify(LifeCycleEventType.request, FAKE_REQUEST as RequestDetails) lifeCycle.notify(LifeCycleEventType.error, FAKE_ERROR as ErrorMessage) + lifeCycle.notify(LifeCycleEventType.userAction, FAKE_USER_ACTION) expect(server.requests.length).toEqual(0) }) @@ -337,4 +340,35 @@ describe('rum global context', () => { expect((getRumMessage(server, 1) as any).foo).toEqual('bar') expect((getRumMessage(server, 1) as any).bar).toBeUndefined() }) + + it('should not be automatically snake cased', () => { + RUM.setRumGlobalContext({ fooBar: 'foo' }) + lifeCycle.notify(LifeCycleEventType.error, FAKE_ERROR as ErrorMessage) + + expect((getRumMessage(server, 0) as any).fooBar).toEqual('foo') + }) +}) + +describe('rum user action', () => { + let lifeCycle: LifeCycle + let RUM: RumApi + let server: sinon.SinonFakeServer + + beforeEach(() => { + const session = { + getId: () => undefined, + isTracked: () => true, + isTrackedWithResource: () => true, + } + server = sinon.fakeServer.create() + lifeCycle = new LifeCycle() + RUM = startRum('appId', lifeCycle, configuration as Configuration, session) as RumApi + server.requests = [] + }) + + it('should not be automatically snake cased', () => { + lifeCycle.notify(LifeCycleEventType.userAction, { name: 'hello', context: { fooBar: 'foo' } }) + + expect((getRumMessage(server, 0) as any).fooBar).toEqual('foo') + }) }) diff --git a/packages/rum/test/viewTracker.spec.ts b/packages/rum/test/viewTracker.spec.ts index 29f3ba9a94..edef71dcf4 100644 --- a/packages/rum/test/viewTracker.spec.ts +++ b/packages/rum/test/viewTracker.spec.ts @@ -1,5 +1,3 @@ -import { Batch } from '@browser-sdk/core' - import { LifeCycle, LifeCycleEventType } from '../src/lifeCycle' import { PerformanceLongTaskTiming, PerformancePaintTiming, RumEvent, RumViewEvent, UserAction } from '../src/rum' import { trackView, viewId, viewLocation } from '../src/viewTracker' @@ -18,13 +16,7 @@ function setup({ fakeLocation.hash = url.hash }) const fakeLocation: Partial = { pathname: '/foo' } - const fakeBatch: Partial> = { beforeFlushOnUnload: () => undefined } - trackView( - fakeBatch as Batch, - fakeLocation as Location, - lifeCycle || new LifeCycle(), - addRumEvent || (() => undefined) - ) + trackView(fakeLocation as Location, lifeCycle || new LifeCycle(), addRumEvent || (() => undefined), () => undefined) } describe('rum track url change', () => {