{"version":3,"file":"browserMetrics.js","sources":["../../../src/metrics/browserMetrics.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Measurements, Span, SpanAttributes, SpanAttributeValue, StartSpanOptions } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getComponentName,\n isPrimitive,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setMeasurement,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { trackClsAsStandaloneSpan } from './cls';\nimport {\n addClsInstrumentationHandler,\n addLcpInstrumentationHandler,\n addPerformanceInstrumentationHandler,\n addTtfbInstrumentationHandler,\n type PerformanceLongAnimationFrameTiming,\n} from './instrument';\nimport { isValidLcpMetric, trackLcpAsStandaloneSpan } from './lcp';\nimport { resourceTimingToSpanAttributes } from './resourceTiming';\nimport { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';\nimport { getActivationStart } from './web-vitals/lib/getActivationStart';\nimport { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';\nimport { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';\nimport { DEBUG_BUILD } from '../debug-build';\ninterface NavigatorNetworkInformation {\n readonly connection?: NetworkInformation;\n}\n\n// http://wicg.github.io/netinfo/#connection-types\ntype ConnectionType = 'bluetooth' | 'cellular' | 'ethernet' | 'mixed' | 'none' | 'other' | 'unknown' | 'wifi' | 'wimax';\n\n// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum\ntype EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';\n\n// http://wicg.github.io/netinfo/#dom-megabit\ntype Megabit = number;\n// http://wicg.github.io/netinfo/#dom-millisecond\ntype Millisecond = number;\n\n// http://wicg.github.io/netinfo/#networkinformation-interface\ninterface NetworkInformation extends EventTarget {\n // http://wicg.github.io/netinfo/#type-attribute\n readonly type?: ConnectionType;\n // http://wicg.github.io/netinfo/#effectivetype-attribute\n readonly effectiveType?: EffectiveConnectionType;\n // http://wicg.github.io/netinfo/#downlinkmax-attribute\n readonly downlinkMax?: Megabit;\n // http://wicg.github.io/netinfo/#downlink-attribute\n readonly downlink?: Megabit;\n // http://wicg.github.io/netinfo/#rtt-attribute\n readonly rtt?: Millisecond;\n // http://wicg.github.io/netinfo/#savedata-attribute\n readonly saveData?: boolean;\n // http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection\n onchange?: EventListener;\n}\n\n// https://w3c.github.io/device-memory/#sec-device-memory-js-api\ninterface NavigatorDeviceMemory {\n readonly deviceMemory?: number;\n}\n\nconst MAX_INT_AS_BYTES = 2147483647;\n\nlet _performanceCursor: number = 0;\n\nlet _measurements: Measurements = {};\nlet _lcpEntry: LargestContentfulPaint | undefined;\nlet _clsEntry: LayoutShift | undefined;\n\ninterface StartTrackingWebVitalsOptions {\n /**\n * When `true`, CLS is tracked as a standalone span. When `false`, CLS is\n * recorded as a measurement on the pageload span. When `undefined`, CLS\n * tracking is skipped entirely (e.g. because span streaming handles it).\n */\n recordClsStandaloneSpans: boolean | undefined;\n /**\n * When `true`, LCP is tracked as a standalone span. When `false`, LCP is\n * recorded as a measurement on the pageload span. When `undefined`, LCP\n * tracking is skipped entirely (e.g. because span streaming handles it).\n */\n recordLcpStandaloneSpans: boolean | undefined;\n client: Client;\n}\n\n/**\n * Start tracking web vitals.\n * The callback returned by this function can be used to stop tracking & ensure all measurements are final & captured.\n *\n * @deprecated this function will be removed and streamlined once we stop supporting standalone v1\n * @returns A function that forces web vitals collection\n */\nexport function startTrackingWebVitals({\n recordClsStandaloneSpans,\n recordLcpStandaloneSpans,\n client,\n}: StartTrackingWebVitalsOptions): () => void {\n const performance = getBrowserPerformanceAPI();\n if (performance && browserPerformanceTimeOrigin()) {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n if (performance.mark) {\n WINDOW.performance.mark('sentry-tracing-init');\n }\n\n const lcpCleanupCallback = recordLcpStandaloneSpans\n ? trackLcpAsStandaloneSpan(client)\n : recordLcpStandaloneSpans === false\n ? _trackLCP()\n : undefined;\n\n const clsCleanupCallback = recordClsStandaloneSpans\n ? trackClsAsStandaloneSpan(client)\n : recordClsStandaloneSpans === false\n ? _trackCLS()\n : undefined;\n\n const ttfbCleanupCallback = _trackTtfb();\n\n return (): void => {\n ttfbCleanupCallback();\n lcpCleanupCallback?.();\n clsCleanupCallback?.();\n };\n }\n\n return () => undefined;\n}\n\n/**\n * Start tracking long tasks.\n */\nexport function startTrackingLongTasks(): void {\n addPerformanceInstrumentationHandler('longtask', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n\n const { op: parentOp, start_timestamp: parentStartTimestamp } = spanToJSON(parent);\n\n for (const entry of entries) {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding a span if the long task started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-task',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n });\n}\n\n/**\n * Start tracking long animation frames.\n */\nexport function startTrackingLongAnimationFrames(): void {\n // NOTE: the current web-vitals version (3.5.2) does not support long-animation-frame, so\n // we directly observe `long-animation-frame` events instead of through the web-vitals\n // `observe` helper function.\n const observer = new PerformanceObserver(list => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of list.getEntries() as PerformanceLongAnimationFrameTiming[]) {\n if (!entry.scripts[0]) {\n continue;\n }\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n\n const { start_timestamp: parentStartTimestamp, op: parentOp } = spanToJSON(parent);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding the span if the long animation frame started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n const duration = msToSec(entry.duration);\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n };\n\n const initialScript = entry.scripts[0];\n const { invoker, invokerType, sourceURL, sourceFunctionName, sourceCharPosition } = initialScript;\n attributes['browser.script.invoker'] = invoker;\n attributes['browser.script.invoker_type'] = invokerType;\n if (sourceURL) {\n attributes['code.filepath'] = sourceURL;\n }\n if (sourceFunctionName) {\n attributes['code.function'] = sourceFunctionName;\n }\n if (sourceCharPosition !== -1) {\n attributes['browser.script.source_char_position'] = sourceCharPosition;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long-animation-frame',\n attributes,\n });\n }\n });\n\n observer.observe({ type: 'long-animation-frame', buffered: true });\n}\n\n/**\n * Start tracking interaction events.\n */\nexport function startTrackingInteractions(): void {\n addPerformanceInstrumentationHandler('event', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of entries) {\n if (entry.name === 'click') {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n const spanOptions: StartSpanOptions & Required> = {\n name: htmlTreeAsString(entry.target),\n op: `ui.interaction.${entry.name}`,\n startTime: startTime,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n };\n\n const componentName = getComponentName(entry.target);\n if (componentName) {\n spanOptions.attributes['ui.component_name'] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n\nexport { registerInpInteractionListener, startTrackingINP } from './inp';\n\n/**\n * Starts tracking the Cumulative Layout Shift on the current page and collects the value and last entry\n * to the `_measurements` object which ultimately is applied to the pageload span's measurements.\n */\nfunction _trackCLS(): () => void {\n return addClsInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n _measurements['cls'] = { value: metric.value, unit: '' };\n _clsEntry = entry;\n }, true);\n}\n\n/** Starts tracking the Largest Contentful Paint on the current page. */\nfunction _trackLCP(): () => void {\n return addLcpInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n\n _measurements['lcp'] = { value: metric.value, unit: 'millisecond' };\n _lcpEntry = entry as LargestContentfulPaint;\n }, true);\n}\n\nfunction _trackTtfb(): () => void {\n return addTtfbInstrumentationHandler(({ metric }) => {\n const entry = metric.entries[metric.entries.length - 1];\n if (!entry) {\n return;\n }\n\n _measurements['ttfb'] = { value: metric.value, unit: 'millisecond' };\n });\n}\n\ninterface AddPerformanceEntriesOptions {\n /**\n * Flag to determine if CLS should be recorded as a measurement on the pageload span or\n * sent as a standalone span instead.\n * Sending it as a standalone span will yield more accurate LCP values.\n *\n * Default: `false` for backwards compatibility.\n */\n recordClsOnPageloadSpan: boolean;\n\n /**\n * Flag to determine if LCP should be recorded as a measurement on the pageload span or\n * sent as a standalone span instead.\n * Sending it as a standalone span will yield more accurate LCP values.\n *\n * Default: `false` for backwards compatibility.\n */\n recordLcpOnPageloadSpan: boolean;\n\n /**\n * Resource spans with `op`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>;\n\n /**\n * Performance spans created from browser Performance APIs,\n * `performance.mark(...)` nand `performance.measure(...)`\n * with `name`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignorePerformanceApiSpans: Array;\n\n /**\n * Whether span streaming is enabled.\n */\n spanStreamingEnabled?: boolean;\n}\n\n/** Add performance related spans to a transaction */\nexport function addPerformanceEntries(span: Span, options: AddPerformanceEntriesOptions): void {\n const performance = getBrowserPerformanceAPI();\n const origin = browserPerformanceTimeOrigin();\n if (!performance?.getEntries || !origin) {\n // Gatekeeper if performance API not available\n return;\n }\n\n const {\n spanStreamingEnabled,\n ignorePerformanceApiSpans,\n ignoreResourceSpans,\n recordClsOnPageloadSpan,\n recordLcpOnPageloadSpan,\n } = options;\n\n const timeOrigin = msToSec(origin);\n\n const performanceEntries = performance.getEntries();\n\n const { op, start_timestamp: transactionStartTime } = spanToJSON(span);\n\n performanceEntries.slice(_performanceCursor).forEach(entry => {\n const startTime = msToSec(entry.startTime);\n const duration = msToSec(\n // Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.\n // There is a SO post attempting to explain this, but it leaves one with open questions: https://stackoverflow.com/questions/23191918/peformance-getentries-and-negative-duration-display\n // The way we clamp the value is probably not accurate, since we have observed this happen for things that may take a while to load, like for example the replay worker.\n // TODO: Investigate why this happens and how to properly mitigate. For now, this is a workaround to prevent transactions being dropped due to negative duration spans.\n Math.max(0, entry.duration),\n );\n\n if (op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) {\n return;\n }\n\n switch (entry.entryType) {\n case 'navigation': {\n _addNavigationSpans(span, entry as PerformanceNavigationTiming, timeOrigin);\n break;\n }\n case 'mark':\n case 'paint':\n case 'measure': {\n _addMeasureSpans(span, entry, startTime, duration, timeOrigin, ignorePerformanceApiSpans);\n\n // capture web vitals\n const firstHidden = getVisibilityWatcher();\n // Only report if the page wasn't hidden prior to the web vital.\n const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;\n\n if (entry.name === 'first-paint' && shouldRecord) {\n _measurements['fp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n if (entry.name === 'first-contentful-paint' && shouldRecord) {\n _measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' };\n }\n break;\n }\n case 'resource': {\n _addResourceSpans(\n span,\n entry as PerformanceResourceTiming,\n entry.name,\n startTime,\n duration,\n timeOrigin,\n ignoreResourceSpans,\n );\n break;\n }\n // Ignore other entry types.\n }\n });\n\n _performanceCursor = Math.max(performanceEntries.length - 1, 0);\n\n _trackNavigator(span, spanStreamingEnabled);\n\n // Measurements are only available for pageload transactions\n if (op === 'pageload') {\n _addTtfbRequestTimeToMeasurements(_measurements);\n\n if (spanStreamingEnabled) {\n const setAttr = (shortWebVitalName: string, value: number, customAttrName?: string) => {\n const attrKey = customAttrName ?? `browser.web_vital.${shortWebVitalName}.value`;\n span.setAttribute(attrKey, value);\n DEBUG_BUILD && debug.log('Setting web vital attribute', { [attrKey]: value }, 'on pageload span');\n };\n // for streamed pageload spans, we add the web vital measurements as attributes.\n // We omit LCP, CLS and INP because they're tracked separately as spans\n ['ttfb', 'fp', 'fcp'].forEach(measurementName => {\n if (_measurements[measurementName]) {\n setAttr(measurementName, _measurements[measurementName].value);\n }\n });\n if (_measurements['ttfb.requestTime']) {\n setAttr('ttfb.requestTime', _measurements['ttfb.requestTime'].value, 'browser.web_vital.ttfb.request_time');\n }\n } else {\n // TODO (V11): Remove this else branch once we remove v1 standalone spans and transactions\n\n // If CLS standalone spans are enabled, don't record CLS as a measurement\n if (!recordClsOnPageloadSpan) {\n delete _measurements.cls;\n }\n\n // If LCP standalone spans are enabled, don't record LCP as a measurement\n if (!recordLcpOnPageloadSpan) {\n delete _measurements.lcp;\n }\n\n Object.entries(_measurements).forEach(([measurementName, measurement]) => {\n setMeasurement(measurementName, measurement.value, measurement.unit);\n });\n\n _setWebVitalAttributes(span, options);\n }\n\n // Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on\n span.setAttribute(spanStreamingEnabled ? 'browser.performance.time_origin' : 'performance.timeOrigin', timeOrigin);\n\n // In prerendering scenarios, where a page might be prefetched and pre-rendered before the user clicks the link,\n // the navigation starts earlier than when the user clicks it. Web Vitals should always be based on the\n // user-perceived time, so they are not reported from the actual start of the navigation, but rather from the\n // time where the user actively started the navigation, for example by clicking a link.\n // This is user action is called \"activation\" and the time between navigation and activation is stored in\n // the `activationStart` attribute of the \"navigation\" PerformanceEntry.\n span.setAttribute(\n spanStreamingEnabled ? 'browser.performance.navigation.activation_start' : 'performance.activationStart',\n getActivationStart(),\n );\n }\n\n _lcpEntry = undefined;\n _clsEntry = undefined;\n _measurements = {};\n}\n\n/**\n * React 19.2+ creates performance.measure entries for component renders.\n * We can identify them by the `detail.devtools.track` property being set to 'Components ⚛'.\n * see: https://react.dev/reference/dev-tools/react-performance-tracks\n * see: https://github.com/facebook/react/blob/06fcc8f380c6a905c7bc18d94453f623cf8cbc81/packages/react-reconciler/src/ReactFiberPerformanceTrack.js#L454-L473\n */\nfunction isReact19MeasureEntry(entry: PerformanceEntry | null): boolean | void {\n if (entry?.entryType !== 'measure') {\n return;\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return (entry as PerformanceMeasure).detail.devtools.track === 'Components ⚛';\n } catch {\n return;\n }\n}\n\n/**\n * Create measure related spans.\n * Exported only for tests.\n */\nexport function _addMeasureSpans(\n span: Span,\n entry: PerformanceEntry,\n startTime: number,\n duration: number,\n timeOrigin: number,\n ignorePerformanceApiSpans: AddPerformanceEntriesOptions['ignorePerformanceApiSpans'],\n): void {\n if (isReact19MeasureEntry(entry)) {\n return;\n }\n\n if (\n ['mark', 'measure'].includes(entry.entryType) &&\n stringMatchesSomePattern(entry.name, ignorePerformanceApiSpans)\n ) {\n return;\n }\n\n const navEntry = getNavigationEntry(false);\n\n const requestTime = msToSec(navEntry ? navEntry.requestStart : 0);\n // Because performance.measure accepts arbitrary timestamps it can produce\n // spans that happen before the browser even makes a request for the page.\n //\n // An example of this is the automatically generated Next.js-before-hydration\n // spans created by the Next.js framework.\n //\n // To prevent this we will pin the start timestamp to the request start time\n // This does make duration inaccurate, so if this does happen, we will add\n // an attribute to the span\n const measureStartTimestamp = timeOrigin + Math.max(startTime, requestTime);\n const startTimeStamp = timeOrigin + startTime;\n const measureEndTimestamp = startTimeStamp + duration;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n if (measureStartTimestamp !== startTimeStamp) {\n attributes['sentry.browser.measure_happened_before_request'] = true;\n attributes['sentry.browser.measure_start_time'] = measureStartTimestamp;\n }\n\n _addDetailToSpanAttributes(attributes, entry as PerformanceMeasure);\n\n // Measurements from third parties can be off, which would create invalid spans, dropping transactions in the process.\n if (measureStartTimestamp <= measureEndTimestamp) {\n startAndEndSpan(span, measureStartTimestamp, measureEndTimestamp, {\n name: entry.name,\n op: entry.entryType,\n attributes,\n });\n }\n}\n\nfunction _addDetailToSpanAttributes(attributes: SpanAttributes, performanceMeasure: PerformanceMeasure): void {\n try {\n // Accessing detail might throw in some browsers (e.g., Firefox) due to security restrictions\n const detail = performanceMeasure.detail;\n\n if (!detail) {\n return;\n }\n\n // Process detail based on its type\n if (typeof detail === 'object') {\n // Handle object details\n for (const [key, value] of Object.entries(detail)) {\n if (value && isPrimitive(value)) {\n attributes[`sentry.browser.measure.detail.${key}`] = value as SpanAttributeValue;\n } else if (value !== undefined) {\n try {\n // This is user defined so we can't guarantee it's serializable\n attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);\n } catch {\n // Skip values that can't be stringified\n }\n }\n }\n return;\n }\n\n if (isPrimitive(detail)) {\n // Handle primitive details\n attributes['sentry.browser.measure.detail'] = detail as SpanAttributeValue;\n return;\n }\n\n try {\n attributes['sentry.browser.measure.detail'] = JSON.stringify(detail);\n } catch {\n // Skip if stringification fails\n }\n } catch {\n // Silently ignore any errors when accessing detail\n // This handles the Firefox \"Permission denied to access object\" error\n }\n}\n\n/**\n * Instrument navigation entries\n * exported only for tests\n */\nexport function _addNavigationSpans(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n (['unloadEvent', 'redirect', 'domContentLoadedEvent', 'loadEvent', 'connect'] as const).forEach(event => {\n _addPerformanceNavigationTiming(span, entry, event, timeOrigin);\n });\n _addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin, 'TLS/SSL');\n _addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin, 'cache');\n _addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin, 'DNS');\n\n _addRequest(span, entry, timeOrigin);\n}\n\ntype StartEventName =\n | 'secureConnection'\n | 'fetch'\n | 'domainLookup'\n | 'unloadEvent'\n | 'redirect'\n | 'connect'\n | 'domContentLoadedEvent'\n | 'loadEvent';\n\ntype EndEventName =\n | 'domainLookupStart'\n | 'domainLookupEnd'\n | 'unloadEventEnd'\n | 'redirectEnd'\n | 'connectEnd'\n | 'domContentLoadedEventEnd'\n | 'loadEventEnd';\n\n/** Create performance navigation related spans */\nfunction _addPerformanceNavigationTiming(\n span: Span,\n entry: PerformanceNavigationTiming,\n event: StartEventName,\n timeOrigin: number,\n name: string = event,\n): void {\n const eventEnd = _getEndPropertyNameForNavigationTiming(event) satisfies keyof PerformanceNavigationTiming;\n const end = entry[eventEnd];\n const start = entry[`${event}Start`];\n if (!start || !end) {\n return;\n }\n startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {\n op: `browser.${name}`,\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n ...(event === 'redirect' && entry.redirectCount != null ? { 'http.redirect_count': entry.redirectCount } : {}),\n },\n });\n}\n\nfunction _getEndPropertyNameForNavigationTiming(event: StartEventName): EndEventName {\n if (event === 'secureConnection') {\n return 'connectEnd';\n }\n if (event === 'fetch') {\n return 'domainLookupStart';\n }\n return `${event}End`;\n}\n\n/** Create request and response related spans */\nfunction _addRequest(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n const requestStartTimestamp = timeOrigin + msToSec(entry.requestStart);\n const responseEndTimestamp = timeOrigin + msToSec(entry.responseEnd);\n const responseStartTimestamp = timeOrigin + msToSec(entry.responseStart);\n if (entry.responseEnd) {\n // It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in.\n // In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0.\n // In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect\n // these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.\n startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {\n op: 'browser.request',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n\n startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {\n op: 'browser.response',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n}\n\n/**\n * Create resource-related spans.\n * Exported only for tests.\n */\nexport function _addResourceSpans(\n span: Span,\n entry: PerformanceResourceTiming,\n resourceUrl: string,\n startTime: number,\n duration: number,\n timeOrigin: number,\n ignoredResourceSpanOps?: Array,\n): void {\n // we already instrument based on fetch and xhr, so we don't need to\n // duplicate spans here.\n if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {\n return;\n }\n\n const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other';\n if (ignoredResourceSpanOps?.includes(op)) {\n return;\n }\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n const parsedUrl = parseUrl(resourceUrl);\n\n if (parsedUrl.protocol) {\n attributes['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.\n }\n\n if (parsedUrl.host) {\n attributes['server.address'] = parsedUrl.host;\n }\n\n attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);\n\n _setResourceRequestAttributes(entry, attributes, [\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n ['responseStatus', 'http.response.status_code'],\n\n ['transferSize', 'http.response_transfer_size'],\n ['encodedBodySize', 'http.response_content_length'],\n ['decodedBodySize', 'http.decoded_response_content_length'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/renderBlockingStatus\n ['renderBlockingStatus', 'resource.render_blocking_status'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/deliveryType\n ['deliveryType', 'http.response_delivery_type'],\n ]);\n\n const attributesWithResourceTiming: SpanAttributes = { ...attributes, ...resourceTimingToSpanAttributes(entry) };\n\n const startTimestamp = timeOrigin + startTime;\n const endTimestamp = startTimestamp + duration;\n\n startAndEndSpan(span, startTimestamp, endTimestamp, {\n name: resourceUrl.replace(WINDOW.location.origin, ''),\n op,\n attributes: attributesWithResourceTiming,\n });\n}\n\n/**\n * Capture the information of the user agent.\n * TODO v11: Remove non-span-streaming attributes and measurements once we removed transactions\n */\nfunction _trackNavigator(span: Span, spanStreamingEnabled: boolean | undefined): void {\n const navigator = WINDOW.navigator as null | (Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory);\n if (!navigator) {\n return;\n }\n\n // track network connectivity\n const connection = navigator.connection;\n if (connection) {\n if (connection.effectiveType) {\n span.setAttribute(\n spanStreamingEnabled ? 'network.connection.effective_type' : 'effectiveConnectionType',\n connection.effectiveType,\n );\n }\n\n if (connection.type) {\n span.setAttribute(spanStreamingEnabled ? 'network.connection.type' : 'connectionType', connection.type);\n }\n\n if (isMeasurementValue(connection.rtt)) {\n _measurements['connection.rtt'] = { value: connection.rtt, unit: 'millisecond' };\n if (spanStreamingEnabled) {\n span.setAttribute('network.connection.rtt', connection.rtt);\n }\n }\n }\n\n if (isMeasurementValue(navigator.deviceMemory)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.memory.estimated_capacity', navigator.deviceMemory);\n } else {\n span.setAttribute('deviceMemory', `${navigator.deviceMemory} GB`);\n }\n }\n\n if (isMeasurementValue(navigator.hardwareConcurrency)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.processor_count', navigator.hardwareConcurrency);\n } else {\n span.setAttribute('hardwareConcurrency', String(navigator.hardwareConcurrency));\n }\n }\n}\n\n/** Add LCP / CLS data to span to allow debugging */\nfunction _setWebVitalAttributes(span: Span, options: AddPerformanceEntriesOptions): void {\n // Only add LCP attributes if LCP is being recorded on the pageload span\n if (_lcpEntry && options.recordLcpOnPageloadSpan) {\n // Capture Properties of the LCP element that contributes to the LCP.\n\n if (_lcpEntry.element) {\n span.setAttribute('lcp.element', htmlTreeAsString(_lcpEntry.element));\n }\n\n if (_lcpEntry.id) {\n span.setAttribute('lcp.id', _lcpEntry.id);\n }\n\n if (_lcpEntry.url) {\n // Trim URL to the first 200 characters.\n span.setAttribute('lcp.url', _lcpEntry.url.trim().slice(0, 200));\n }\n\n if (_lcpEntry.loadTime != null) {\n // loadTime is the time of LCP that's related to receiving the LCP element response..\n span.setAttribute('lcp.loadTime', _lcpEntry.loadTime);\n }\n\n if (_lcpEntry.renderTime != null) {\n // renderTime is loadTime + rendering time\n // it's 0 if the LCP element is loaded from a 3rd party origin that doesn't send the\n // `Timing-Allow-Origin` header.\n span.setAttribute('lcp.renderTime', _lcpEntry.renderTime);\n }\n\n span.setAttribute('lcp.size', _lcpEntry.size);\n }\n\n // Only add CLS attributes if CLS is being recorded on the pageload span\n if (_clsEntry?.sources && options.recordClsOnPageloadSpan) {\n _clsEntry.sources.forEach((source, index) =>\n span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString(source.node)),\n );\n }\n}\n\ntype ExperimentalResourceTimingProperty =\n | 'renderBlockingStatus'\n | 'deliveryType'\n // For some reason, TS during build, errors on `responseStatus` not being a property of\n // PerformanceResourceTiming while it actually is. Hence, we're adding it here.\n // Perhaps because response status is not yet available in Webkit/Safari.\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n | 'responseStatus';\n\n/**\n * Use this to set any attributes we can take directly form the PerformanceResourceTiming entry.\n *\n * This is just a mapping function for entry->attribute to keep bundle-size minimal.\n * Experimental properties are also accepted (see {@link ExperimentalResourceTimingProperty}).\n * Assumes that all entry properties might be undefined for browser-specific differences.\n * Only accepts string and number values for now and also sets 0-values.\n */\nexport function _setResourceRequestAttributes(\n entry: Partial & Partial>,\n attributes: SpanAttributes,\n properties: [keyof PerformanceResourceTiming | ExperimentalResourceTimingProperty, string][],\n): void {\n properties.forEach(([entryKey, attributeKey]) => {\n const entryVal = entry[entryKey];\n if (\n entryVal != null &&\n ((typeof entryVal === 'number' && entryVal < MAX_INT_AS_BYTES) || typeof entryVal === 'string')\n ) {\n attributes[attributeKey] = entryVal;\n }\n });\n}\n\n/**\n * Add ttfb request time information to measurements.\n *\n * ttfb information is added via vendored web vitals library.\n */\nfunction _addTtfbRequestTimeToMeasurements(_measurements: Measurements): void {\n const navEntry = getNavigationEntry(false);\n if (!navEntry) {\n return;\n }\n\n const { responseStart, requestStart } = navEntry;\n\n if (requestStart <= responseStart) {\n _measurements['ttfb.requestTime'] = {\n value: responseStart - requestStart,\n unit: 'millisecond',\n };\n }\n}\n"],"names":["_measurements"],"mappings":"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"}