{"version":3,"file":"UIProfiler.js","sources":["../../../../../src/profiling/UIProfiler.ts"],"sourcesContent":["import type { Client, ContinuousProfiler, ProfileChunk, ProfileChunkEnvelope, Span } from '@sentry/core/browser';\nimport {\n createEnvelope,\n debug,\n dsnToString,\n getGlobalScope,\n getRootSpan,\n getSdkMetadataForEnvelopeHeader,\n uuid4,\n} from '@sentry/core/browser';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from './../debug-build';\nimport type { JSSelfProfiler } from './jsSelfProfiling';\nimport {\n createProfileChunkPayload,\n setThreadAttributes,\n shouldProfileSession,\n startJSSelfProfile,\n validateProfileChunk,\n} from './utils';\n\nconst CHUNK_INTERVAL_MS = 60_000; // 1 minute\n// Maximum length for trace lifecycle profiling per root span (e.g. if spanEnd never fires)\nconst MAX_ROOT_SPAN_PROFILE_MS = 300_000; // 5 minutes max per root span in trace mode\n\n/**\n * UIProfiler (Profiling V2):\n * Supports two lifecycle modes:\n * - 'manual': controlled explicitly via start()/stop()\n * - 'trace': automatically runs while there are active sampled root spans\n *\n * Profiles are emitted as standalone `profile_chunk` envelopes either when:\n * - there are no more sampled root spans, or\n * - the 60s chunk timer elapses while profiling is running.\n */\nexport class UIProfiler implements ContinuousProfiler {\n private _client: Client | undefined;\n private _profiler: JSSelfProfiler | undefined;\n private _chunkTimer: ReturnType | undefined;\n\n // Manual + Trace\n private _profilerId: string | undefined; // one per Profiler session\n private _isRunning: boolean; // current profiler instance active flag\n private _sessionSampled: boolean; // sampling decision for entire session\n private _lifecycleMode: 'manual' | 'trace' | undefined;\n\n // Trace-only\n private _activeRootSpanIds: Set;\n private _rootSpanTimeouts: Map>;\n\n public constructor() {\n this._client = undefined;\n this._profiler = undefined;\n this._chunkTimer = undefined;\n\n this._profilerId = undefined;\n this._isRunning = false;\n this._sessionSampled = false;\n this._lifecycleMode = undefined;\n\n this._activeRootSpanIds = new Set();\n this._rootSpanTimeouts = new Map();\n }\n\n /**\n * Initialize the profiler with client, session sampling and lifecycle mode.\n */\n public initialize(client: Client): void {\n const lifecycleMode = (client.getOptions() as BrowserOptions).profileLifecycle;\n const sessionSampled = shouldProfileSession(client.getOptions());\n\n DEBUG_BUILD && debug.log(`[Profiling] Initializing profiler (lifecycle='${lifecycleMode}').`);\n\n if (!sessionSampled) {\n DEBUG_BUILD && debug.log('[Profiling] Session not sampled. Skipping lifecycle profiler initialization.');\n }\n\n // One Profiler ID per profiling session (user session)\n this._profilerId = uuid4();\n this._client = client;\n this._sessionSampled = sessionSampled;\n this._lifecycleMode = lifecycleMode;\n\n if (lifecycleMode === 'trace') {\n this._setupTraceLifecycleListeners(client);\n }\n\n client.on('spanStart', span => {\n if (this._isRunning) {\n setThreadAttributes(span);\n }\n });\n }\n\n /** Starts UI profiling (only effective in 'manual' mode and when sampled). */\n public start(): void {\n if (this._lifecycleMode === 'trace') {\n DEBUG_BUILD &&\n debug.warn(\n '[Profiling] `profileLifecycle` is set to \"trace\". Calls to `uiProfiler.start()` are ignored in trace mode.',\n );\n return;\n }\n\n if (this._isRunning) {\n DEBUG_BUILD && debug.warn('[Profiling] Profile session is already running, `uiProfiler.start()` is a no-op.');\n return;\n }\n\n if (!this._sessionSampled) {\n DEBUG_BUILD && debug.warn('[Profiling] Session is not sampled, `uiProfiler.start()` is a no-op.');\n return;\n }\n\n this._beginProfiling();\n }\n\n /** Stops UI profiling (only effective in 'manual' mode). */\n public stop(): void {\n if (this._lifecycleMode === 'trace') {\n DEBUG_BUILD &&\n debug.warn(\n '[Profiling] `profileLifecycle` is set to \"trace\". Calls to `uiProfiler.stop()` are ignored in trace mode.',\n );\n return;\n }\n\n if (!this._isRunning) {\n DEBUG_BUILD && debug.warn('[Profiling] Profiler is not running, `uiProfiler.stop()` is a no-op.');\n return;\n }\n\n this._endProfiling();\n }\n\n /** Handle an already-active root span at integration setup time (used only in trace mode). */\n public notifyRootSpanActive(rootSpan: Span): void {\n if (this._lifecycleMode !== 'trace' || !this._sessionSampled) {\n return;\n }\n\n const spanId = rootSpan.spanContext().spanId;\n if (!spanId || this._activeRootSpanIds.has(spanId)) {\n return;\n }\n\n this._registerTraceRootSpan(spanId);\n\n const rootSpanCount = this._activeRootSpanIds.size;\n\n if (rootSpanCount === 1) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Detected already active root span during setup. Active root spans now:', rootSpanCount);\n\n this._beginProfiling();\n }\n\n if (this._isRunning) {\n setThreadAttributes(rootSpan);\n }\n }\n\n /**\n * Begin profiling if not already running.\n */\n private _beginProfiling(): void {\n if (this._isRunning) {\n return;\n }\n this._isRunning = true;\n\n DEBUG_BUILD && debug.log('[Profiling] Started profiling with profiler ID:', this._profilerId);\n\n // Expose profiler_id to match root spans with profiles\n getGlobalScope().setContext('profile', { profiler_id: this._profilerId });\n\n this._startProfilerInstance();\n\n if (!this._profiler) {\n DEBUG_BUILD && debug.log('[Profiling] Failed to start JS Profiler; stopping.');\n this._resetProfilerInfo();\n return;\n }\n\n this._startPeriodicChunking();\n }\n\n /** End profiling session; final chunk will be collected and sent. */\n private _endProfiling(): void {\n if (!this._isRunning) {\n return;\n }\n this._isRunning = false;\n\n if (this._chunkTimer) {\n clearTimeout(this._chunkTimer);\n this._chunkTimer = undefined;\n }\n\n this._clearAllRootSpanTimeouts();\n\n // Collect whatever was currently recording\n this._collectCurrentChunk().catch(e => {\n DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk on `stop()`:', e);\n });\n\n // Manual: Clear profiling context so spans outside start()/stop() aren't marked as profiled\n // Trace: Profile context is kept for the whole session duration\n if (this._lifecycleMode === 'manual') {\n getGlobalScope().setContext('profile', {});\n }\n }\n\n /** Trace-mode: attach spanStart/spanEnd listeners. */\n private _setupTraceLifecycleListeners(client: Client): void {\n client.on('spanStart', span => {\n if (!this._sessionSampled) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Span not profiled because of negative sampling decision for user session.');\n return;\n }\n if (span !== getRootSpan(span)) {\n return; // only care about root spans\n }\n // Only count sampled root spans\n if (!span.isRecording()) {\n DEBUG_BUILD && debug.log('[Profiling] Discarding profile because root span was not sampled.');\n return;\n }\n\n const spanId = span.spanContext().spanId;\n if (!spanId || this._activeRootSpanIds.has(spanId)) {\n return;\n }\n\n this._registerTraceRootSpan(spanId);\n\n const rootSpanCount = this._activeRootSpanIds.size;\n if (rootSpanCount === 1) {\n DEBUG_BUILD &&\n debug.log(\n `[Profiling] Root span ${spanId} started. Profiling active while there are active root spans (count=${rootSpanCount}).`,\n );\n this._beginProfiling();\n }\n });\n\n client.on('spanEnd', span => {\n if (!this._sessionSampled) {\n return;\n }\n const spanId = span.spanContext().spanId;\n if (!spanId || !this._activeRootSpanIds.has(spanId)) {\n return;\n }\n this._activeRootSpanIds.delete(spanId);\n const rootSpanCount = this._activeRootSpanIds.size;\n\n DEBUG_BUILD &&\n debug.log(\n `[Profiling] Root span with ID ${spanId} ended. Will continue profiling for as long as there are active root spans (currently: ${rootSpanCount}).`,\n );\n if (rootSpanCount === 0) {\n this._collectCurrentChunk().catch(e => {\n DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk on last `spanEnd`:', e);\n });\n this._endProfiling();\n }\n });\n }\n\n /**\n * Resets profiling information from scope and resets running state (used on failure)\n */\n private _resetProfilerInfo(): void {\n this._isRunning = false;\n getGlobalScope().setContext('profile', {});\n }\n\n /**\n * Clear and reset all per-root-span timeouts.\n */\n private _clearAllRootSpanTimeouts(): void {\n this._rootSpanTimeouts.forEach(timeout => clearTimeout(timeout));\n this._rootSpanTimeouts.clear();\n }\n\n /** Keep track of root spans and schedule safeguard timeout (trace mode). */\n private _registerTraceRootSpan(spanId: string): void {\n this._activeRootSpanIds.add(spanId);\n const timeout = setTimeout(() => this._onRootSpanTimeout(spanId), MAX_ROOT_SPAN_PROFILE_MS);\n this._rootSpanTimeouts.set(spanId, timeout);\n }\n\n /**\n * Start a profiler instance if needed.\n */\n private _startProfilerInstance(): void {\n if (this._profiler?.stopped === false) {\n return; // already running\n }\n const profiler = startJSSelfProfile();\n if (!profiler) {\n DEBUG_BUILD && debug.log('[Profiling] Failed to start JS Profiler.');\n return;\n }\n this._profiler = profiler;\n }\n\n /**\n * Schedule the next 60s chunk while running.\n * Each tick collects a chunk and restarts the profiler.\n * A chunk should be closed when there are no active root spans anymore OR when the maximum chunk interval is reached.\n */\n private _startPeriodicChunking(): void {\n if (!this._isRunning) {\n return;\n }\n\n this._chunkTimer = setTimeout(() => {\n this._collectCurrentChunk().catch(e => {\n DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk during periodic chunking:', e);\n });\n\n if (this._isRunning) {\n this._startProfilerInstance();\n\n if (!this._profiler) {\n // If restart failed, stop scheduling further chunks and reset context.\n this._resetProfilerInfo();\n return;\n }\n\n this._startPeriodicChunking();\n }\n }, CHUNK_INTERVAL_MS);\n }\n\n /**\n * Handle timeout for a specific root span ID to avoid indefinitely running profiler if `spanEnd` never fires.\n * If this was the last active root span, collect the current chunk and stop profiling.\n */\n private _onRootSpanTimeout(rootSpanId: string): void {\n // If span already ended, ignore\n if (!this._rootSpanTimeouts.has(rootSpanId)) {\n return;\n }\n this._rootSpanTimeouts.delete(rootSpanId);\n\n if (!this._activeRootSpanIds.has(rootSpanId)) {\n return;\n }\n\n DEBUG_BUILD &&\n debug.log(\n `[Profiling] Reached 5-minute timeout for root span ${rootSpanId}. You likely started a manual root span that never called \\`.end()\\`.`,\n );\n\n this._activeRootSpanIds.delete(rootSpanId);\n\n if (this._activeRootSpanIds.size === 0) {\n this._endProfiling();\n }\n }\n\n /**\n * Stop current profiler instance, convert profile to chunk & send.\n */\n private async _collectCurrentChunk(): Promise {\n const prevProfiler = this._profiler;\n this._profiler = undefined;\n\n if (!prevProfiler) {\n return;\n }\n\n try {\n const profile = await prevProfiler.stop();\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const chunk = createProfileChunkPayload(profile, this._client!, this._profilerId);\n\n // Validate chunk before sending\n const validationReturn = validateProfileChunk(chunk);\n if ('reason' in validationReturn) {\n DEBUG_BUILD &&\n debug.log(\n '[Profiling] Discarding invalid profile chunk (this is probably a bug in the SDK):',\n validationReturn.reason,\n );\n return;\n }\n\n this._sendProfileChunk(chunk);\n\n DEBUG_BUILD && debug.log('[Profiling] Collected browser profile chunk.');\n } catch (e) {\n DEBUG_BUILD && debug.log('[Profiling] Error while stopping JS Profiler for chunk:', e);\n }\n }\n\n /**\n * Send a profile chunk as a standalone envelope.\n */\n private _sendProfileChunk(chunk: ProfileChunk): void {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const client = this._client!;\n\n const sdkInfo = getSdkMetadataForEnvelopeHeader(client.getSdkMetadata?.());\n const dsn = client.getDsn();\n const tunnel = client.getOptions().tunnel;\n\n const envelope = createEnvelope(\n {\n event_id: uuid4(),\n sent_at: new Date().toISOString(),\n ...(sdkInfo && { sdk: sdkInfo }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n },\n [[{ type: 'profile_chunk', platform: 'javascript' }, chunk]],\n );\n\n client.sendEnvelope(envelope).then(null, reason => {\n DEBUG_BUILD && debug.error('Error while sending profile chunk envelope:', reason);\n });\n }\n}\n"],"names":[],"mappings":"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"}