UNPKG

@embrace-io/web-sdk

Version:
324 lines (323 loc) 14.9 kB
import { NamespacedStorage } from "../utils/NamespacedStorage/NamespacedStorage.js"; import { nsfConfigValidation } from "../utils/nsfConfigValidation.js"; import { OTelPerformanceManager, updateZeroTimeMillis } from "../utils/PerformanceManager/OTelPerformanceManager.js"; import { log } from "../api-logs/logAPI.js"; import { page } from "../api-page/pageAPI.js"; import { session } from "../api-sessions/sessionAPI.js"; import { trace as trace$1 } from "../api-traces/traceAPI.js"; import { user } from "../api-users/userAPI.js"; import { EmbraceLogExporter } from "../exporters/EmbraceLogExporter/EmbraceLogExporter.js"; import { EmbraceTraceExporter } from "../exporters/EmbraceTraceExporter/EmbraceTraceExporter.js"; import { EmbraceDynamicConfigManager } from "../managers/EmbraceConfigManager/EmbraceDynamicConfigManager.js"; import { DEFAULT_LIMITS } from "../managers/EmbraceLimitManager/constants.js"; import { EmbraceLimitManager } from "../managers/EmbraceLimitManager/EmbraceLimitManager.js"; import { EmbraceLogManager } from "../managers/EmbraceLogManager/EmbraceLogManager.js"; import { EmbracePageManager } from "../managers/EmbracePageManager/EmbracePageManager.js"; import { EmbraceSDKFeaturesManager } from "../managers/EmbraceSDKFeaturesManager/EmbraceSDKFeaturesManager.js"; import { EmbraceTraceManager } from "../managers/EmbraceTraceManager/EmbraceTraceManager.js"; import { EmbraceUserManager } from "../managers/EmbraceUserManager/EmbraceUserManager.js"; import { EmbraceUserSessionManager } from "../managers/EmbraceUserSessionManager/EmbraceUserSessionManager.js"; import { BrowserLogRecordProcessor } from "../processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.js"; import { BrowserSpanProcessor } from "../processors/BrowserSpanProcessor/BrowserSpanProcessor.js"; import { EmbraceLogRecordProcessor } from "../processors/EmbraceLogRecordProcessor/EmbraceLogRecordProcessor.js"; import { EmbraceNetworkSpanProcessor } from "../processors/EmbraceNetworkSpanProcessor/EmbraceNetworkSpanProcessor.js"; import { EmbraceSessionPartBatchedSpanProcessor } from "../processors/EmbraceSessionPartBatchedSpanProcessor/EmbraceSessionPartBatchedSpanProcessor.js"; import { LogRecordScrubProcessor } from "../processors/LogRecordScrubProcessor/LogRecordScrubProcessor.js"; import { PageLogRecordProcessor } from "../processors/PageLogRecordProcessor/PageLogRecordProcessor.js"; import { PageSpanProcessor } from "../processors/PageSpanProcessor/PageSpanProcessor.js"; import { SignalCorrelationLogRecordProcessor } from "../processors/SignalCorrelationLogRecordProcessor/SignalCorrelationLogRecordProcessor.js"; import { SignalCorrelationSpanProcessor } from "../processors/SignalCorrelationSpanProcessor/SignalCorrelationSpanProcessor.js"; import { SpanScrubProcessor } from "../processors/SpanScrubProcessor/SpanScrubProcessor.js"; import { UserLogRecordProcessor } from "../processors/UserLogRecordProcessor/UserLogRecordProcessor.js"; import { UserSessionLogRecordProcessor } from "../processors/UserSessionLogRecordProcessor/UserSessionLogRecordProcessor.js"; import { UserSpanProcessor } from "../processors/UserSpanProcessor/UserSpanProcessor.js"; import { SignalBuffer } from "../processors/utils/SignalBuffer.js"; import { EmbraceW3CTraceContextPropagator } from "../propagators/EmbraceW3CTraceContextPropagator/EmbraceW3CTraceContextPropagator.js"; import { getWebSDKOverridableResource, getWebSDKResource } from "../resources/webSdkResource.js"; import { getDefaultAttributeScrubbers } from "./defaultAttributeScrubbers.js"; import { registry } from "./registry.js"; import { setupDefaultInstrumentations } from "./setupDefaultInstrumentations.js"; import { validateAppID, validateAppVersion } from "./utils.js"; import { DiagConsoleLogger, DiagLogLevel, diag } from "@opentelemetry/api"; import { logs } from "@opentelemetry/api-logs"; import { registerInstrumentations } from "@opentelemetry/instrumentation"; import { emptyResource } from "@opentelemetry/resources"; import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs"; import { BatchSpanProcessor } from "@opentelemetry/sdk-trace"; import { StackContextManager, WebTracerProvider } from "@opentelemetry/sdk-trace-web"; //#region src/sdk/initSDK.ts const initSDK = ({ appID, appVersion, resource = emptyResource(), spanExporters = [], logExporters = [], spanProcessors = [], propagator = null, defaultInstrumentationConfig, instrumentations = [], contextManager = null, logProcessors = [], attributeScrubbers = [], enableDefaultAttributeScrubbing = true, additionalQueryParamsToScrub = [], logLevel = DiagLogLevel.ERROR, embraceDataURL, embraceConfigURL, diagLogger = diag.createComponentLogger({ namespace: "embrace-sdk" }), dynamicSDKConfigManager: providedDynamicSDKConfigManager, dynamicSDKConfig, registerGlobally = true, blockNetworkSpanForwarding = false, restrictedProtocols = /* @__PURE__ */ new Set(["file:"]), useDocumentTitleAsPageLabel = true } = {}) => { try { if (registerGlobally) { const existingSDK = registry.registered(); if (existingSDK !== null) { diagLogger.warn("SDK has already been successfully initialized, skipping this invocation of initSDK"); return existingSDK; } } diag.setLogger(new DiagConsoleLogger(), { logLevel }); if (typeof window === "undefined") { diagLogger.warn("browser not detected, skipping initialization"); return false; } const perf = new OTelPerformanceManager(); const initSDKStart = perf.getNowMillis(); window.addEventListener("pageshow", (event) => updateZeroTimeMillis(perf.epochMillisFromOrigin(event.timeStamp))); const validatedAppID = validateAppID(appID); const validatedAppVersion = validateAppVersion(appVersion); const sendingToEmbrace = validatedAppID !== void 0; if (!sendingToEmbrace && !logExporters.length && !spanExporters.length) throw new Error("when appID is omitted, at least one logExporter or spanExporter must be set"); if (restrictedProtocols.has(window.location.protocol)) throw new Error(`not initializing due to restricted protocol: ${window.location.protocol}`); if (sendingToEmbrace && typeof CompressionStream === "undefined") throw new Error("CompressionStream is not supported in this browser and required for data compression."); const namespace = appID ?? void 0; const sdkLocalStorage = new NamespacedStorage({ namespace, storage: window.localStorage, diag: diagLogger }); const sdkTabStorage = new NamespacedStorage({ namespace, storage: window.sessionStorage, diag: diagLogger }); const resourceWithWebSDKAttributes = getWebSDKOverridableResource().merge(resource).merge(getWebSDKResource({ diagLogger, appVersion: validatedAppVersion, tabStorage: sdkTabStorage })); const userManager = setupUser({ registerGlobally, sdkLocalStorage }); const enduserPseudoID = userManager.getEmbraceUserId(); if (sendingToEmbrace && !enduserPseudoID) throw new Error("userID is required when using Embrace exporter"); const dynamicConfigManager = providedDynamicSDKConfigManager ?? new EmbraceDynamicConfigManager({ appID: validatedAppID, appVersion: validatedAppVersion, embraceConfigURL, defaultConfig: dynamicSDKConfig, deviceId: enduserPseudoID, storage: sdkLocalStorage }); dynamicConfigManager.refreshRemoteConfig(); const sdkFeaturesManager = new EmbraceSDKFeaturesManager({ dynamicConfigManager, deviceId: enduserPseudoID, blockNetworkSpanForwarding }); if (!sdkFeaturesManager.isSDKEnabled()) { diagLogger.debug("SDK is disabled, skipping initialization."); return false; } const nsfValid = nsfConfigValidation({ featureManager: sdkFeaturesManager, diag: diagLogger, registerGlobally, defaultInstrumentationConfig, propagator }); const limitManager = new EmbraceLimitManager(DEFAULT_LIMITS); const finalAttributeScrubbers = [...enableDefaultAttributeScrubbing ? getDefaultAttributeScrubbers(additionalQueryParamsToScrub) : [], ...attributeScrubbers]; const userSessionManager = setupUserSession({ limitManager, perf, registerGlobally, sdkLocalStorage, visibilityDoc: window.document, dynamicConfigManager }); let embraceSpanProcessor; let embraceLogProcessor; if (sendingToEmbrace) { embraceSpanProcessor = new EmbraceSessionPartBatchedSpanProcessor({ exporter: new EmbraceTraceExporter({ appID: validatedAppID, embraceDataURL, userID: enduserPseudoID }), limitManager, userSessionManager }); embraceLogProcessor = new BatchLogRecordProcessor({ exporter: new EmbraceLogExporter({ appID: validatedAppID, embraceDataURL, userID: enduserPseudoID }) }); } const pageManager = setupPage({ useDocumentTitleAsPageLabel, registerGlobally, userSessionManager, perf }); const signalBuffer = !defaultInstrumentationConfig?.omit?.has("soft-navigation-performance") ? new SignalBuffer() : void 0; const { tracerProvider, embraceTraceManager } = setupTraces({ resource: resourceWithWebSDKAttributes, userManager, spanExporters, spanProcessors, propagator: nsfValid ? new EmbraceW3CTraceContextPropagator() : propagator, contextManager, attributeScrubbers: finalAttributeScrubbers, registerGlobally, embraceSpanProcessor, pageManager, signalBuffer }); userSessionManager.setTracerProvider(tracerProvider); userSessionManager.startSessionPartInternal({ reason: "init" }); const { loggerProvider, embraceLogManager } = setupLogs({ resource: resourceWithWebSDKAttributes, userManager, logExporters, logProcessors, userSessionManager, limitManager, attributeScrubbers: finalAttributeScrubbers, perf, registerGlobally, embraceLogProcessor, sdkLocalStorage, pageManager, visibilityDoc: window.document, signalBuffer }); if (!registerGlobally) registerInstrumentations({ tracerProvider, loggerProvider, instrumentations: [setupDefaultInstrumentations(defaultInstrumentationConfig, { logManager: embraceLogManager, userSessionManager, pageManager, limitManager, signalBuffer }), ...instrumentations] }); else registerInstrumentations({ instrumentations: [setupDefaultInstrumentations(defaultInstrumentationConfig, { pageManager, limitManager, signalBuffer }), ...instrumentations] }); diagLogger.info("successfully initialized the SDK"); const sdkControl = { setDynamicConfig: (config) => { dynamicConfigManager.setConfig(config); }, flush: async () => { await tracerProvider.forceFlush(); await loggerProvider.forceFlush(); }, log: embraceLogManager, trace: embraceTraceManager, session: userSessionManager, user: userManager, page: pageManager }; if (registerGlobally) registry.register(sdkControl); userSessionManager.recordSDKStartupDuration(perf.getNowMillis() - initSDKStart); return sdkControl; } catch (e) { const message = e instanceof Error ? e.message : "Unknown error."; diagLogger.error(`failed to initialize the SDK: ${message}`); return false; } }; const setupUser = ({ registerGlobally, sdkLocalStorage }) => { const embraceUserManager = new EmbraceUserManager({ storage: sdkLocalStorage }); if (registerGlobally) user.setGlobalUserManager(embraceUserManager); return embraceUserManager; }; const setupUserSession = ({ limitManager, perf, registerGlobally, sdkLocalStorage, visibilityDoc, dynamicConfigManager }) => { const embraceUserSessionManager = new EmbraceUserSessionManager({ limitManager, perf, storage: sdkLocalStorage, visibilityDoc, dynamicConfigManager }); if (registerGlobally) session.setGlobalUserSessionManager(embraceUserSessionManager); return embraceUserSessionManager; }; const setupTraces = ({ resource, userManager, spanExporters, spanProcessors = [], propagator = null, contextManager = null, attributeScrubbers, registerGlobally, embraceSpanProcessor, pageManager, signalBuffer }) => { const finalSpanProcessors = [ ...spanProcessors, new BrowserSpanProcessor(), new EmbraceNetworkSpanProcessor(), new UserSpanProcessor({ userManager }), new PageSpanProcessor({ pageManager }), new SpanScrubProcessor({ attributeScrubbers }), ...signalBuffer ? [new SignalCorrelationSpanProcessor({ buffer: signalBuffer })] : [] ]; spanExporters?.forEach((exporter) => { finalSpanProcessors.push(new BatchSpanProcessor({ exporter })); }); if (embraceSpanProcessor) finalSpanProcessors.push(embraceSpanProcessor); const tracerProvider = new WebTracerProvider({ resource, spanProcessors: finalSpanProcessors, spanLimits: { attributeCountLimit: DEFAULT_LIMITS.maxAllowed.session_property * 2, eventCountLimit: DEFAULT_LIMITS.maxAllowed.breadcrumb * 2 } }); const embraceTraceManager = new EmbraceTraceManager({ tracerProvider: registerGlobally ? void 0 : tracerProvider }); if (registerGlobally) { trace$1.setGlobalTraceManager(embraceTraceManager); tracerProvider.register({ contextManager: contextManager || new StackContextManager(), propagator }); } return { tracerProvider, embraceTraceManager }; }; const setupLogs = ({ resource, userManager, logExporters, logProcessors, userSessionManager, limitManager, attributeScrubbers, perf, registerGlobally, embraceLogProcessor, sdkLocalStorage, pageManager, visibilityDoc, signalBuffer }) => { const finalLogProcessors = [ ...logProcessors, new UserSessionLogRecordProcessor({ userSessionManager }), new BrowserLogRecordProcessor(), new EmbraceLogRecordProcessor(), new UserLogRecordProcessor({ userManager }), new LogRecordScrubProcessor({ attributeScrubbers }), new PageLogRecordProcessor({ pageManager }), ...signalBuffer ? [new SignalCorrelationLogRecordProcessor({ buffer: signalBuffer })] : [] ]; logExporters?.forEach((exporter) => { finalLogProcessors.push(new BatchLogRecordProcessor({ exporter })); }); if (embraceLogProcessor) finalLogProcessors.push(embraceLogProcessor); const loggerProvider = new LoggerProvider({ resource, processors: finalLogProcessors }); const embraceLogManager = new EmbraceLogManager({ userSessionManager, limitManager, loggerProvider: registerGlobally ? void 0 : loggerProvider, perf, storage: sdkLocalStorage, visibilityDoc }); if (registerGlobally) { logs.setGlobalLoggerProvider(loggerProvider); log.setGlobalLogManager(embraceLogManager); } return { loggerProvider, embraceLogManager }; }; const setupPage = ({ useDocumentTitleAsPageLabel, registerGlobally, userSessionManager, perf }) => { const embracePageManager = new EmbracePageManager({ useDocumentTitleAsPageLabel, userSessionManager, perf }); if (registerGlobally) page.setGlobalPageManager(embracePageManager); return embracePageManager; }; //#endregion export { initSDK }; //# sourceMappingURL=initSDK.js.map