@sentry/browser-utils 11.0.0 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/build/cjs/performance/interactions.js +1 -1
- package/build/cjs/performance/interactions.js.map +1 -1
- package/build/cjs/web-vitals/spans.js +2 -2
- package/build/cjs/web-vitals/spans.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/performance/interactions.js +2 -2
- package/build/esm/performance/interactions.js.map +1 -1
- package/build/esm/web-vitals/spans.js +3 -3
- package/build/esm/web-vitals/spans.js.map +1 -1
- package/build/types/performance/interactions.d.ts.map +1 -1
- package/build/types/web-vitals/spans.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,14 +10,17 @@
|
|
|
10
10
|
[](https://www.npmjs.com/package/@sentry/browser-utils)
|
|
11
11
|
[](https://www.npmjs.com/package/@sentry/browser-utils)
|
|
12
12
|
|
|
13
|
+
Shared browser utilities used by Sentry’s JavaScript SDKs.
|
|
14
|
+
|
|
13
15
|
> [!NOTE]
|
|
14
16
|
> This package is an internal library published for use by Sentry-owned JavaScript SDK packages. It is not part of the
|
|
15
17
|
> public API contract and may change in any release. Do not rely on SemVer compatibility if you depend on it directly.
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## Documentation
|
|
18
20
|
|
|
19
|
-
- [
|
|
21
|
+
- [JavaScript SDK documentation](https://docs.sentry.io/platforms/javascript/)
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## Support
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
- [Report a bug](https://github.com/getsentry/sentry-javascript/issues/new/choose)
|
|
26
|
+
- [Contributing](https://github.com/getsentry/sentry-javascript/blob/develop/CONTRIBUTING.md)
|
|
@@ -134,7 +134,7 @@ function trackInteractionsAsSpans(client) {
|
|
|
134
134
|
attributes: {
|
|
135
135
|
[attributes.SENTRY_OP]: op.UI_INTERACTION_CLICK,
|
|
136
136
|
[attributes.SENTRY_ORIGIN]: "auto.browser.interactions",
|
|
137
|
-
...selector && selector !== inp.UNKNOWN_ELEMENT_NAME && {
|
|
137
|
+
...selector && selector !== inp.UNKNOWN_ELEMENT_NAME && { [attributes.BROWSER_WEB_VITAL_INP_TARGET]: selector }
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
140
|
if (componentName$1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactions.js","sources":["../../../src/performance/interactions.ts"],"sourcesContent":["import {\n HTTP_ROUTE,\n ROUTER_NAVIGATION_ROUTE_ID,\n SENTRY_IDLE_SPAN_FINISH_REASON,\n SENTRY_OP,\n SENTRY_ORIGIN,\n SENTRY_SEGMENT_NAME,\n SENTRY_SEGMENT_NAME_SOURCE,\n SENTRY_SOURCE,\n UI_COMPONENT_NAME,\n URL_FULL,\n URL_PATH,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';\nimport type { Client, IntegrationFn, Span, StartSpanOptions, TransactionSource } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n defineIntegration,\n filterCollectedUrl,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n spanToJSON,\n UI_ACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { startIdleSpan } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver';\nimport { UNKNOWN_ELEMENT_NAME } from '../web-vitals/inp';\nimport { isBotUserAgent } from '../isBotUserAgent';\nimport { WINDOW } from '../types';\nimport { msToSec, startAndEndSpan } from './utils';\nimport { getComponentName } from '../component-name';\n\nconst INTEGRATION_NAME = 'Interactions';\n\ninterface InteractionsOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the interaction span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout?: number;\n\n /**\n * The max. time an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout?: number;\n\n /**\n * The max. time a child span of an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout?: number;\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n routeId: string | undefined;\n urlTemplate: string | undefined;\n httpRoute: string | undefined;\n urlPath: string | undefined;\n urlFull: string | undefined;\n}\n\nconst _interactionsIntegration = ((options: InteractionsOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n if (isBotUserAgent()) {\n return;\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n routeId: undefined,\n urlTemplate: undefined,\n httpRoute: undefined,\n urlPath: undefined,\n urlFull: undefined,\n };\n // The pageload/navigation span that is currently in progress, if any. Clicks that happen while one\n // is open are not turned into interaction spans, as they'd compete with the route span for children.\n let inflightRouteSpan: Span | undefined;\n\n function trackRoute(span: Span): void {\n const { name, attributes } = spanToJSON(span);\n latestRoute.name = name;\n // oxlint-disable-next-line typescript/no-deprecated\n latestRoute.source = (attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE]) as\n | TransactionSource\n | undefined;\n latestRoute.routeId = attributes[ROUTER_NAVIGATION_ROUTE_ID] as string | undefined;\n latestRoute.urlTemplate = attributes[URL_TEMPLATE] as string | undefined;\n latestRoute.httpRoute = attributes[HTTP_ROUTE] as string | undefined;\n latestRoute.urlPath = attributes[URL_PATH] as string | undefined;\n latestRoute.urlFull = attributes[URL_FULL] as string | undefined;\n }\n\n client.on('spanStart', span => {\n if (isRouteSpan(span)) {\n inflightRouteSpan = span;\n trackRoute(span);\n }\n });\n\n client.on('spanEnd', span => {\n if (span !== inflightRouteSpan) {\n return;\n }\n inflightRouteSpan = undefined;\n // Re-read the route on end: routing instrumentation frequently renames the pageload or navigation\n // span once the route is resolved, so this is more accurate than what we saw at span start.\n trackRoute(span);\n });\n\n registerInteractionListener(client, latestRoute, () => inflightRouteSpan, options);\n\n trackInteractionsAsSpans(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures user interactions as spans.\n *\n * Important: This integration is considered experimental and might lead to noisy spans. Use at your own risk.\n *\n *\n * Clicks that happen outside of an in-progress pageload or navigation start an idle `ui.action.click` span,\n * named after the last known route, which collects everything the interaction triggers (requests, child spans,\n * …). Additionally, `ui.interaction.click` spans are recorded for the browser's own `event` timing entries.\n *\n * The integration requires `browserTracingIntegration` (or another source of pageload/navigation spans)\n * to know which route an interaction belongs to.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [Sentry.browserTracingIntegration(), Sentry.interactionsIntegration()],\n * });\n * ```\n */\nexport const interactionsIntegration = defineIntegration(_interactionsIntegration);\n\nfunction isRouteSpan(span: Span): boolean {\n if (getRootSpan(span) !== span) {\n return false;\n }\n const op = spanToJSON(span).attributes[SENTRY_OP];\n return op === 'pageload' || op === 'navigation';\n}\n\nfunction registerInteractionListener(\n client: Client,\n latestRoute: RouteInfo,\n getInflightRouteSpan: () => Span | undefined,\n // `startIdleSpan` fills in `TRACING_DEFAULTS` for whatever is left out, which are the same defaults\n // `browserTracingIntegration` uses for its pageload and navigation spans.\n idleSpanOptions: InteractionsOptions,\n): void {\n // `document` is not available in all browser environments (e.g. web workers), and without it there is\n // nothing to click on.\n if (!WINDOW.document) {\n return;\n }\n\n let inflightInteractionSpan: Span | undefined;\n\n addEventListener(\n 'click',\n () => {\n if (getInflightRouteSpan()) {\n DEBUG_BUILD &&\n debug.warn(\n `[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`,\n );\n return;\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);\n return;\n }\n\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n const routeName = latestRoute.routeId || latestRoute.urlTemplate || latestRoute.httpRoute;\n const streamedName = routeName || UI_ACTION_CLICK_SPAN_NAME_FALLBACK;\n // A route id is a name the app gave the route, so it is `custom` rather than a `route` pattern.\n const streamedNameSource = !routeName || latestRoute.routeId ? 'custom' : 'route';\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: hasSpanStreaming ? streamedName : latestRoute.name,\n attributes: {\n [SENTRY_OP]: UI_ACTION_CLICK,\n [SENTRY_SEGMENT_NAME_SOURCE]: hasSpanStreaming ? streamedNameSource : latestRoute.source || 'url',\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(hasSpanStreaming && { [SENTRY_SEGMENT_NAME]: streamedName }),\n ...(latestRoute.routeId && { [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId }),\n ...(latestRoute.urlTemplate && { [URL_TEMPLATE]: latestRoute.urlTemplate }),\n ...(latestRoute.httpRoute && { [HTTP_ROUTE]: latestRoute.httpRoute }),\n ...(latestRoute.urlPath && { [URL_PATH]: latestRoute.urlPath }),\n ...(latestRoute.urlFull && { [URL_FULL]: filterCollectedUrl(latestRoute.urlFull) }),\n },\n },\n idleSpanOptions,\n );\n },\n { capture: true },\n );\n}\n\n/**\n * Record the browser's `event` timing entries for clicks as spans on the currently active span.\n */\nfunction trackInteractionsAsSpans(client: Client): 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 selector = htmlTreeAsString(entry.target);\n const componentName = getComponentName(entry.target);\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: hasSpanStreaming ? componentName || UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK : selector,\n startTime: startTime,\n attributes: {\n [SENTRY_OP]: UI_INTERACTION_CLICK,\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(selector && selector !== UNKNOWN_ELEMENT_NAME && { 'browser.web_vital.inp.target': selector }),\n },\n };\n\n if (componentName) {\n spanOptions.attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n"],"names":["isBotUserAgent","attributes","spanToJSON","SENTRY_SOURCE","SENTRY_SEGMENT_NAME_SOURCE","ROUTER_NAVIGATION_ROUTE_ID","URL_TEMPLATE","HTTP_ROUTE","URL_PATH","URL_FULL","defineIntegration","getRootSpan","SENTRY_OP","WINDOW","DEBUG_BUILD","debug","UI_ACTION_CLICK","SENTRY_IDLE_SPAN_FINISH_REASON","hasSpanStreamingEnabled","UI_ACTION_CLICK_SPAN_NAME_FALLBACK","startIdleSpan","SENTRY_ORIGIN","SENTRY_SEGMENT_NAME","filterCollectedUrl","addPerformanceInstrumentationHandler","getActiveSpan","msToSec","browserPerformanceTimeOrigin","htmlTreeAsString","componentName","getComponentName","UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK","UI_INTERACTION_CLICK","UNKNOWN_ELEMENT_NAME","UI_COMPONENT_NAME","startAndEndSpan"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interactions.js","sources":["../../../src/performance/interactions.ts"],"sourcesContent":["import {\n BROWSER_WEB_VITAL_INP_TARGET,\n HTTP_ROUTE,\n ROUTER_NAVIGATION_ROUTE_ID,\n SENTRY_IDLE_SPAN_FINISH_REASON,\n SENTRY_OP,\n SENTRY_ORIGIN,\n SENTRY_SEGMENT_NAME,\n SENTRY_SEGMENT_NAME_SOURCE,\n SENTRY_SOURCE,\n UI_COMPONENT_NAME,\n URL_FULL,\n URL_PATH,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';\nimport type { Client, IntegrationFn, Span, StartSpanOptions, TransactionSource } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n defineIntegration,\n filterCollectedUrl,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n spanToJSON,\n UI_ACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { startIdleSpan } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver';\nimport { UNKNOWN_ELEMENT_NAME } from '../web-vitals/inp';\nimport { isBotUserAgent } from '../isBotUserAgent';\nimport { WINDOW } from '../types';\nimport { msToSec, startAndEndSpan } from './utils';\nimport { getComponentName } from '../component-name';\n\nconst INTEGRATION_NAME = 'Interactions';\n\ninterface InteractionsOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the interaction span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout?: number;\n\n /**\n * The max. time an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout?: number;\n\n /**\n * The max. time a child span of an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout?: number;\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n routeId: string | undefined;\n urlTemplate: string | undefined;\n httpRoute: string | undefined;\n urlPath: string | undefined;\n urlFull: string | undefined;\n}\n\nconst _interactionsIntegration = ((options: InteractionsOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n if (isBotUserAgent()) {\n return;\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n routeId: undefined,\n urlTemplate: undefined,\n httpRoute: undefined,\n urlPath: undefined,\n urlFull: undefined,\n };\n // The pageload/navigation span that is currently in progress, if any. Clicks that happen while one\n // is open are not turned into interaction spans, as they'd compete with the route span for children.\n let inflightRouteSpan: Span | undefined;\n\n function trackRoute(span: Span): void {\n const { name, attributes } = spanToJSON(span);\n latestRoute.name = name;\n // oxlint-disable-next-line typescript/no-deprecated\n latestRoute.source = (attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE]) as\n | TransactionSource\n | undefined;\n latestRoute.routeId = attributes[ROUTER_NAVIGATION_ROUTE_ID] as string | undefined;\n latestRoute.urlTemplate = attributes[URL_TEMPLATE] as string | undefined;\n latestRoute.httpRoute = attributes[HTTP_ROUTE] as string | undefined;\n latestRoute.urlPath = attributes[URL_PATH] as string | undefined;\n latestRoute.urlFull = attributes[URL_FULL] as string | undefined;\n }\n\n client.on('spanStart', span => {\n if (isRouteSpan(span)) {\n inflightRouteSpan = span;\n trackRoute(span);\n }\n });\n\n client.on('spanEnd', span => {\n if (span !== inflightRouteSpan) {\n return;\n }\n inflightRouteSpan = undefined;\n // Re-read the route on end: routing instrumentation frequently renames the pageload or navigation\n // span once the route is resolved, so this is more accurate than what we saw at span start.\n trackRoute(span);\n });\n\n registerInteractionListener(client, latestRoute, () => inflightRouteSpan, options);\n\n trackInteractionsAsSpans(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures user interactions as spans.\n *\n * Important: This integration is considered experimental and might lead to noisy spans. Use at your own risk.\n *\n *\n * Clicks that happen outside of an in-progress pageload or navigation start an idle `ui.action.click` span,\n * named after the last known route, which collects everything the interaction triggers (requests, child spans,\n * …). Additionally, `ui.interaction.click` spans are recorded for the browser's own `event` timing entries.\n *\n * The integration requires `browserTracingIntegration` (or another source of pageload/navigation spans)\n * to know which route an interaction belongs to.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [Sentry.browserTracingIntegration(), Sentry.interactionsIntegration()],\n * });\n * ```\n */\nexport const interactionsIntegration = defineIntegration(_interactionsIntegration);\n\nfunction isRouteSpan(span: Span): boolean {\n if (getRootSpan(span) !== span) {\n return false;\n }\n const op = spanToJSON(span).attributes[SENTRY_OP];\n return op === 'pageload' || op === 'navigation';\n}\n\nfunction registerInteractionListener(\n client: Client,\n latestRoute: RouteInfo,\n getInflightRouteSpan: () => Span | undefined,\n // `startIdleSpan` fills in `TRACING_DEFAULTS` for whatever is left out, which are the same defaults\n // `browserTracingIntegration` uses for its pageload and navigation spans.\n idleSpanOptions: InteractionsOptions,\n): void {\n // `document` is not available in all browser environments (e.g. web workers), and without it there is\n // nothing to click on.\n if (!WINDOW.document) {\n return;\n }\n\n let inflightInteractionSpan: Span | undefined;\n\n addEventListener(\n 'click',\n () => {\n if (getInflightRouteSpan()) {\n DEBUG_BUILD &&\n debug.warn(\n `[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`,\n );\n return;\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);\n return;\n }\n\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n const routeName = latestRoute.routeId || latestRoute.urlTemplate || latestRoute.httpRoute;\n const streamedName = routeName || UI_ACTION_CLICK_SPAN_NAME_FALLBACK;\n // A route id is a name the app gave the route, so it is `custom` rather than a `route` pattern.\n const streamedNameSource = !routeName || latestRoute.routeId ? 'custom' : 'route';\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: hasSpanStreaming ? streamedName : latestRoute.name,\n attributes: {\n [SENTRY_OP]: UI_ACTION_CLICK,\n [SENTRY_SEGMENT_NAME_SOURCE]: hasSpanStreaming ? streamedNameSource : latestRoute.source || 'url',\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(hasSpanStreaming && { [SENTRY_SEGMENT_NAME]: streamedName }),\n ...(latestRoute.routeId && { [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId }),\n ...(latestRoute.urlTemplate && { [URL_TEMPLATE]: latestRoute.urlTemplate }),\n ...(latestRoute.httpRoute && { [HTTP_ROUTE]: latestRoute.httpRoute }),\n ...(latestRoute.urlPath && { [URL_PATH]: latestRoute.urlPath }),\n ...(latestRoute.urlFull && { [URL_FULL]: filterCollectedUrl(latestRoute.urlFull) }),\n },\n },\n idleSpanOptions,\n );\n },\n { capture: true },\n );\n}\n\n/**\n * Record the browser's `event` timing entries for clicks as spans on the currently active span.\n */\nfunction trackInteractionsAsSpans(client: Client): 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 selector = htmlTreeAsString(entry.target);\n const componentName = getComponentName(entry.target);\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: hasSpanStreaming ? componentName || UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK : selector,\n startTime: startTime,\n attributes: {\n [SENTRY_OP]: UI_INTERACTION_CLICK,\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(selector && selector !== UNKNOWN_ELEMENT_NAME && { [BROWSER_WEB_VITAL_INP_TARGET]: selector }),\n },\n };\n\n if (componentName) {\n spanOptions.attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n"],"names":["isBotUserAgent","attributes","spanToJSON","SENTRY_SOURCE","SENTRY_SEGMENT_NAME_SOURCE","ROUTER_NAVIGATION_ROUTE_ID","URL_TEMPLATE","HTTP_ROUTE","URL_PATH","URL_FULL","defineIntegration","getRootSpan","SENTRY_OP","WINDOW","DEBUG_BUILD","debug","UI_ACTION_CLICK","SENTRY_IDLE_SPAN_FINISH_REASON","hasSpanStreamingEnabled","UI_ACTION_CLICK_SPAN_NAME_FALLBACK","startIdleSpan","SENTRY_ORIGIN","SENTRY_SEGMENT_NAME","filterCollectedUrl","addPerformanceInstrumentationHandler","getActiveSpan","msToSec","browserPerformanceTimeOrigin","htmlTreeAsString","componentName","getComponentName","UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK","UI_INTERACTION_CLICK","UNKNOWN_ELEMENT_NAME","BROWSER_WEB_VITAL_INP_TARGET","UI_COMPONENT_NAME","startAndEndSpan"],"mappings":"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"}
|
|
@@ -245,8 +245,8 @@ function _sendInpSpan(inpValue, entry, standalone = false, attributedSpan, softN
|
|
|
245
245
|
const attributes$1 = {
|
|
246
246
|
[core.SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue
|
|
247
247
|
};
|
|
248
|
-
selector && selector !== inp.UNKNOWN_ELEMENT_NAME && (attributes$1[
|
|
249
|
-
entryInteractionType && (attributes$1[
|
|
248
|
+
selector && selector !== inp.UNKNOWN_ELEMENT_NAME && (attributes$1[attributes.BROWSER_WEB_VITAL_INP_TARGET] = selector);
|
|
249
|
+
entryInteractionType && (attributes$1[attributes.BROWSER_WEB_VITAL_INP_INTERACTION_TYPE] = entryInteractionType);
|
|
250
250
|
if (componentName$1) {
|
|
251
251
|
attributes$1[attributes.UI_COMPONENT_NAME] = componentName$1;
|
|
252
252
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { getComponentName } from '../component-name';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION, UNKNOWN_ELEMENT_NAME } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\nconst INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n hover: UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n drag: UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n press: UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const selector = entry ? htmlTreeAsString(entry.element) : undefined;\n const componentName = entry?.element ? getComponentName(entry.element) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (selector) {\n attributes['browser.web_vital.lcp.element'] = selector;\n }\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const firstSourceNode = entry?.sources[0]?.node;\n const selector = entry ? htmlTreeAsString(firstSourceNode) : undefined;\n const componentName = firstSourceNode ? getComponentName(firstSourceNode) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const entryInteractionType = entry && INP_ENTRY_MAP[entry.name];\n const interactionType = entryInteractionType || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const selector = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : undefined);\n const componentName = entry?.target ? getComponentName(entry.target) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const fallbackName = INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK[interactionType];\n const name = hasSpanStreaming ? componentName || fallbackName : (selector ?? 'Interaction to next paint');\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n };\n\n // The span's name and op always have a value, even for an INP without an entry, so they can't\n // say whether there was an interaction to describe. These attributes can: they are only set for\n // what was actually observed. The name no longer holds the selector either, now that it is the\n // component name or the op's fallback under span streaming.\n // TODO: use the `@sentry/conventions` constants once getsentry/sentry-conventions#641 is released.\n selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes['browser.web_vital.inp.target'] = selector);\n entryInteractionType && (attributes['browser.web_vital.inp.interaction_type'] = entryInteractionType);\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes,\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":["UI_INTERACTION_CLICK","UI_INTERACTION_HOVER","UI_INTERACTION_DRAG","UI_INTERACTION_PRESS","UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK","UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK","UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK","UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK","attributes","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","NAVIGATION","BROWSER_NAVIGATION_TYPE","getNavigationSpanForMetric","DEBUG_BUILD","debug","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","componentName","getComponentName","getClient","hasSpanStreamingEnabled","UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK","UI_COMPONENT_NAME","_emitWebVitalSpan","UI_WEBVITAL_LCP","addClsInstrumentationHandler","timestampInSeconds","UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK","UI_WEBVITAL_CLS","getBrowserPerformanceAPI","addInpInstrumentationHandler","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","getCachedInteractionContext","getActiveSpan","getRootSpan","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","UNKNOWN_ELEMENT_NAME"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { getComponentName } from '../component-name';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION, UNKNOWN_ELEMENT_NAME } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport {\n BROWSER_NAVIGATION_TYPE,\n BROWSER_WEB_VITAL_INP_INTERACTION_TYPE,\n BROWSER_WEB_VITAL_INP_TARGET,\n UI_COMPONENT_NAME,\n} from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\nconst INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n hover: UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n drag: UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n press: UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const selector = entry ? htmlTreeAsString(entry.element) : undefined;\n const componentName = entry?.element ? getComponentName(entry.element) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (selector) {\n attributes['browser.web_vital.lcp.element'] = selector;\n }\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const firstSourceNode = entry?.sources[0]?.node;\n const selector = entry ? htmlTreeAsString(firstSourceNode) : undefined;\n const componentName = firstSourceNode ? getComponentName(firstSourceNode) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const entryInteractionType = entry && INP_ENTRY_MAP[entry.name];\n const interactionType = entryInteractionType || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const selector = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : undefined);\n const componentName = entry?.target ? getComponentName(entry.target) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const fallbackName = INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK[interactionType];\n const name = hasSpanStreaming ? componentName || fallbackName : (selector ?? 'Interaction to next paint');\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n };\n\n // The span's name and op always have a value, even for an INP without an entry, so they can't\n // say whether there was an interaction to describe. These attributes can: they are only set for\n // what was actually observed. The name no longer holds the selector either, now that it is the\n // component name or the op's fallback under span streaming.\n selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes[BROWSER_WEB_VITAL_INP_TARGET] = selector);\n entryInteractionType && (attributes[BROWSER_WEB_VITAL_INP_INTERACTION_TYPE] = entryInteractionType);\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes,\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":["UI_INTERACTION_CLICK","UI_INTERACTION_HOVER","UI_INTERACTION_DRAG","UI_INTERACTION_PRESS","UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK","UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK","UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK","UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK","attributes","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","NAVIGATION","BROWSER_NAVIGATION_TYPE","getNavigationSpanForMetric","DEBUG_BUILD","debug","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","componentName","getComponentName","getClient","hasSpanStreamingEnabled","UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK","UI_COMPONENT_NAME","_emitWebVitalSpan","UI_WEBVITAL_LCP","addClsInstrumentationHandler","timestampInSeconds","UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK","UI_WEBVITAL_CLS","getBrowserPerformanceAPI","addInpInstrumentationHandler","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","getCachedInteractionContext","getActiveSpan","getRootSpan","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","UNKNOWN_ELEMENT_NAME","BROWSER_WEB_VITAL_INP_TARGET","BROWSER_WEB_VITAL_INP_INTERACTION_TYPE"],"mappings":"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"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"11.
|
|
1
|
+
{"type":"module","version":"11.1.0","sideEffects":false}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SENTRY_OP, SENTRY_SOURCE, SENTRY_SEGMENT_NAME_SOURCE, ROUTER_NAVIGATION_ROUTE_ID, URL_TEMPLATE, HTTP_ROUTE, URL_PATH, URL_FULL, SENTRY_SEGMENT_NAME, SENTRY_ORIGIN, SENTRY_IDLE_SPAN_FINISH_REASON, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';
|
|
1
|
+
import { SENTRY_OP, SENTRY_SOURCE, SENTRY_SEGMENT_NAME_SOURCE, ROUTER_NAVIGATION_ROUTE_ID, URL_TEMPLATE, HTTP_ROUTE, URL_PATH, URL_FULL, SENTRY_SEGMENT_NAME, SENTRY_ORIGIN, SENTRY_IDLE_SPAN_FINISH_REASON, BROWSER_WEB_VITAL_INP_TARGET, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';
|
|
2
2
|
import { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';
|
|
3
3
|
import { defineIntegration, getRootSpan, spanToJSON, debug, hasSpanStreamingEnabled, UI_ACTION_CLICK_SPAN_NAME_FALLBACK, filterCollectedUrl, getActiveSpan, browserPerformanceTimeOrigin, UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK } from '@sentry/core';
|
|
4
4
|
import { startIdleSpan } from '@sentry/core/browser';
|
|
@@ -132,7 +132,7 @@ function trackInteractionsAsSpans(client) {
|
|
|
132
132
|
attributes: {
|
|
133
133
|
[SENTRY_OP]: UI_INTERACTION_CLICK,
|
|
134
134
|
[SENTRY_ORIGIN]: "auto.browser.interactions",
|
|
135
|
-
...selector && selector !== UNKNOWN_ELEMENT_NAME && {
|
|
135
|
+
...selector && selector !== UNKNOWN_ELEMENT_NAME && { [BROWSER_WEB_VITAL_INP_TARGET]: selector }
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
138
|
if (componentName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactions.js","sources":["../../../src/performance/interactions.ts"],"sourcesContent":["import {\n HTTP_ROUTE,\n ROUTER_NAVIGATION_ROUTE_ID,\n SENTRY_IDLE_SPAN_FINISH_REASON,\n SENTRY_OP,\n SENTRY_ORIGIN,\n SENTRY_SEGMENT_NAME,\n SENTRY_SEGMENT_NAME_SOURCE,\n SENTRY_SOURCE,\n UI_COMPONENT_NAME,\n URL_FULL,\n URL_PATH,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';\nimport type { Client, IntegrationFn, Span, StartSpanOptions, TransactionSource } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n defineIntegration,\n filterCollectedUrl,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n spanToJSON,\n UI_ACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { startIdleSpan } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver';\nimport { UNKNOWN_ELEMENT_NAME } from '../web-vitals/inp';\nimport { isBotUserAgent } from '../isBotUserAgent';\nimport { WINDOW } from '../types';\nimport { msToSec, startAndEndSpan } from './utils';\nimport { getComponentName } from '../component-name';\n\nconst INTEGRATION_NAME = 'Interactions';\n\ninterface InteractionsOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the interaction span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout?: number;\n\n /**\n * The max. time an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout?: number;\n\n /**\n * The max. time a child span of an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout?: number;\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n routeId: string | undefined;\n urlTemplate: string | undefined;\n httpRoute: string | undefined;\n urlPath: string | undefined;\n urlFull: string | undefined;\n}\n\nconst _interactionsIntegration = ((options: InteractionsOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n if (isBotUserAgent()) {\n return;\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n routeId: undefined,\n urlTemplate: undefined,\n httpRoute: undefined,\n urlPath: undefined,\n urlFull: undefined,\n };\n // The pageload/navigation span that is currently in progress, if any. Clicks that happen while one\n // is open are not turned into interaction spans, as they'd compete with the route span for children.\n let inflightRouteSpan: Span | undefined;\n\n function trackRoute(span: Span): void {\n const { name, attributes } = spanToJSON(span);\n latestRoute.name = name;\n // oxlint-disable-next-line typescript/no-deprecated\n latestRoute.source = (attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE]) as\n | TransactionSource\n | undefined;\n latestRoute.routeId = attributes[ROUTER_NAVIGATION_ROUTE_ID] as string | undefined;\n latestRoute.urlTemplate = attributes[URL_TEMPLATE] as string | undefined;\n latestRoute.httpRoute = attributes[HTTP_ROUTE] as string | undefined;\n latestRoute.urlPath = attributes[URL_PATH] as string | undefined;\n latestRoute.urlFull = attributes[URL_FULL] as string | undefined;\n }\n\n client.on('spanStart', span => {\n if (isRouteSpan(span)) {\n inflightRouteSpan = span;\n trackRoute(span);\n }\n });\n\n client.on('spanEnd', span => {\n if (span !== inflightRouteSpan) {\n return;\n }\n inflightRouteSpan = undefined;\n // Re-read the route on end: routing instrumentation frequently renames the pageload or navigation\n // span once the route is resolved, so this is more accurate than what we saw at span start.\n trackRoute(span);\n });\n\n registerInteractionListener(client, latestRoute, () => inflightRouteSpan, options);\n\n trackInteractionsAsSpans(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures user interactions as spans.\n *\n * Important: This integration is considered experimental and might lead to noisy spans. Use at your own risk.\n *\n *\n * Clicks that happen outside of an in-progress pageload or navigation start an idle `ui.action.click` span,\n * named after the last known route, which collects everything the interaction triggers (requests, child spans,\n * …). Additionally, `ui.interaction.click` spans are recorded for the browser's own `event` timing entries.\n *\n * The integration requires `browserTracingIntegration` (or another source of pageload/navigation spans)\n * to know which route an interaction belongs to.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [Sentry.browserTracingIntegration(), Sentry.interactionsIntegration()],\n * });\n * ```\n */\nexport const interactionsIntegration = defineIntegration(_interactionsIntegration);\n\nfunction isRouteSpan(span: Span): boolean {\n if (getRootSpan(span) !== span) {\n return false;\n }\n const op = spanToJSON(span).attributes[SENTRY_OP];\n return op === 'pageload' || op === 'navigation';\n}\n\nfunction registerInteractionListener(\n client: Client,\n latestRoute: RouteInfo,\n getInflightRouteSpan: () => Span | undefined,\n // `startIdleSpan` fills in `TRACING_DEFAULTS` for whatever is left out, which are the same defaults\n // `browserTracingIntegration` uses for its pageload and navigation spans.\n idleSpanOptions: InteractionsOptions,\n): void {\n // `document` is not available in all browser environments (e.g. web workers), and without it there is\n // nothing to click on.\n if (!WINDOW.document) {\n return;\n }\n\n let inflightInteractionSpan: Span | undefined;\n\n addEventListener(\n 'click',\n () => {\n if (getInflightRouteSpan()) {\n DEBUG_BUILD &&\n debug.warn(\n `[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`,\n );\n return;\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);\n return;\n }\n\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n const routeName = latestRoute.routeId || latestRoute.urlTemplate || latestRoute.httpRoute;\n const streamedName = routeName || UI_ACTION_CLICK_SPAN_NAME_FALLBACK;\n // A route id is a name the app gave the route, so it is `custom` rather than a `route` pattern.\n const streamedNameSource = !routeName || latestRoute.routeId ? 'custom' : 'route';\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: hasSpanStreaming ? streamedName : latestRoute.name,\n attributes: {\n [SENTRY_OP]: UI_ACTION_CLICK,\n [SENTRY_SEGMENT_NAME_SOURCE]: hasSpanStreaming ? streamedNameSource : latestRoute.source || 'url',\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(hasSpanStreaming && { [SENTRY_SEGMENT_NAME]: streamedName }),\n ...(latestRoute.routeId && { [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId }),\n ...(latestRoute.urlTemplate && { [URL_TEMPLATE]: latestRoute.urlTemplate }),\n ...(latestRoute.httpRoute && { [HTTP_ROUTE]: latestRoute.httpRoute }),\n ...(latestRoute.urlPath && { [URL_PATH]: latestRoute.urlPath }),\n ...(latestRoute.urlFull && { [URL_FULL]: filterCollectedUrl(latestRoute.urlFull) }),\n },\n },\n idleSpanOptions,\n );\n },\n { capture: true },\n );\n}\n\n/**\n * Record the browser's `event` timing entries for clicks as spans on the currently active span.\n */\nfunction trackInteractionsAsSpans(client: Client): 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 selector = htmlTreeAsString(entry.target);\n const componentName = getComponentName(entry.target);\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: hasSpanStreaming ? componentName || UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK : selector,\n startTime: startTime,\n attributes: {\n [SENTRY_OP]: UI_INTERACTION_CLICK,\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(selector && selector !== UNKNOWN_ELEMENT_NAME && { 'browser.web_vital.inp.target': selector }),\n },\n };\n\n if (componentName) {\n spanOptions.attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interactions.js","sources":["../../../src/performance/interactions.ts"],"sourcesContent":["import {\n BROWSER_WEB_VITAL_INP_TARGET,\n HTTP_ROUTE,\n ROUTER_NAVIGATION_ROUTE_ID,\n SENTRY_IDLE_SPAN_FINISH_REASON,\n SENTRY_OP,\n SENTRY_ORIGIN,\n SENTRY_SEGMENT_NAME,\n SENTRY_SEGMENT_NAME_SOURCE,\n SENTRY_SOURCE,\n UI_COMPONENT_NAME,\n URL_FULL,\n URL_PATH,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';\nimport type { Client, IntegrationFn, Span, StartSpanOptions, TransactionSource } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n defineIntegration,\n filterCollectedUrl,\n getActiveSpan,\n getRootSpan,\n hasSpanStreamingEnabled,\n spanToJSON,\n UI_ACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { startIdleSpan } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver';\nimport { UNKNOWN_ELEMENT_NAME } from '../web-vitals/inp';\nimport { isBotUserAgent } from '../isBotUserAgent';\nimport { WINDOW } from '../types';\nimport { msToSec, startAndEndSpan } from './utils';\nimport { getComponentName } from '../component-name';\n\nconst INTEGRATION_NAME = 'Interactions';\n\ninterface InteractionsOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the interaction span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout?: number;\n\n /**\n * The max. time an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout?: number;\n\n /**\n * The max. time a child span of an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout?: number;\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n routeId: string | undefined;\n urlTemplate: string | undefined;\n httpRoute: string | undefined;\n urlPath: string | undefined;\n urlFull: string | undefined;\n}\n\nconst _interactionsIntegration = ((options: InteractionsOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n if (isBotUserAgent()) {\n return;\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n routeId: undefined,\n urlTemplate: undefined,\n httpRoute: undefined,\n urlPath: undefined,\n urlFull: undefined,\n };\n // The pageload/navigation span that is currently in progress, if any. Clicks that happen while one\n // is open are not turned into interaction spans, as they'd compete with the route span for children.\n let inflightRouteSpan: Span | undefined;\n\n function trackRoute(span: Span): void {\n const { name, attributes } = spanToJSON(span);\n latestRoute.name = name;\n // oxlint-disable-next-line typescript/no-deprecated\n latestRoute.source = (attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE]) as\n | TransactionSource\n | undefined;\n latestRoute.routeId = attributes[ROUTER_NAVIGATION_ROUTE_ID] as string | undefined;\n latestRoute.urlTemplate = attributes[URL_TEMPLATE] as string | undefined;\n latestRoute.httpRoute = attributes[HTTP_ROUTE] as string | undefined;\n latestRoute.urlPath = attributes[URL_PATH] as string | undefined;\n latestRoute.urlFull = attributes[URL_FULL] as string | undefined;\n }\n\n client.on('spanStart', span => {\n if (isRouteSpan(span)) {\n inflightRouteSpan = span;\n trackRoute(span);\n }\n });\n\n client.on('spanEnd', span => {\n if (span !== inflightRouteSpan) {\n return;\n }\n inflightRouteSpan = undefined;\n // Re-read the route on end: routing instrumentation frequently renames the pageload or navigation\n // span once the route is resolved, so this is more accurate than what we saw at span start.\n trackRoute(span);\n });\n\n registerInteractionListener(client, latestRoute, () => inflightRouteSpan, options);\n\n trackInteractionsAsSpans(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures user interactions as spans.\n *\n * Important: This integration is considered experimental and might lead to noisy spans. Use at your own risk.\n *\n *\n * Clicks that happen outside of an in-progress pageload or navigation start an idle `ui.action.click` span,\n * named after the last known route, which collects everything the interaction triggers (requests, child spans,\n * …). Additionally, `ui.interaction.click` spans are recorded for the browser's own `event` timing entries.\n *\n * The integration requires `browserTracingIntegration` (or another source of pageload/navigation spans)\n * to know which route an interaction belongs to.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [Sentry.browserTracingIntegration(), Sentry.interactionsIntegration()],\n * });\n * ```\n */\nexport const interactionsIntegration = defineIntegration(_interactionsIntegration);\n\nfunction isRouteSpan(span: Span): boolean {\n if (getRootSpan(span) !== span) {\n return false;\n }\n const op = spanToJSON(span).attributes[SENTRY_OP];\n return op === 'pageload' || op === 'navigation';\n}\n\nfunction registerInteractionListener(\n client: Client,\n latestRoute: RouteInfo,\n getInflightRouteSpan: () => Span | undefined,\n // `startIdleSpan` fills in `TRACING_DEFAULTS` for whatever is left out, which are the same defaults\n // `browserTracingIntegration` uses for its pageload and navigation spans.\n idleSpanOptions: InteractionsOptions,\n): void {\n // `document` is not available in all browser environments (e.g. web workers), and without it there is\n // nothing to click on.\n if (!WINDOW.document) {\n return;\n }\n\n let inflightInteractionSpan: Span | undefined;\n\n addEventListener(\n 'click',\n () => {\n if (getInflightRouteSpan()) {\n DEBUG_BUILD &&\n debug.warn(\n `[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`,\n );\n return;\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);\n return;\n }\n\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n const routeName = latestRoute.routeId || latestRoute.urlTemplate || latestRoute.httpRoute;\n const streamedName = routeName || UI_ACTION_CLICK_SPAN_NAME_FALLBACK;\n // A route id is a name the app gave the route, so it is `custom` rather than a `route` pattern.\n const streamedNameSource = !routeName || latestRoute.routeId ? 'custom' : 'route';\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: hasSpanStreaming ? streamedName : latestRoute.name,\n attributes: {\n [SENTRY_OP]: UI_ACTION_CLICK,\n [SENTRY_SEGMENT_NAME_SOURCE]: hasSpanStreaming ? streamedNameSource : latestRoute.source || 'url',\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(hasSpanStreaming && { [SENTRY_SEGMENT_NAME]: streamedName }),\n ...(latestRoute.routeId && { [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId }),\n ...(latestRoute.urlTemplate && { [URL_TEMPLATE]: latestRoute.urlTemplate }),\n ...(latestRoute.httpRoute && { [HTTP_ROUTE]: latestRoute.httpRoute }),\n ...(latestRoute.urlPath && { [URL_PATH]: latestRoute.urlPath }),\n ...(latestRoute.urlFull && { [URL_FULL]: filterCollectedUrl(latestRoute.urlFull) }),\n },\n },\n idleSpanOptions,\n );\n },\n { capture: true },\n );\n}\n\n/**\n * Record the browser's `event` timing entries for clicks as spans on the currently active span.\n */\nfunction trackInteractionsAsSpans(client: Client): 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 selector = htmlTreeAsString(entry.target);\n const componentName = getComponentName(entry.target);\n const hasSpanStreaming = hasSpanStreamingEnabled(client);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: hasSpanStreaming ? componentName || UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK : selector,\n startTime: startTime,\n attributes: {\n [SENTRY_OP]: UI_INTERACTION_CLICK,\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n ...(selector && selector !== UNKNOWN_ELEMENT_NAME && { [BROWSER_WEB_VITAL_INP_TARGET]: selector }),\n },\n };\n\n if (componentName) {\n spanOptions.attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { htmlTreeAsString } from '../htmlTreeAsString.js';
|
|
|
4
4
|
import { getComponentName } from '../component-name.js';
|
|
5
5
|
import { MAX_PLAUSIBLE_INP_DURATION, INP_ENTRY_MAP, getCachedInteractionContext, UNKNOWN_ELEMENT_NAME } from './inp.js';
|
|
6
6
|
import { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler } from '../instrumentation/performanceObserver.js';
|
|
7
|
-
import { BROWSER_NAVIGATION_TYPE, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';
|
|
7
|
+
import { BROWSER_NAVIGATION_TYPE, UI_COMPONENT_NAME, BROWSER_WEB_VITAL_INP_TARGET, BROWSER_WEB_VITAL_INP_INTERACTION_TYPE } from '@sentry/conventions/attributes';
|
|
8
8
|
import { _emitWebVitalSpan } from './emitSpan.js';
|
|
9
9
|
import { isValidLcpMetric } from './lcp.js';
|
|
10
10
|
import { listenForWebVitalReportEvents } from './reportEvents.js';
|
|
@@ -243,8 +243,8 @@ function _sendInpSpan(inpValue, entry, standalone = false, attributedSpan, softN
|
|
|
243
243
|
const attributes = {
|
|
244
244
|
[SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue
|
|
245
245
|
};
|
|
246
|
-
selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes[
|
|
247
|
-
entryInteractionType && (attributes[
|
|
246
|
+
selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes[BROWSER_WEB_VITAL_INP_TARGET] = selector);
|
|
247
|
+
entryInteractionType && (attributes[BROWSER_WEB_VITAL_INP_INTERACTION_TYPE] = entryInteractionType);
|
|
248
248
|
if (componentName) {
|
|
249
249
|
attributes[UI_COMPONENT_NAME] = componentName;
|
|
250
250
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { getComponentName } from '../component-name';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION, UNKNOWN_ELEMENT_NAME } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport { BROWSER_NAVIGATION_TYPE, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\nconst INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n hover: UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n drag: UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n press: UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const selector = entry ? htmlTreeAsString(entry.element) : undefined;\n const componentName = entry?.element ? getComponentName(entry.element) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (selector) {\n attributes['browser.web_vital.lcp.element'] = selector;\n }\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const firstSourceNode = entry?.sources[0]?.node;\n const selector = entry ? htmlTreeAsString(firstSourceNode) : undefined;\n const componentName = firstSourceNode ? getComponentName(firstSourceNode) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const entryInteractionType = entry && INP_ENTRY_MAP[entry.name];\n const interactionType = entryInteractionType || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const selector = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : undefined);\n const componentName = entry?.target ? getComponentName(entry.target) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const fallbackName = INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK[interactionType];\n const name = hasSpanStreaming ? componentName || fallbackName : (selector ?? 'Interaction to next paint');\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n };\n\n // The span's name and op always have a value, even for an INP without an entry, so they can't\n // say whether there was an interaction to describe. These attributes can: they are only set for\n // what was actually observed. The name no longer holds the selector either, now that it is the\n // component name or the op's fallback under span streaming.\n // TODO: use the `@sentry/conventions` constants once getsentry/sentry-conventions#641 is released.\n selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes['browser.web_vital.inp.target'] = selector);\n entryInteractionType && (attributes['browser.web_vital.inp.interaction_type'] = entryInteractionType);\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes,\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spans.js","sources":["../../../src/web-vitals/spans.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n timestampInSeconds,\n UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK,\n UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { getComponentName } from '../component-name';\nimport type { InteractionType } from './inp';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION, UNKNOWN_ELEMENT_NAME } from './inp';\nimport type { InstrumentationHandlerCallback, MetricNavigationType } from '../instrumentation/performanceObserver';\nimport {\n addClsInstrumentationHandler,\n addInpInstrumentationHandler,\n addLcpInstrumentationHandler,\n} from '../instrumentation/performanceObserver';\nimport type { LargestContentfulPaint, LayoutShift } from './emitSpan';\nimport {\n BROWSER_NAVIGATION_TYPE,\n BROWSER_WEB_VITAL_INP_INTERACTION_TYPE,\n BROWSER_WEB_VITAL_INP_TARGET,\n UI_COMPONENT_NAME,\n} from '@sentry/conventions/attributes';\nimport { _emitWebVitalSpan } from './emitSpan';\nimport { isValidLcpMetric } from './lcp';\nimport { listenForWebVitalReportEvents } from './reportEvents';\nimport { getNavigationSpanForMetric } from './softNavs';\nimport { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';\nimport type { PerformanceEventTiming } from '../instrumentation/performanceObserver';\nimport {\n NAVIGATION,\n UI_INTERACTION_CLICK,\n UI_INTERACTION_DRAG,\n UI_INTERACTION_HOVER,\n UI_INTERACTION_PRESS,\n UI_WEBVITAL_CLS,\n UI_WEBVITAL_LCP,\n} from '@sentry/conventions/op';\n\nconst INTERACTION_TYPE_TO_SPAN_OP: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK,\n hover: UI_INTERACTION_HOVER,\n drag: UI_INTERACTION_DRAG,\n press: UI_INTERACTION_PRESS,\n};\n\nconst INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK: Record<InteractionType, string> = {\n click: UI_INTERACTION_CLICK_SPAN_NAME_FALLBACK,\n hover: UI_INTERACTION_HOVER_SPAN_NAME_FALLBACK,\n drag: UI_INTERACTION_DRAG_SPAN_NAME_FALLBACK,\n press: UI_INTERACTION_PRESS_SPAN_NAME_FALLBACK,\n};\n\ntype WebVitalMetric = Parameters<Parameters<typeof addLcpInstrumentationHandler>[0]>[0]['metric'];\ntype InpMetric = Parameters<InstrumentationHandlerCallback>[0]['metric'];\n\n/**\n * Reports a web vital once per navigation, rather than once per page load.\n *\n * web-vitals restarts the metric on every soft navigation and force-reports the previous one just\n * before it does (and again on pagehide), and re-reports every metric after a bfcache restore.\n * Since `reportAllChanges` is off in this mode, every value we're handed is already the final one\n * for its navigation, so there is nothing to accumulate: each report is a span.\n */\nfunction trackWebVitalPerNavigation<M extends WebVitalMetric>(\n client: Client,\n addInstrumentationHandler: (callback: (data: { metric: M }) => void) => unknown,\n send: (metric: M, parentSpan: Span | undefined, softNavigationId: number | undefined) => void,\n): void {\n let pageloadSpan: Span | undefined;\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n });\n\n // Remembered when the restore happens rather than read back at report time: the restore\n // navigation span is an idle span, and CLS and INP are only finalized on pagehide, by which point\n // it has long ended and is no longer what is active.\n let bfcacheNavigationSpan: Span | undefined;\n client.on('spanStart', span => {\n // The op has to be checked too: the web vital spans emitted for a restore carry the same\n // `back-forward-cache` navigation type, so matching on that alone lets the first of them replace the\n // navigation span, and every later vital then hangs off a sibling vital instead.\n const attributes = spanToJSON(span).attributes;\n if (\n attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === NAVIGATION &&\n attributes[BROWSER_NAVIGATION_TYPE] === 'back-forward-cache'\n ) {\n bfcacheNavigationSpan = span;\n }\n });\n\n addInstrumentationHandler(({ metric }) => {\n const navigationSpan = getNavigationSpanForMetric(metric);\n if (metric.navigationType === 'soft-navigation') {\n // Reporting an uncorrelated soft navigation vital would attribute it to the wrong route, so\n // it's dropped instead.\n if (navigationSpan) {\n send(metric, navigationSpan, metric.navigationId);\n } else {\n DEBUG_BUILD &&\n debug.log(`[SoftNav] Dropping ${metric.name} for uncorrelated soft navigation ${metric.navigationId}`);\n }\n return;\n }\n\n if (metric.navigationType === 'back-forward-cache') {\n // A restore reuses the frozen document, so the pageload span above belongs to the page view\n // from before the freeze. The navigation span started for the restore is the page view these\n // values were actually measured on.\n send(metric, bfcacheNavigationSpan, undefined);\n return;\n }\n\n send(metric, pageloadSpan, undefined);\n });\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addLcpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n _sendLcpSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n let lcpNavigationType: MetricNavigationType | undefined;\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\n // The navigation type describes the page, not the entry, so it is worth keeping even for a\n // report we otherwise discard.\n lcpNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LargestContentfulPaint | undefined;\n if (!entry || !isValidLcpMetric(metric.value)) {\n return;\n }\n lcpValue = metric.value;\n lcpEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, undefined, lcpNavigationType);\n cleanupLcpHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendLcpSpan(\n lcpValue: number,\n entry: LargestContentfulPaint | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n if (!isValidLcpMetric(lcpValue)) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Sending LCP span (${lcpValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin() || 0;\n // A soft navigation's LCP is measured from the triggering interaction, not the document time\n // origin. Starting the span there too keeps it inside the navigation span it is parented to and\n // keeps its duration equal to the value it reports.\n const startTime = msToSec(performanceTimeOrigin + (navigationStartTime || 0));\n // Without an entry there is no render time to end at, so the span lasts the value it reports,\n // like an entry-less INP does. Ending at the time origin instead would invert the span.\n const endTime = entry ? msToSec(performanceTimeOrigin + entry.startTime) : startTime + msToSec(lcpValue);\n const selector = entry ? htmlTreeAsString(entry.element) : undefined;\n const componentName = entry?.element ? getComponentName(entry.element) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_LCP_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (selector) {\n attributes['browser.web_vital.lcp.element'] = selector;\n }\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n entry?.id && (attributes['browser.web_vital.lcp.id'] = entry.id);\n entry?.url && (attributes['browser.web_vital.lcp.url'] = entry.url);\n entry?.loadTime != null && (attributes['browser.web_vital.lcp.load_time'] = entry.loadTime);\n entry?.renderTime != null && (attributes['browser.web_vital.lcp.render_time'] = entry.renderTime);\n entry?.size != null && (attributes['browser.web_vital.lcp.size'] = entry.size);\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_LCP,\n origin: 'auto.http.browser.lcp',\n metricName: 'lcp',\n value: lcpValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n endTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client, perNavigation = false): void {\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n if (perNavigation) {\n trackWebVitalPerNavigation(client, addClsInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n _sendClsSpan(\n metric.value,\n entry,\n parentSpan,\n softNavigationId,\n metric.navigationType,\n metric.navigationStartTime,\n );\n });\n return;\n }\n\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n let clsNavigationType: MetricNavigationType | undefined;\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\n // A CLS of 0 is reported with no entries and still emits a span, so the navigation type has to\n // be captured before the entry check rather than alongside the value.\n clsNavigationType = metric.navigationType;\n\n const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;\n if (!entry) {\n return;\n }\n clsValue = metric.value;\n clsEntry = entry;\n }, true);\n\n listenForWebVitalReportEvents(client, pageloadSpan => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, undefined, clsNavigationType);\n cleanupClsHandler();\n });\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendClsSpan(\n clsValue: number,\n entry: LayoutShift | undefined,\n pageloadSpan?: Span,\n softNavigationId?: number,\n navigationType?: MetricNavigationType,\n navigationStartTime?: number,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const performanceTimeOrigin = browserPerformanceTimeOrigin();\n // A CLS of 0 has no shift to place the span at. It is reported when the navigation it was\n // measured on is already over - the next soft navigation, or pagehide - so the current time would\n // land it outside that navigation, on the route that follows it.\n const offset = entry?.startTime ?? navigationStartTime ?? 0;\n const startTime = performanceTimeOrigin ? msToSec(performanceTimeOrigin + offset) : timestampInSeconds();\n const firstSourceNode = entry?.sources[0]?.node;\n const selector = entry ? htmlTreeAsString(firstSourceNode) : undefined;\n const componentName = firstSourceNode ? getComponentName(firstSourceNode) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const name = hasSpanStreaming\n ? componentName || UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK\n : (selector ?? UI_WEBVITAL_CLS_SPAN_NAME_FALLBACK);\n\n const attributes: SpanAttributes = {};\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n if (entry?.sources) {\n entry.sources.forEach((source, index) => {\n attributes[`browser.web_vital.cls.source.${index + 1}`] = htmlTreeAsString(source.node);\n });\n }\n\n _emitWebVitalSpan({\n name,\n op: UI_WEBVITAL_CLS,\n origin: 'auto.http.browser.cls',\n metricName: 'cls',\n value: clsValue,\n attributes,\n parentSpan: pageloadSpan,\n startTime,\n softNavigationId,\n navigationType,\n });\n}\n\n/**\n * Tracks INP and emits it as a web vital span, as a child of the interaction's root span.\n * Requires `registerInpInteractionListener()` to be called separately for cached element names and\n * root spans per interaction.\n */\nexport function trackInpAsSpan(client: Client, perNavigation = false): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n // INP reports late (on pagehide, after the pageload span has ended). With span streaming enabled\n // it rides the streaming pipeline. With streaming disabled it would be dropped as a late span, so\n // it is emitted as its own standalone v2 span instead (see `_emitWebVitalSpan`), overriding the\n // static trace lifecycle for INP only.\n // TODO(standalone): once the static trace lifecycle is dropped, INP always streams; drop this flag.\n const standalone = !hasSpanStreamingEnabled(client);\n\n if (perNavigation) {\n // INP restarts per navigation and reports once that navigation is over, by which point the\n // navigation span has ended and the interaction cache no longer knows about it. The metric\n // says which navigation it belongs to, so INP is attributed exactly like LCP and CLS.\n trackWebVitalPerNavigation(client, addInpInstrumentationHandler, (metric, parentSpan, softNavigationId) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, parentSpan, softNavigationId, metric);\n }\n });\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (isPlausibleInp(metric)) {\n _sendInpSpan(metric.value, findInpEntry(metric), standalone, undefined, undefined, metric);\n }\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\nfunction isPlausibleInp(metric: InpMetric): boolean {\n return metric.value != null && msToSec(metric.value) <= MAX_PLAUSIBLE_INP_DURATION;\n}\n\n/**\n * The entry an INP span is built from: the one whose duration the reported value came from.\n *\n * There isn't always one. When every interaction of a soft navigation stayed below the Event Timing\n * threshold, web-vitals reports a synthetic value with no entries at all - see\n * `_estimateP98LongestInteraction`. The span still gets reported in that case, just without the\n * element and interaction type an entry would have supplied.\n */\nfunction findInpEntry(metric: InpMetric): PerformanceEventTiming | undefined {\n return metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(\n inpValue: number,\n entry: PerformanceEventTiming | undefined,\n standalone = false,\n attributedSpan?: Span,\n softNavigationId?: number,\n metric?: InpMetric,\n): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n // A web vital span carries the metric, not a real interaction timing, so an INP without an entry\n // is still worth reporting. It just has no element or interaction type to describe, and is placed\n // at the start of the navigation it belongs to rather than at the interaction.\n const startTime = msToSec(\n (browserPerformanceTimeOrigin() as number) + (entry?.startTime ?? metric?.navigationStartTime ?? 0),\n );\n const duration = msToSec(inpValue);\n // An INP without an entry has no interaction type to report. It still has to land inside the\n // `ui.interaction.*` family, because falling outside it would hide exactly the fast navigations\n // that web-vitals synthesizes these values for (GoogleChrome/web-vitals#724), reintroducing the\n // reporting bias they were added to remove.\n const entryInteractionType = entry && INP_ENTRY_MAP[entry.name];\n const interactionType = entryInteractionType || 'click';\n\n const cachedContext = entry && getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n // With soft navigations the caller knows exactly which navigation the metric belongs to. Without\n // them we fall back to the span that was active when the interaction was observed.\n const spanToUse = attributedSpan || cachedContext?.span || rootSpan;\n const selector = cachedContext?.elementName || (entry ? htmlTreeAsString(entry.target) : undefined);\n const componentName = entry?.target ? getComponentName(entry.target) : null;\n const client = getClient();\n const hasSpanStreaming = !!client && hasSpanStreamingEnabled(client);\n const fallbackName = INTERACTION_TYPE_TO_SPAN_NAME_FALLBACK[interactionType];\n const name = hasSpanStreaming ? componentName || fallbackName : (selector ?? 'Interaction to next paint');\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration ?? inpValue,\n };\n\n // The span's name and op always have a value, even for an INP without an entry, so they can't\n // say whether there was an interaction to describe. These attributes can: they are only set for\n // what was actually observed. The name no longer holds the selector either, now that it is the\n // component name or the op's fallback under span streaming.\n selector && selector !== UNKNOWN_ELEMENT_NAME && (attributes[BROWSER_WEB_VITAL_INP_TARGET] = selector);\n entryInteractionType && (attributes[BROWSER_WEB_VITAL_INP_INTERACTION_TYPE] = entryInteractionType);\n\n if (componentName) {\n attributes[UI_COMPONENT_NAME] = componentName;\n }\n\n _emitWebVitalSpan({\n name,\n op: INTERACTION_TYPE_TO_SPAN_OP[interactionType],\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes,\n startTime,\n endTime: startTime + duration,\n navigationType: metric?.navigationType,\n parentSpan: spanToUse,\n standalone,\n softNavigationId,\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/performance/interactions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/performance/interactions.ts"],"names":[],"mappings":"AAyCA,UAAU,mBAAmB;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAuED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB;;CAA8C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spans.d.ts","sourceRoot":"","sources":["../../../src/web-vitals/spans.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAkB,MAAM,cAAc,CAAC;AAwBjE,OAAO,KAAK,EAAE,8BAA8B,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAMnH,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"spans.d.ts","sourceRoot":"","sources":["../../../src/web-vitals/spans.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAkB,MAAM,cAAc,CAAC;AAwBjE,OAAO,KAAK,EAAE,8BAA8B,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAMnH,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYtE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AA0BrF,KAAK,SAAS,GAAG,UAAU,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AA+DzE;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,IAAI,CAyC1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,sBAAsB,GAAG,SAAS,EACzC,YAAY,CAAC,EAAE,IAAI,EACnB,gBAAgB,CAAC,EAAE,MAAM,EACzB,cAAc,CAAC,EAAE,oBAAoB,EACrC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,IAAI,CAkDN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,IAAI,CAyC1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,YAAY,CAAC,EAAE,IAAI,EACnB,gBAAgB,CAAC,EAAE,MAAM,EACzB,cAAc,CAAC,EAAE,oBAAoB,EACrC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,IAAI,CA0CN;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,IAAI,CAgC1E;AAkBD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,sBAAsB,GAAG,SAAS,EACzC,UAAU,UAAQ,EAClB,cAAc,CAAC,EAAE,IAAI,EACrB,gBAAgB,CAAC,EAAE,MAAM,EACzB,MAAM,CAAC,EAAE,SAAS,GACjB,IAAI,CA4DN"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/browser-utils",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Browser Utilities for all Sentry JavaScript SDKs",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser-utils",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@sentry/core": "11.
|
|
37
|
-
"@sentry/conventions": "^0.
|
|
36
|
+
"@sentry/core": "11.1.0",
|
|
37
|
+
"@sentry/conventions": "^0.24.0",
|
|
38
38
|
"web-vitals": "^6.1.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|