Skip to content

Commit

Permalink
📝 [RUM-158] Add jscdoc to public APIs (#2775)
Browse files Browse the repository at this point in the history
  • Loading branch information
amortemousque authored May 28, 2024
1 parent bd1c3e7 commit f551f53
Show file tree
Hide file tree
Showing 12 changed files with 410 additions and 92 deletions.
18 changes: 16 additions & 2 deletions packages/core/src/boot/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,21 @@ import { assign } from '../tools/utils/polyfills'
// replaced at build time
declare const __BUILD_ENV__SDK_VERSION__: string

export function makePublicApi<T>(stub: T): T & { onReady(callback: () => void): void; version: string } {
export interface PublicApi {
/**
* Version of the Logs browser SDK
*/
version: string

/**
* [For CDN async setup] Early RUM API calls must be wrapped in the `window.DD_RUM.onReady()` callback. This ensures the code only gets executed once the SDK is properly loaded.
*
* See [CDN async setup](https://docs.datadoghq.com/real_user_monitoring/browser/#cdn-async) for further information.
*/
onReady: (callback: () => void) => void
}

export function makePublicApi<T extends PublicApi>(stub: Omit<T, keyof PublicApi>): T {
const publicApi = assign(
{
version: __BUILD_ENV__SDK_VERSION__,
Expand All @@ -29,7 +43,7 @@ export function makePublicApi<T>(stub: T): T & { onReady(callback: () => void):
enumerable: false,
})

return publicApi
return publicApi as T
}

export function defineGlobal<Global, Name extends keyof Global>(global: Global, name: Name, api: Global[Name]) {
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/domain/configuration/configuration.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type { RumEvent } from '../../../../rum-core/src'
import { EXHAUSTIVE_INIT_CONFIGURATION, SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION } from '../../../test'
import type { ExtractTelemetryConfiguration, MapInitConfigurationKey } from '../../../test'
import { display } from '../../tools/display'
import { DOCS_ORIGIN, display } from '../../tools/display'
import {
ExperimentalFeature,
isExperimentalFeatureEnabled,
resetExperimentalFeatures,
} from '../../tools/experimentalFeatures'
import { TrackingConsent } from '../trackingConsent'
import type { InitConfiguration } from './configuration'
import { DOC_LINK, serializeConfiguration, validateAndBuildConfiguration } from './configuration'
import { serializeConfiguration, validateAndBuildConfiguration } from './configuration'

describe('validateAndBuildConfiguration', () => {
const clientToken = 'some_client_token'
Expand Down Expand Up @@ -213,7 +213,9 @@ describe('validateAndBuildConfiguration', () => {
describe('site parameter validation', () => {
it('should validate the site parameter', () => {
validateAndBuildConfiguration({ clientToken, site: 'foo.com' })
expect(displaySpy).toHaveBeenCalledOnceWith(`Site should be a valid Datadog site. Learn more here: ${DOC_LINK}.`)
expect(displaySpy).toHaveBeenCalledOnceWith(
`Site should be a valid Datadog site. Learn more here: ${DOCS_ORIGIN}/getting_started/site/.`
)
})
})

Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { catchUserErrors } from '../../tools/catchUserErrors'
import { display } from '../../tools/display'
import { DOCS_ORIGIN, display } from '../../tools/display'
import type { RawTelemetryConfiguration } from '../telemetry'
import { ExperimentalFeature, addExperimentalFeatures } from '../../tools/experimentalFeatures'
import type { Duration } from '../../tools/utils/timeUtils'
Expand All @@ -14,7 +14,6 @@ import { TrackingConsent } from '../trackingConsent'
import type { TransportConfiguration } from './transportConfiguration'
import { computeTransportConfiguration } from './transportConfiguration'

export const DOC_LINK = 'https://docs.datadoghq.com/getting_started/site/'
export const DefaultPrivacyLevel = {
ALLOW: 'allow',
MASK: 'mask',
Expand Down Expand Up @@ -174,7 +173,7 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
}

if (initConfiguration.site && !isDatadogSite(initConfiguration.site)) {
display.error(`Site should be a valid Datadog site. Learn more here: ${DOC_LINK}.`)
display.error(`Site should be a valid Datadog site. Learn more here: ${DOCS_ORIGIN}/getting_started/site/.`)
return
}

Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/domain/configuration/tags.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ describe('buildTag', () => {
})

function expectWarning() {
expect(displaySpy).toHaveBeenCalledOnceWith("env value doesn't meet tag requirements and will be sanitized")
expect(displaySpy).toHaveBeenCalledOnceWith(
jasmine.stringContaining("env value doesn't meet tag requirements and will be sanitized")
)
}
})
6 changes: 4 additions & 2 deletions packages/core/src/domain/configuration/tags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { display } from '../../tools/display'
import { DOCS_ORIGIN, display } from '../../tools/display'
import type { InitConfiguration } from './configuration'

export const TAG_SIZE_LIMIT = 200
Expand Down Expand Up @@ -32,7 +32,9 @@ export function buildTag(key: string, rawValue: string) {
const valueSizeLimit = TAG_SIZE_LIMIT - key.length - 1

if (rawValue.length > valueSizeLimit || FORBIDDEN_CHARACTERS.test(rawValue)) {
display.warn(`${key} value doesn't meet tag requirements and will be sanitized`)
display.warn(
`${key} value doesn't meet tag requirements and will be sanitized. More details: ${DOCS_ORIGIN}/getting_started/tagging/#defining-tags`
)
}

// Let the backend do most of the sanitization, but still make sure multiple tags can't be crafted
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/domain/context/customerDataTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ONE_KIBI_BYTE, computeBytesCount } from '../../tools/utils/byteUtils'
import { throttle } from '../../tools/utils/functionUtils'
import type { Context } from '../../tools/serialisation/context'
import { jsonStringify } from '../../tools/serialisation/jsonStringify'
import { display } from '../../tools/display'
import { DOCS_ORIGIN, display } from '../../tools/display'
import { isEmptyObject } from '../../tools/utils/objectUtils'
import type { CustomerDataType } from './contextConstants'

Expand Down Expand Up @@ -129,6 +129,6 @@ function displayCustomerDataLimitReachedWarning(bytesCountLimit: number) {
display.warn(
`Customer data exceeds the recommended ${
bytesCountLimit / ONE_KIBI_BYTE
}KiB threshold. More details: https://docs.datadoghq.com/real_user_monitoring/browser/troubleshooting/#customer-data-exceeds-the-recommended-threshold-warning`
}KiB threshold. More details: ${DOCS_ORIGIN}/real_user_monitoring/browser/troubleshooting/#customer-data-exceeds-the-recommended-threshold-warning`
)
}
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export {
} from './tools/experimentalFeatures'
export { trackRuntimeError } from './domain/error/trackRuntimeError'
export { computeStackTrace, StackTrace } from './tools/stackTrace/computeStackTrace'
export { defineGlobal, makePublicApi } from './boot/init'
export { defineGlobal, makePublicApi, PublicApi } from './boot/init'
export { displayAlreadyInitializedError } from './boot/displayAlreadyInitializedError'
export { initReportObservable, RawReport, RawReportType } from './domain/report/reportObservable'
export {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/tools/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ export const display: Display = {
warn: originalConsoleMethods.warn.bind(globalConsole, PREFIX),
error: originalConsoleMethods.error.bind(globalConsole, PREFIX),
}

export const DOCS_ORIGIN = 'https://docs.datadoghq.com'
4 changes: 2 additions & 2 deletions packages/core/src/transport/batch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { display } from '../tools/display'
import { DOCS_ORIGIN, display } from '../tools/display'
import type { Context } from '../tools/serialisation/context'
import { objectValues } from '../tools/utils/polyfills'
import { isPageExitReason } from '../browser/pageExitObservable'
Expand Down Expand Up @@ -81,7 +81,7 @@ export class Batch {

if (estimatedMessageBytesCount >= this.messageBytesLimit) {
display.warn(
`Discarded a message whose size was bigger than the maximum allowed size ${this.messageBytesLimit}KB.`
`Discarded a message whose size was bigger than the maximum allowed size ${this.messageBytesLimit}KB. More details: ${DOCS_ORIGIN}/real_user_monitoring/browser/troubleshooting/#technical-limitations`
)
return
}
Expand Down
163 changes: 140 additions & 23 deletions packages/logs/src/boot/logsPublicApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Context, TrackingConsent, User } from '@datadog/browser-core'
import type { Context, TrackingConsent, User, PublicApi } from '@datadog/browser-core'
import {
addTelemetryUsage,
CustomerDataType,
Expand All @@ -19,6 +19,7 @@ import type { LogsInitConfiguration } from '../domain/configuration'
import type { HandlerType, StatusType } from '../domain/logger'
import { Logger } from '../domain/logger'
import { buildCommonContext } from '../domain/contexts/commonContext'
import type { InternalContext } from '../domain/contexts/internalContext'
import type { StartLogs, StartLogsResult } from './startLogs'
import { createPreStartStrategy } from './preStartLogs'

Expand All @@ -28,7 +29,135 @@ export interface LoggerConfiguration {
context?: object
}

export type LogsPublicApi = ReturnType<typeof makeLogsPublicApi>
export interface LogsPublicApi extends PublicApi {
logger: Logger

/**
* Init the Logs browser SDK.
* @param initConfiguration Configuration options of the SDK
*
* See [Browser Log Collection](https://docs.datadoghq.com/logs/log_collection/javascript) for further information.
*/
init: (initConfiguration: LogsInitConfiguration) => void

/**
* Set the tracking consent of the current user.
*
* @param {"granted" | "not-granted"} trackingConsent The user tracking consent
*
* Logs will be sent only if it is set to "granted". This value won't be stored by the library
* across page loads: you will need to call this method or set the appropriate `trackingConsent`
* field in the init() method at each page load.
*
* If this method is called before the init() method, the provided value will take precedence
* over the one provided as initialization parameter.
*/
setTrackingConsent: (trackingConsent: TrackingConsent) => void

/**
* Get the global Context
*
* See [Overwrite context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information.
*/
getGlobalContext: () => Context

/**
* Set the global context information to all logs, stored in `@context`
*
* @param context Global context
*
* See [Overwrite context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information.
*/
setGlobalContext: (context: any) => void

/**
* Set or update a global context property, stored in `@context.<key>`
*
* @param key Key of the property
* @param property Value of the property
*
* See [Overwrite context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information.
*/
setGlobalContextProperty: (key: any, value: any) => void

/**
* Remove a global context property
*
* See [Overwrite context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information.
*/
removeGlobalContextProperty: (key: any) => void

/**
* Clear the global context
*
* See [Overwrite context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information.
*/
clearGlobalContext: () => void

/**
* The Datadog browser logs SDK contains a default logger `DD_LOGS.logger`, but this API allows to create different ones.
*
* See [Define multiple loggers](https://docs.datadoghq.com/logs/log_collection/javascript/#define-multiple-loggers) for further information.
*/
createLogger: (name: string, conf?: LoggerConfiguration) => Logger

/**
* Get a logger
*
* See [Define multiple loggers](https://docs.datadoghq.com/logs/log_collection/javascript/#define-multiple-loggers) for further information.
*/
getLogger: (name: string) => Logger | undefined

/**
* Get the init configuration
*/
getInitConfiguration: () => LogsInitConfiguration | undefined

/**
* [Internal API] Get the internal SDK context
*
* See [Access internal context](https://docs.datadoghq.com/logs/log_collection/javascript/#access-internal-context) for further information.
*/
getInternalContext: (startTime?: number | undefined) => InternalContext | undefined

/**
* Set user information to all events, stored in `@usr`
*
* See [User context](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information.
*/
setUser: (newUser: User) => void

/**
* Get user information
*
* See [User context](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information.
*/
getUser: () => Context

/**
* Set or update the user property, stored in `@usr.<key>`
*
* @param key Key of the property
* @param property Value of the property
*
* See [User context](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information.
*/
setUserProperty: (key: any, property: any) => void

/**
* Remove a user property
*
* See [User context](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information.
*/
removeUserProperty: (key: any) => void

/**
* Clear all user information
*
* See [User context](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information.
*/
clearUser: () => void
}

const LOGS_STORAGE_KEY = 'logs'

Expand All @@ -39,7 +168,7 @@ export interface Strategy {
handleLog: StartLogsResult['handleLog']
}

export function makeLogsPublicApi(startLogsImpl: StartLogs) {
export function makeLogsPublicApi(startLogsImpl: StartLogs): LogsPublicApi {
const customerDataTrackerManager = createCustomerDataTrackerManager()
const globalContextManager = createContextManager(
customerDataTrackerManager.getOrCreateTracker(CustomerDataType.GlobalContext)
Expand Down Expand Up @@ -70,24 +199,12 @@ export function makeLogsPublicApi(startLogsImpl: StartLogs) {
customerDataTrackerManager.createDetachedTracker()
)

return makePublicApi({
return makePublicApi<LogsPublicApi>({
logger: mainLogger,

init: monitor((initConfiguration: LogsInitConfiguration) => strategy.init(initConfiguration)),

/**
* Set the tracking consent of the current user.
*
* @param {"granted" | "not-granted"} trackingConsent The user tracking consent
*
* Logs will be sent only if it is set to "granted". This value won't be stored by the library
* across page loads: you will need to call this method or set the appropriate `trackingConsent`
* field in the init() method at each page load.
*
* If this method is called before the init() method, the provided value will take precedence
* over the one provided as initialization parameter.
*/
setTrackingConsent: monitor((trackingConsent: TrackingConsent) => {
init: monitor((initConfiguration) => strategy.init(initConfiguration)),

setTrackingConsent: monitor((trackingConsent) => {
trackingConsentState.update(trackingConsent)
addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: trackingConsent })
}),
Expand All @@ -102,7 +219,7 @@ export function makeLogsPublicApi(startLogsImpl: StartLogs) {

clearGlobalContext: monitor(() => globalContextManager.clearContext()),

createLogger: monitor((name: string, conf: LoggerConfiguration = {}) => {
createLogger: monitor((name, conf = {}) => {
customLoggers[name] = new Logger(
(...params) => strategy.handleLog(...params),
customerDataTrackerManager.createDetachedTracker(),
Expand All @@ -115,13 +232,13 @@ export function makeLogsPublicApi(startLogsImpl: StartLogs) {
return customLoggers[name]!
}),

getLogger: monitor((name: string) => customLoggers[name]),
getLogger: monitor((name) => customLoggers[name]),

getInitConfiguration: monitor(() => deepClone(strategy.initConfiguration)),

getInternalContext: monitor((startTime?: number | undefined) => strategy.getInternalContext(startTime)),
getInternalContext: monitor((startTime) => strategy.getInternalContext(startTime)),

setUser: monitor((newUser: User) => {
setUser: monitor((newUser) => {
if (checkUser(newUser)) {
userContextManager.setContext(sanitizeUser(newUser as Context))
}
Expand Down
Loading

0 comments on commit f551f53

Please sign in to comment.