import type { TrackingConsent, PublicApi, ContextManager, Account, Context, User } from '@datadog/browser-core' import { ContextManagerMethod, CustomerContextKey, addTelemetryUsage, makePublicApi, monitor, sanitize, displayAlreadyInitializedError, deepClone, createTrackingConsentState, defineContextMethod, startBufferingData, callMonitored, mockable, } from '@datadog/browser-core' import type { LogsInitConfiguration } from '../domain/configuration' 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' import type { StartLogsResult } from './startLogs' import { startLogs } from './startLogs' import { createPreStartStrategy } from './preStartLogs' export interface LoggerConfiguration { level?: StatusType handler?: HandlerType | HandlerType[] context?: object } /** * Public API for the Logs browser SDK. * * See [Browser Log Collection](https://docs.datadoghq.com/logs/log_collection/javascript) for further information. * * @category Main */ export interface LogsPublicApi extends PublicApi { /** * The default logger * * @category Logger */ logger: Logger /** * Init the Logs browser SDK. * * See [Browser Log Collection](https://docs.datadoghq.com/logs/log_collection/javascript) for further information. * * @category Init * @param initConfiguration - Configuration options of the SDK */ init: (initConfiguration: LogsInitConfiguration) => void /** * Set the tracking consent of the current user. * * 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. * * See [User tracking consent](https://docs.datadoghq.com/logs/log_collection/javascript/#user-tracking-consent) for further information. * * @category Privacy * @param trackingConsent - The user tracking consent */ setTrackingConsent: (trackingConsent: TrackingConsent) => void /** * Set the global context information to all events, stored in `@context` * See [Global context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information. * * @category Context - Global Context * @param context - Global context */ setGlobalContext: (context: any) => void /** * Get the global Context * * See [Global context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information. * * @category Context - Global Context */ getGlobalContext: () => Context /** * Set or update a global context property, stored in `@context.` * * See [Global context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information. * * @category Context - Global Context * @param key - Key of the property * @param value - Value of the property */ setGlobalContextProperty: (key: any, value: any) => void /** * Remove a global context property * * See [Global context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information. * * @category Context - Global Context */ removeGlobalContextProperty: (key: any) => void /** * Clear the global context * * See [Global context](https://docs.datadoghq.com/logs/log_collection/javascript/#overwrite-context) for further information. * * @category Context - Global Context */ clearGlobalContext: () => void /** * Set user information to all events, stored in `@usr` * * See [User session](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information. * * @category Context - User * @param newUser - User information */ setUser(newUser: User & { id: string }): void /** * Set user information to all events, stored in `@usr` * * @category Context - User * @deprecated You must specify a user id, favor using {@link setUser} instead * @param newUser - User information with optional id */ setUser(newUser: User): void /** * Get user information * * See [User session](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information. * * @category Context - User * @returns User information */ getUser: () => Context /** * Set or update the user property, stored in `@usr.` * * See [User session](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information. * * @category Context - User * @param key - Key of the property * @param property - Value of the property */ setUserProperty: (key: any, property: any) => void /** * Remove a user property * * @category Context - User * @param key - Key of the property to remove * @see [User session](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information. */ removeUserProperty: (key: any) => void /** * Clear all user information * * See [User session](https://docs.datadoghq.com/logs/log_collection/javascript/#user-context) for further information. * * @category Context - User */ clearUser: () => void /** * Set account information to all events, stored in `@account` * * @category Context - Account * @param newAccount - Account information */ setAccount: (newAccount: Account) => void /** * Get account information * * @category Context - Account * @returns Account information */ getAccount: () => Context /** * Set or update the account property, stored in `@account.` * * @category Context - Account * @param key - Key of the property * @param property - Value of the property */ setAccountProperty: (key: string, property: any) => void /** * Remove an account property * * @category Context - Account * @param key - Key of the property to remove */ removeAccountProperty: (key: string) => void /** * Clear all account information * * @category Context - Account * @returns Clear all account information */ clearAccount: () => 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. * * @category Logger * @param name - Name of the logger * @param conf - Configuration of the logger (level, handler, context) */ 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. * * @category Logger * @param name - Name of the logger */ getLogger: (name: string) => Logger | undefined /** * Get the init configuration * * @category Init * @returns 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. * * @internal */ getInternalContext: (startTime?: number) => InternalContext | undefined } export interface Strategy { init: (initConfiguration: LogsInitConfiguration, errorStack?: string) => void initConfiguration: LogsInitConfiguration | undefined globalContext: ContextManager accountContext: ContextManager userContext: ContextManager getInternalContext: StartLogsResult['getInternalContext'] handleLog: StartLogsResult['handleLog'] } export function makeLogsPublicApi(): LogsPublicApi { const trackingConsentState = createTrackingConsentState() const bufferedDataObservable = startBufferingData().observable let strategy = createPreStartStrategy( buildCommonContext, trackingConsentState, (initConfiguration, configuration, hooks) => { const startLogsResult = mockable(startLogs)( configuration, buildCommonContext, trackingConsentState, bufferedDataObservable, hooks ) strategy = createPostStartStrategy(initConfiguration, startLogsResult) return startLogsResult } ) const getStrategy = () => strategy const customLoggers: { [name: string]: Logger | undefined } = {} const mainLogger = new Logger((...params) => strategy.handleLog(...params)) return makePublicApi({ logger: mainLogger, init: (initConfiguration) => { const errorStack = new Error().stack callMonitored(() => strategy.init(initConfiguration, errorStack)) }, setTrackingConsent: monitor((trackingConsent) => { trackingConsentState.update(trackingConsent) addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: trackingConsent }) }), getGlobalContext: defineContextMethod( getStrategy, CustomerContextKey.globalContext, ContextManagerMethod.getContext ), setGlobalContext: defineContextMethod( getStrategy, CustomerContextKey.globalContext, ContextManagerMethod.setContext ), setGlobalContextProperty: defineContextMethod( getStrategy, CustomerContextKey.globalContext, ContextManagerMethod.setContextProperty ), removeGlobalContextProperty: defineContextMethod( getStrategy, CustomerContextKey.globalContext, ContextManagerMethod.removeContextProperty ), clearGlobalContext: defineContextMethod( getStrategy, CustomerContextKey.globalContext, ContextManagerMethod.clearContext ), createLogger: monitor((name, conf = {}) => { customLoggers[name] = new Logger( (...params) => strategy.handleLog(...params), sanitize(name), conf.handler, conf.level, sanitize(conf.context) as object ) return customLoggers[name] }), getLogger: monitor((name) => customLoggers[name]), getInitConfiguration: monitor(() => deepClone(strategy.initConfiguration)), getInternalContext: monitor((startTime) => strategy.getInternalContext(startTime)), setUser: defineContextMethod(getStrategy, CustomerContextKey.userContext, ContextManagerMethod.setContext), getUser: defineContextMethod(getStrategy, CustomerContextKey.userContext, ContextManagerMethod.getContext), setUserProperty: defineContextMethod( getStrategy, CustomerContextKey.userContext, ContextManagerMethod.setContextProperty ), removeUserProperty: defineContextMethod( getStrategy, CustomerContextKey.userContext, ContextManagerMethod.removeContextProperty ), clearUser: defineContextMethod(getStrategy, CustomerContextKey.userContext, ContextManagerMethod.clearContext), setAccount: defineContextMethod(getStrategy, CustomerContextKey.accountContext, ContextManagerMethod.setContext), getAccount: defineContextMethod(getStrategy, CustomerContextKey.accountContext, ContextManagerMethod.getContext), setAccountProperty: defineContextMethod( getStrategy, CustomerContextKey.accountContext, ContextManagerMethod.setContextProperty ), removeAccountProperty: defineContextMethod( getStrategy, CustomerContextKey.accountContext, ContextManagerMethod.removeContextProperty ), clearAccount: defineContextMethod( getStrategy, CustomerContextKey.accountContext, ContextManagerMethod.clearContext ), }) } function createPostStartStrategy(initConfiguration: LogsInitConfiguration, startLogsResult: StartLogsResult): Strategy { return { init: (initConfiguration: LogsInitConfiguration) => { displayAlreadyInitializedError('DD_LOGS', initConfiguration) }, initConfiguration, ...startLogsResult, } }