Skip to content

Commit

Permalink
✨ Logs beforeSend
Browse files Browse the repository at this point in the history
  • Loading branch information
bcaudan committed Dec 11, 2020
1 parent c924fe1 commit 1aa110a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 49 deletions.
3 changes: 2 additions & 1 deletion packages/logs/src/boot/logs.entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import {
UserConfiguration,
} from '@datadog/browser-core'
import { HandlerType, Logger, LogsMessage, StatusType } from '../domain/logger'
import { LogsEventsFormat } from '../logsEventsFormat'
import { startLogs } from './logs'

export interface LogsUserConfiguration extends UserConfiguration {
forwardErrorsToLogs?: boolean
beforeSend?: (event: LogsEventsFormat) => void
}

export interface LoggerConfiguration {
Expand Down Expand Up @@ -47,7 +49,6 @@ export function makeLogsGlobal(startLogsImpl: StartLogs) {
let sendLogStrategy = (message: LogsMessage, currentContext: Context) => {
beforeInitSendLog.add([message, currentContext])
}

const logger = new Logger(sendLog)

return makeGlobal({
Expand Down
95 changes: 60 additions & 35 deletions packages/logs/src/boot/logs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
import sinon from 'sinon'

import { Logger, LogsMessage, StatusType } from '../domain/logger'
import { assembleMessageContexts, doStartLogs } from './logs'
import { LogsEventsFormat } from '../logsEventsFormat'
import { buildAssemble, doStartLogs } from './logs'

interface SentMessage extends LogsMessage {
logger?: { name: string }
Expand Down Expand Up @@ -126,16 +127,35 @@ describe('logs', () => {
})
})

describe('assembleMessageContexts', () => {
it('assembles various contexts', () => {
expect(
assembleMessageContexts(
{ session_id: SESSION_ID, service: 'Service' },
{ foo: 'from-current-context' },
{ view: { url: 'http://from-rum-context.com', id: 'view-id' } },
DEFAULT_MESSAGE
)
).toEqual({
describe('assemble', () => {
let assemble: (message: LogsMessage, currentContext: Context) => Context | undefined
let beforeSend: (event: LogsEventsFormat) => void

beforeEach(() => {
beforeSend = noop
assemble = buildAssemble(session, {
...(baseConfiguration as Configuration),
beforeSend: (x: LogsEventsFormat) => beforeSend(x),
})
window.DD_RUM = {
getInternalContext: noop,
}
})

it('should not assemble when session is not tracked', () => {
sessionIsTracked = false

expect(assemble(DEFAULT_MESSAGE, { foo: 'from-current-context' })).toBeUndefined()
})

it('add default, current and RUM context to message', () => {
spyOn(window.DD_RUM!, 'getInternalContext').and.returnValue({
view: { url: 'http://from-rum-context.com', id: 'view-id' },
})

const assembledMessage = assemble(DEFAULT_MESSAGE, { foo: 'from-current-context' })

expect(assembledMessage).toEqual({
foo: 'from-current-context',
message: DEFAULT_MESSAGE.message,
service: 'Service',
Expand All @@ -146,36 +166,41 @@ describe('logs', () => {
})

it('message context should take precedence over RUM context', () => {
expect(
assembleMessageContexts(
{},
{ session_id: 'from-rum-context' },
{},
{ ...DEFAULT_MESSAGE, session_id: 'from-message-context' }
).session_id
).toBe('from-message-context')
spyOn(window.DD_RUM!, 'getInternalContext').and.returnValue({ session_id: 'from-rum-context' })

const assembledMessage = assemble({ ...DEFAULT_MESSAGE, session_id: 'from-message-context' }, {})

expect(assembledMessage!.session_id).toBe('from-message-context')
})

it('RUM context should take precedence over current context', () => {
expect(
assembleMessageContexts(
{},
{ session_id: 'from-current-context' },
{ session_id: 'from-rum-context' },
DEFAULT_MESSAGE
).session_id
).toBe('from-rum-context')
spyOn(window.DD_RUM!, 'getInternalContext').and.returnValue({ session_id: 'from-rum-context' })

const assembledMessage = assemble(DEFAULT_MESSAGE, { session_id: 'from-current-context' })

expect(assembledMessage!.session_id).toBe('from-rum-context')
})

it('current context should take precedence over default context', () => {
expect(
assembleMessageContexts(
{ service: 'from-default-context' },
{ service: 'from-current-context' },
undefined,
DEFAULT_MESSAGE
).service
).toBe('from-current-context')
const assembledMessage = assemble(DEFAULT_MESSAGE, { service: 'from-current-context' })

expect(assembledMessage!.service).toBe('from-current-context')
})

it('should allow modification on sensitive field', () => {
beforeSend = (event: LogsEventsFormat) => (event.message = 'modified')

const assembledMessage = assemble(DEFAULT_MESSAGE, {})

expect(assembledMessage!.message).toBe('modified')
})

it('should reject modification on non sensitive field', () => {
beforeSend = (event: LogsEventsFormat) => ((event.service as any) = 'modified')

const assembledMessage = assemble(DEFAULT_MESSAGE, {})

expect(assembledMessage!.service).toBe('Service')
})
})

Expand Down
52 changes: 39 additions & 13 deletions packages/logs/src/boot/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import {
getTimestamp,
HttpRequest,
InternalMonitoring,
limitModification,
noop,
Observable,
RawError,
startAutomaticErrorCollection,
} from '@datadog/browser-core'
import { Logger, LogsMessage } from '../domain/logger'
import { LoggerSession, startLoggerSession } from '../domain/loggerSession'
import { LogsEventsFormat } from '../logsEventsFormat'
import { buildEnv } from './buildEnv'
import { LogsUserConfiguration } from './logs.entry'

const FIELDS_WITH_SENSITIVE_DATA = ['view.url', 'view.referrer', 'message', 'error.stack', 'http.url']

export function startLogs(
userConfiguration: LogsUserConfiguration,
errorLogger: Logger,
Expand All @@ -44,7 +49,8 @@ export function doStartLogs(
combine({ session_id: session.getId() }, getGlobalContext(), getRUMInternalContext())
)

const batch = startLoggerBatch(configuration, session)
const assemble = buildAssemble(session, configuration)
const batch = startLoggerBatch(configuration)

errorObservable.subscribe((error: RawError) => {
errorLogger.error(
Expand Down Expand Up @@ -73,13 +79,14 @@ export function doStartLogs(
})

return (message: LogsMessage, currentContext: Context) => {
if (session.isTracked()) {
batch.add(message, currentContext)
const contextualizedMessage = assemble(message, currentContext)
if (contextualizedMessage) {
batch.add(contextualizedMessage)
}
}
}

function startLoggerBatch(configuration: Configuration, session: LoggerSession) {
function startLoggerBatch(configuration: Configuration) {
const primaryBatch = createLoggerBatch(configuration.logsEndpoint)

let replicaBatch: Batch | undefined
Expand All @@ -98,21 +105,40 @@ function startLoggerBatch(configuration: Configuration, session: LoggerSession)
}

return {
add(message: LogsMessage, currentContext: Context) {
const contextualizedMessage = assembleMessageContexts(
{ service: configuration.service, session_id: session.getId() },
currentContext,
getRUMInternalContext(),
message
)
primaryBatch.add(contextualizedMessage)
add(message: Context) {
primaryBatch.add(message)
if (replicaBatch) {
replicaBatch.add(contextualizedMessage)
replicaBatch.add(message)
}
},
}
}

export function buildAssemble(
session: LoggerSession,
configuration: Configuration
): (message: LogsMessage, currentContext: Context) => Context | undefined {
return (message: LogsMessage, currentContext: Context) => {
if (!session.isTracked()) {
return undefined
}
const contextualizedMessage = combine(
{ service: configuration.service, session_id: session.getId() },
currentContext,
getRUMInternalContext(),
message
)
if (configuration.beforeSend) {
limitModification(
contextualizedMessage as LogsEventsFormat & Context,
FIELDS_WITH_SENSITIVE_DATA,
configuration.beforeSend
)
}
return contextualizedMessage
}
}

export function assembleMessageContexts(
defaultContext: { service?: string; session_id?: string },
currentContext: Context,
Expand Down

0 comments on commit 1aa110a

Please sign in to comment.