@sentry/browser-utils 10.68.0 → 11.0.0-alpha.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/build/cjs/htmlTreeAsString.js.map +1 -1
- package/build/cjs/index.js +2 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/metrics/browserMetrics.js +25 -91
- package/build/cjs/metrics/browserMetrics.js.map +1 -1
- package/build/cjs/metrics/inp.js +0 -57
- package/build/cjs/metrics/inp.js.map +1 -1
- package/build/cjs/metrics/lcp.js +0 -67
- package/build/cjs/metrics/lcp.js.map +1 -1
- package/build/cjs/metrics/userTiming.js +118 -0
- package/build/cjs/metrics/userTiming.js.map +1 -0
- package/build/cjs/metrics/utils.js +0 -43
- package/build/cjs/metrics/utils.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +2 -6
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js +1 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/onHidden.js +3 -4
- package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -1
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -2
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -1
- package/build/cjs/metrics/webVitalSpans.js +25 -9
- package/build/cjs/metrics/webVitalSpans.js.map +1 -1
- package/build/esm/htmlTreeAsString.js.map +1 -1
- package/build/esm/index.js +2 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/metrics/browserMetrics.js +29 -94
- package/build/esm/metrics/browserMetrics.js.map +1 -1
- package/build/esm/metrics/inp.js +3 -57
- package/build/esm/metrics/inp.js.map +1 -1
- package/build/esm/metrics/lcp.js +1 -66
- package/build/esm/metrics/lcp.js.map +1 -1
- package/build/esm/metrics/userTiming.js +115 -0
- package/build/esm/metrics/userTiming.js.map +1 -0
- package/build/esm/metrics/utils.js +2 -44
- package/build/esm/metrics/utils.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +2 -6
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js +1 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/onHidden.js +3 -4
- package/build/esm/metrics/web-vitals/lib/onHidden.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +1 -1
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -2
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +1 -1
- package/build/esm/metrics/webVitalSpans.js +26 -10
- package/build/esm/metrics/webVitalSpans.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/metrics/browserMetrics.d.ts +5 -29
- package/build/types/metrics/browserMetrics.d.ts.map +1 -1
- package/build/types/metrics/inp.d.ts +0 -13
- package/build/types/metrics/inp.d.ts.map +1 -1
- package/build/types/metrics/lcp.d.ts +0 -16
- package/build/types/metrics/lcp.d.ts.map +1 -1
- package/build/types/metrics/userTiming.d.ts +37 -0
- package/build/types/metrics/userTiming.d.ts.map +1 -0
- package/build/types/metrics/utils.d.ts +1 -25
- package/build/types/metrics/utils.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getCLS.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getINP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/getLCP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +1 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts +3 -3
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/observe.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts +4 -16
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +1 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/onFCP.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/onTTFB.d.ts.map +1 -1
- package/build/types/metrics/web-vitals/types.d.ts +1 -1
- package/build/types/metrics/web-vitals/types.d.ts.map +1 -1
- package/build/types/metrics/webVitalSpans.d.ts +15 -9
- package/build/types/metrics/webVitalSpans.d.ts.map +1 -1
- package/build/types/types.d.ts +1 -1
- package/package.json +6 -15
- package/build/cjs/metrics/cls.js +0 -64
- package/build/cjs/metrics/cls.js.map +0 -1
- package/build/esm/metrics/cls.js +0 -61
- package/build/esm/metrics/cls.js.map +0 -1
- package/build/types/metrics/cls.d.ts +0 -17
- package/build/types/metrics/cls.d.ts.map +0 -1
- package/build/types-ts3.8/debug-build.d.ts +0 -7
- package/build/types-ts3.8/getNativeImplementation.d.ts +0 -69
- package/build/types-ts3.8/htmlTreeAsString.d.ts +0 -11
- package/build/types-ts3.8/index.d.ts +0 -17
- package/build/types-ts3.8/instrument/dom.d.ts +0 -11
- package/build/types-ts3.8/instrument/history.d.ts +0 -15
- package/build/types-ts3.8/instrument/location.d.ts +0 -13
- package/build/types-ts3.8/instrument/xhr.d.ts +0 -14
- package/build/types-ts3.8/is.d.ts +0 -7
- package/build/types-ts3.8/metrics/browserMetrics.d.ts +0 -119
- package/build/types-ts3.8/metrics/cls.d.ts +0 -17
- package/build/types-ts3.8/metrics/elementTiming.d.ts +0 -21
- package/build/types-ts3.8/metrics/inp.d.ts +0 -35
- package/build/types-ts3.8/metrics/instrument.d.ts +0 -121
- package/build/types-ts3.8/metrics/lcp.d.ts +0 -22
- package/build/types-ts3.8/metrics/resourceTiming.d.ts +0 -13
- package/build/types-ts3.8/metrics/utils.d.ts +0 -73
- package/build/types-ts3.8/metrics/web-vitals/getCLS.d.ts +0 -26
- package/build/types-ts3.8/metrics/web-vitals/getINP.d.ts +0 -34
- package/build/types-ts3.8/metrics/web-vitals/getLCP.d.ts +0 -16
- package/build/types-ts3.8/metrics/web-vitals/lib/InteractionManager.d.ts +0 -37
- package/build/types-ts3.8/metrics/web-vitals/lib/LCPEntryManager.d.ts +0 -5
- package/build/types-ts3.8/metrics/web-vitals/lib/LayoutShiftManager.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/bindReporter.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/generateUniqueID.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/getActivationStart.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/getNavigationEntry.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +0 -5
- package/build/types-ts3.8/metrics/web-vitals/lib/globalListeners.d.ts +0 -11
- package/build/types-ts3.8/metrics/web-vitals/lib/initMetric.d.ts +0 -21
- package/build/types-ts3.8/metrics/web-vitals/lib/initUnique.d.ts +0 -7
- package/build/types-ts3.8/metrics/web-vitals/lib/observe.d.ts +0 -23
- package/build/types-ts3.8/metrics/web-vitals/lib/onHidden.d.ts +0 -27
- package/build/types-ts3.8/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +0 -15
- package/build/types-ts3.8/metrics/web-vitals/lib/runOnce.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/whenActivated.d.ts +0 -2
- package/build/types-ts3.8/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +0 -6
- package/build/types-ts3.8/metrics/web-vitals/onFCP.d.ts +0 -11
- package/build/types-ts3.8/metrics/web-vitals/onTTFB.d.ts +0 -20
- package/build/types-ts3.8/metrics/web-vitals/types/base.d.ts +0 -106
- package/build/types-ts3.8/metrics/web-vitals/types/cls.d.ts +0 -58
- package/build/types-ts3.8/metrics/web-vitals/types/fcp.d.ts +0 -47
- package/build/types-ts3.8/metrics/web-vitals/types/inp.d.ts +0 -150
- package/build/types-ts3.8/metrics/web-vitals/types/lcp.d.ts +0 -74
- package/build/types-ts3.8/metrics/web-vitals/types/ttfb.d.ts +0 -60
- package/build/types-ts3.8/metrics/web-vitals/types.d.ts +0 -78
- package/build/types-ts3.8/metrics/webVitalSpans.d.ts +0 -65
- package/build/types-ts3.8/networkUtils.d.ts +0 -28
- package/build/types-ts3.8/types.d.ts +0 -15
|
@@ -21,7 +21,8 @@ function _emitWebVitalSpan(options) {
|
|
|
21
21
|
parentSpan,
|
|
22
22
|
reportEvent,
|
|
23
23
|
startTime,
|
|
24
|
-
endTime
|
|
24
|
+
endTime,
|
|
25
|
+
standalone
|
|
25
26
|
} = options;
|
|
26
27
|
const routeName = core.getCurrentScope().getScopeData().transactionName;
|
|
27
28
|
const attributes$1 = {
|
|
@@ -42,19 +43,32 @@ function _emitWebVitalSpan(options) {
|
|
|
42
43
|
if (reportEvent) {
|
|
43
44
|
attributes$1[`browser.web_vital.${metricName}.report_event`] = reportEvent;
|
|
44
45
|
}
|
|
46
|
+
if (standalone) {
|
|
47
|
+
Object.assign(attributes$1, getReplayAttributes());
|
|
48
|
+
}
|
|
45
49
|
const span = core.startInactiveSpan({
|
|
46
50
|
name,
|
|
47
51
|
attributes: attributes$1,
|
|
48
52
|
startTime,
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
parentSpan
|
|
53
|
+
parentSpan,
|
|
54
|
+
// oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above
|
|
55
|
+
experimental: standalone ? { standalone: true } : void 0
|
|
53
56
|
});
|
|
54
57
|
if (span) {
|
|
55
58
|
span.end(endTime ?? startTime);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
61
|
+
function getReplayAttributes() {
|
|
62
|
+
const replay = core.getClient()?.getIntegrationByName("Replay");
|
|
63
|
+
const replayId = replay?.getReplayId(true);
|
|
64
|
+
if (!replayId) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
"sentry.replay_id": replayId,
|
|
69
|
+
"sentry._internal.replay_is_buffering": replay.getRecordingMode() === "buffer" ? true : void 0
|
|
70
|
+
};
|
|
71
|
+
}
|
|
58
72
|
function trackLcpAsSpan(client) {
|
|
59
73
|
let lcpValue = 0;
|
|
60
74
|
let lcpEntry;
|
|
@@ -144,11 +158,12 @@ function _sendClsSpan(clsValue, entry, pageloadSpan, reportEvent) {
|
|
|
144
158
|
startTime
|
|
145
159
|
});
|
|
146
160
|
}
|
|
147
|
-
function trackInpAsSpan() {
|
|
161
|
+
function trackInpAsSpan(client) {
|
|
148
162
|
const performance = utils.getBrowserPerformanceAPI();
|
|
149
163
|
if (!performance || !core.browserPerformanceTimeOrigin()) {
|
|
150
164
|
return;
|
|
151
165
|
}
|
|
166
|
+
const standalone = !core.hasSpanStreamingEnabled(client);
|
|
152
167
|
const onInp = ({ metric }) => {
|
|
153
168
|
if (metric.value == null) {
|
|
154
169
|
return;
|
|
@@ -161,11 +176,11 @@ function trackInpAsSpan() {
|
|
|
161
176
|
if (!entry) {
|
|
162
177
|
return;
|
|
163
178
|
}
|
|
164
|
-
_sendInpSpan(metric.value, entry);
|
|
179
|
+
_sendInpSpan(metric.value, entry, standalone);
|
|
165
180
|
};
|
|
166
181
|
instrument.addInpInstrumentationHandler(onInp);
|
|
167
182
|
}
|
|
168
|
-
function _sendInpSpan(inpValue, entry) {
|
|
183
|
+
function _sendInpSpan(inpValue, entry, standalone = false) {
|
|
169
184
|
debugBuild.DEBUG_BUILD && core.debug.log(`Sending INP span (${inpValue})`);
|
|
170
185
|
const startTime = utils.msToSec(core.browserPerformanceTimeOrigin() + entry.startTime);
|
|
171
186
|
const duration = utils.msToSec(inpValue);
|
|
@@ -190,7 +205,8 @@ function _sendInpSpan(inpValue, entry) {
|
|
|
190
205
|
},
|
|
191
206
|
startTime,
|
|
192
207
|
endTime: startTime + duration,
|
|
193
|
-
parentSpan: spanToUse
|
|
208
|
+
parentSpan: spanToUse,
|
|
209
|
+
standalone
|
|
194
210
|
});
|
|
195
211
|
}
|
|
196
212
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webVitalSpans.js","sources":["../../../src/metrics/webVitalSpans.ts"],"sourcesContent":["import type { Client, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToStreamedSpanJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback } from './instrument';\nimport { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler } from './instrument';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './utils';\nimport { getBrowserPerformanceAPI, listenForWebVitalReportEvents, msToSec, supportsWebVital } from './utils';\nimport type { PerformanceEventTiming } from './instrument';\nimport { SENTRY_SEGMENT_NAME, SENTRY_TRANSACTION } from '@sentry/conventions/attributes';\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n}\n\n/**\n * Emits a web vital span that flows through the span streaming pipeline.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n } = options;\n\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n // Web vital score calculation relies on the user agent\n 'user_agent.original': WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToStreamedSpanJSON(parentSpan).attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n // if we have a pageload span, we let the web vital span start as its parent. This ensures that\n // it is not started as a segment span, without having to manually set it to a \"standalone\" v2 span\n // that has `segment: false` but no actual parent span.\n parentSpan: parentSpan,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client): void {\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\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, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent);\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 reportEvent?: WebVitalReportEvent,\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 const timeOrigin = msToSec(performanceTimeOrigin);\n const endTime = msToSec(performanceTimeOrigin + (entry?.startTime || 0));\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\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 reportEvent,\n startTime: timeOrigin,\n endTime,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client): void {\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\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, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent);\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 reportEvent?: WebVitalReportEvent,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\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 reportEvent,\n startTime,\n });\n}\n\n/**\n * Tracks INP as a streamed span.\n *\n * This mirrors the standalone INP tracking logic (`startTrackingINP`) but emits\n * spans through the streaming pipeline instead of as standalone spans.\n * Requires `registerInpInteractionListener()` to be called separately for\n * cached element names and root spans per interaction.\n */\nexport function trackInpAsSpan(): void {\n const performance = getBrowserPerformanceAPI();\n if (!performance || !browserPerformanceTimeOrigin()) {\n return;\n }\n\n const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (metric.value == null) {\n return;\n }\n\n const duration = msToSec(metric.value);\n\n if (duration > MAX_PLAUSIBLE_INP_DURATION) {\n return;\n }\n\n const entry = metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n\n if (!entry) {\n return;\n }\n\n _sendInpSpan(metric.value, entry);\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(inpValue: number, entry: PerformanceEventTiming): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(inpValue);\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n const cachedContext = getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n const spanToUse = cachedContext?.span || rootSpan;\n const routeName = spanToUse\n ? spanToStreamedSpanJSON(spanToUse).name\n : getCurrentScope().getScopeData().transactionName;\n const name = cachedContext?.elementName || htmlTreeAsString(entry.target);\n\n _emitWebVitalSpan({\n name,\n op: `ui.interaction.${interactionType}`,\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n },\n startTime,\n endTime: startTime + duration,\n parentSpan: spanToUse,\n });\n}\n"],"names":["getCurrentScope","attributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","SENTRY_TRANSACTION","SENTRY_SEGMENT_NAME","WINDOW","spanToStreamedSpanJSON","startInactiveSpan","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","DEBUG_BUILD","debug","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","addClsInstrumentationHandler","timestampInSeconds","getBrowserPerformanceAPI","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","addInpInstrumentationHandler","getCachedInteractionContext","getActiveSpan","getRootSpan"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webVitalSpans.js","sources":["../../../src/metrics/webVitalSpans.ts"],"sourcesContent":["import type { Client, Integration, Span, SpanAttributes } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToStreamedSpanJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { getCachedInteractionContext, INP_ENTRY_MAP, MAX_PLAUSIBLE_INP_DURATION } from './inp';\nimport type { InstrumentationHandlerCallback } from './instrument';\nimport { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler } from './instrument';\nimport { isValidLcpMetric } from './lcp';\nimport type { WebVitalReportEvent } from './utils';\nimport { getBrowserPerformanceAPI, listenForWebVitalReportEvents, msToSec, supportsWebVital } from './utils';\nimport type { PerformanceEventTiming } from './instrument';\nimport { SENTRY_SEGMENT_NAME, SENTRY_TRANSACTION } from '@sentry/conventions/attributes';\n\n// Locally-defined interfaces to avoid leaking bare global type references into the\n// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these\n// available during this package's compilation but are NOT carried to consumers.\n// This mirrors the pattern used for PerformanceEventTiming in instrument.ts.\nexport interface LayoutShift extends PerformanceEntry {\n value: number;\n sources: Array<{ node: Node | null }>;\n hadRecentInput: boolean;\n}\n\nexport interface LargestContentfulPaint extends PerformanceEntry {\n readonly renderTime: DOMHighResTimeStamp;\n readonly loadTime: DOMHighResTimeStamp;\n readonly size: number;\n readonly id: string;\n readonly url: string;\n readonly element: Element | null;\n}\n\ninterface WebVitalSpanOptions {\n name: string;\n op: string;\n origin: string;\n metricName: 'lcp' | 'cls' | 'inp';\n value: number;\n attributes?: SpanAttributes;\n parentSpan?: Span;\n reportEvent?: WebVitalReportEvent;\n startTime: number;\n endTime?: number;\n /**\n * When `true`, the span is sent on its own as a v2 streamed span instead of being folded into a\n * transaction. Used for INP when span streaming is disabled (it reports late, so it can't ride\n * the pageload transaction).\n *\n * TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always streams.\n */\n standalone?: boolean;\n}\n\n/**\n * Emits a web vital span. When `standalone` is set it is sent on its own as a v2 streamed span;\n * otherwise it flows through the span streaming pipeline as a child of `parentSpan`.\n */\nexport function _emitWebVitalSpan(options: WebVitalSpanOptions): void {\n const {\n name,\n op,\n origin,\n metricName,\n value,\n attributes: passedAttributes,\n parentSpan,\n reportEvent,\n startTime,\n endTime,\n standalone,\n } = options;\n\n const routeName = getCurrentScope().getScopeData().transactionName;\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,\n [`browser.web_vital.${metricName}.value`]: value,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n // Web vital score calculation relies on the user agent\n 'user_agent.original': WINDOW.navigator?.userAgent,\n ...passedAttributes,\n };\n\n if (parentSpan && spanToStreamedSpanJSON(parentSpan).attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'pageload') {\n // for LCP and CLS, we collect the pageload span id as an attribute\n attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;\n }\n\n if (reportEvent) {\n attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;\n }\n\n // A standalone span is sent as a plain v2 span without running the `processSpan` hooks (see\n // `captureStandaloneSpanWithStaticCallback`), so Replay can't attach the replay id itself. Set it\n // here, mirroring Replay's `processSpan`, so INP keeps its replay association like it did on v1.\n // TODO(standalone): remove once the static (transaction) trace lifecycle is dropped and INP always\n // streams, at which point Replay's `processSpan` runs and attaches the replay id.\n if (standalone) {\n Object.assign(attributes, getReplayAttributes());\n }\n\n const span = startInactiveSpan({\n name,\n attributes,\n startTime,\n parentSpan,\n // oxlint-disable-next-line typescript/no-deprecated -- intentional during the v1/v2 transition; see the TODO(standalone) above\n experimental: standalone ? { standalone: true } : undefined,\n });\n\n if (span) {\n span.end(endTime ?? startTime);\n }\n}\n\ninterface ReplayIntegration extends Integration {\n getReplayId: (onlyIfSampled?: boolean) => string | undefined;\n getRecordingMode: () => 'session' | 'buffer' | undefined;\n}\n\n// TODO(standalone): remove once the static (transaction) trace lifecycle is dropped; Replay's\n// `processSpan` then attaches the replay id to the streamed INP span instead.\nfunction getReplayAttributes(): SpanAttributes {\n const replay = getClient()?.getIntegrationByName<ReplayIntegration>('Replay');\n const replayId = replay?.getReplayId(true);\n if (!replayId) {\n return {};\n }\n\n return {\n 'sentry.replay_id': replayId,\n 'sentry._internal.replay_is_buffering': replay!.getRecordingMode() === 'buffer' ? true : undefined,\n };\n}\n\n/**\n * Tracks LCP as a streamed span.\n */\nexport function trackLcpAsSpan(client: Client): void {\n let lcpValue = 0;\n let lcpEntry: LargestContentfulPaint | undefined;\n\n if (!supportsWebVital('largest-contentful-paint')) {\n return;\n }\n\n const cleanupLcpHandler = addLcpInstrumentationHandler(({ metric }) => {\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, (reportEvent, _, pageloadSpan) => {\n _sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent);\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 reportEvent?: WebVitalReportEvent,\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 const timeOrigin = msToSec(performanceTimeOrigin);\n const endTime = msToSec(performanceTimeOrigin + (entry?.startTime || 0));\n const name = entry ? htmlTreeAsString(entry.element) : 'Largest contentful paint';\n\n const attributes: SpanAttributes = {};\n\n entry?.element && (attributes['browser.web_vital.lcp.element'] = htmlTreeAsString(entry.element));\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 reportEvent,\n startTime: timeOrigin,\n endTime,\n });\n}\n\n/**\n * Tracks CLS as a streamed span.\n */\nexport function trackClsAsSpan(client: Client): void {\n let clsValue = 0;\n let clsEntry: LayoutShift | undefined;\n\n if (!supportsWebVital('layout-shift')) {\n return;\n }\n\n const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {\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, (reportEvent, _, pageloadSpan) => {\n _sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent);\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 reportEvent?: WebVitalReportEvent,\n): void {\n DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);\n\n const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();\n const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';\n\n const attributes: SpanAttributes = {};\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 reportEvent,\n startTime,\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): 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 const onInp: InstrumentationHandlerCallback = ({ metric }) => {\n if (metric.value == null) {\n return;\n }\n\n const duration = msToSec(metric.value);\n\n if (duration > MAX_PLAUSIBLE_INP_DURATION) {\n return;\n }\n\n const entry = metric.entries.find(e => e.duration === metric.value && INP_ENTRY_MAP[e.name]);\n\n if (!entry) {\n return;\n }\n\n _sendInpSpan(metric.value, entry, standalone);\n };\n\n addInpInstrumentationHandler(onInp);\n}\n\n/**\n * Exported only for testing.\n */\nexport function _sendInpSpan(inpValue: number, entry: PerformanceEventTiming, standalone = false): void {\n DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`);\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(inpValue);\n const interactionType = INP_ENTRY_MAP[entry.name];\n\n const cachedContext = getCachedInteractionContext(entry.interactionId);\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n const spanToUse = cachedContext?.span || rootSpan;\n const routeName = spanToUse\n ? spanToStreamedSpanJSON(spanToUse).name\n : getCurrentScope().getScopeData().transactionName;\n const name = cachedContext?.elementName || htmlTreeAsString(entry.target);\n\n _emitWebVitalSpan({\n name,\n op: `ui.interaction.${interactionType}`,\n origin: 'auto.http.browser.inp',\n metricName: 'inp',\n value: inpValue,\n attributes: {\n [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry.duration,\n // oxlint-disable-next-line typescript-eslint/no-deprecated\n [SENTRY_TRANSACTION]: routeName,\n [SENTRY_SEGMENT_NAME]: routeName,\n },\n startTime,\n endTime: startTime + duration,\n parentSpan: spanToUse,\n standalone,\n });\n}\n"],"names":["getCurrentScope","attributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME","SENTRY_TRANSACTION","SENTRY_SEGMENT_NAME","WINDOW","spanToStreamedSpanJSON","startInactiveSpan","getClient","supportsWebVital","addLcpInstrumentationHandler","isValidLcpMetric","listenForWebVitalReportEvents","DEBUG_BUILD","debug","browserPerformanceTimeOrigin","msToSec","htmlTreeAsString","addClsInstrumentationHandler","timestampInSeconds","getBrowserPerformanceAPI","hasSpanStreamingEnabled","MAX_PLAUSIBLE_INP_DURATION","INP_ENTRY_MAP","addInpInstrumentationHandler","getCachedInteractionContext","getActiveSpan","getRootSpan"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlTreeAsString.js","sources":["../../src/htmlTreeAsString.ts"],"sourcesContent":["import { isString } from '@sentry/core';\n\nconst DEFAULT_MAX_STRING_LENGTH = 80;\n\ntype SimpleNode = {\n parentNode: SimpleNode;\n} | null;\n\n// Native DOM accessors cached at module load. Calling these instead of reading\n// instance properties bypasses user-defined getters that shadow the prototypes.\n// Stored unbound and rebound via .call(el) — the unbound-method lint is expected.\n// See https://github.com/getsentry/sentry-javascript/issues/21353\ntype AccessorKey = 'parentNode' | 'tagName' | 'id' | 'className' | 'getAttribute' | 'dataset';\nconst accessors: Partial<Record<AccessorKey, Function>> = {};\n\n// oxlint-disable typescript
|
|
1
|
+
{"version":3,"file":"htmlTreeAsString.js","sources":["../../src/htmlTreeAsString.ts"],"sourcesContent":["import { isString } from '@sentry/core';\n\nconst DEFAULT_MAX_STRING_LENGTH = 80;\n\ntype SimpleNode = {\n parentNode: SimpleNode;\n} | null;\n\n// Native DOM accessors cached at module load. Calling these instead of reading\n// instance properties bypasses user-defined getters that shadow the prototypes.\n// Stored unbound and rebound via .call(el) — the unbound-method lint is expected.\n// See https://github.com/getsentry/sentry-javascript/issues/21353\ntype AccessorKey = 'parentNode' | 'tagName' | 'id' | 'className' | 'getAttribute' | 'dataset';\nconst accessors: Partial<Record<AccessorKey, Function>> = {};\n\n// oxlint-disable typescript/unbound-method\ntry {\n if (typeof Node !== 'undefined') {\n accessors.parentNode = Object.getOwnPropertyDescriptor(Node.prototype, 'parentNode')!.get!;\n }\n if (typeof Element !== 'undefined') {\n accessors.tagName = Object.getOwnPropertyDescriptor(Element.prototype, 'tagName')!.get!;\n accessors.id = Object.getOwnPropertyDescriptor(Element.prototype, 'id')!.get!;\n accessors.className = Object.getOwnPropertyDescriptor(Element.prototype, 'className')!.get!;\n accessors.getAttribute = Element.prototype.getAttribute;\n }\n if (typeof HTMLElement !== 'undefined') {\n accessors.dataset = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset')!.get!;\n }\n} catch {\n // Polyfilled or stubbed prototypes may not have the expected descriptors.\n // _safeRead falls back to direct property access.\n}\n// oxlint-enable typescript/unbound-method\n\nfunction _safeRead<T>(el: unknown, prop: AccessorKey, arg?: string): T {\n const fn = accessors[prop];\n if (fn) {\n try {\n return fn.call(el, arg) as T;\n } catch {\n // Fall through to direct access\n }\n }\n const val = (el as Record<string, unknown>)[prop];\n return typeof val === 'function' ? val.call(el, arg) : (val as T);\n}\n\n/**\n * Given a child DOM element, returns a query-selector statement describing that\n * and its ancestors\n * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nexport function htmlTreeAsString(\n elem: unknown,\n options: string[] | { keyAttrs?: string[]; maxStringLength?: number } = {},\n): string {\n if (!elem) {\n return '<unknown>';\n }\n\n // try/catch both:\n // - accessing event.target (see getsentry/raven-js#838, #768)\n // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly\n // - can throw an exception in some circumstances.\n try {\n let currentElem = elem as SimpleNode;\n const MAX_TRAVERSE_HEIGHT = 5;\n const out = [];\n let height = 0;\n let len = 0;\n const separator = ' > ';\n const sepLength = separator.length;\n let nextStr;\n const keyAttrs = Array.isArray(options) ? options : options.keyAttrs;\n const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH;\n\n while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {\n nextStr = _htmlElementAsString(currentElem, keyAttrs);\n // bail out if\n // - nextStr is the 'html' element\n // - the length of the string that would be created exceeds maxStringLength\n // (ignore this limit if we are on the first iteration)\n if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) {\n break;\n }\n\n out.push(nextStr);\n\n len += nextStr.length;\n currentElem = _safeRead<SimpleNode>(currentElem, 'parentNode');\n }\n\n return out.reverse().join(separator);\n } catch {\n return '<unknown>';\n }\n}\n\n/**\n * Returns a simple, query-selector representation of a DOM element\n * e.g. [HTMLElement] => input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nfunction _htmlElementAsString(el: unknown, keyAttrs?: string[]): string {\n const out = [];\n\n const tagName = _safeRead<string | undefined>(el, 'tagName');\n if (!tagName) {\n return '';\n }\n\n if (typeof HTMLElement !== 'undefined') {\n // If using the component name annotation plugin, this value may be available on the DOM node\n if (el instanceof HTMLElement) {\n const dataset = _safeRead<DOMStringMap | undefined>(el, 'dataset');\n if (dataset) {\n if (dataset['sentryComponent']) {\n return dataset['sentryComponent'];\n }\n if (dataset['sentryElement']) {\n return dataset['sentryElement'];\n }\n }\n }\n }\n\n out.push(tagName.toLowerCase());\n\n // Pairs of attribute keys defined in `serializeAttribute` and their values on element.\n const keyAttrPairs = keyAttrs?.length\n ? keyAttrs\n .filter(keyAttr => _safeRead<string | null>(el, 'getAttribute', keyAttr))\n .map(keyAttr => [keyAttr, _safeRead<string | null>(el, 'getAttribute', keyAttr)])\n : null;\n\n if (keyAttrPairs?.length) {\n keyAttrPairs.forEach(keyAttrPair => {\n out.push(`[${keyAttrPair[0]}=\"${keyAttrPair[1]}\"]`);\n });\n } else {\n const id = _safeRead<string | undefined>(el, 'id');\n if (id) {\n out.push(`#${id}`);\n }\n\n const className = _safeRead<string | undefined>(el, 'className');\n if (className && isString(className)) {\n const classes = className.split(/\\s+/);\n for (const c of classes) {\n out.push(`.${c}`);\n }\n }\n }\n for (const k of ['aria-label', 'type', 'name', 'title', 'alt']) {\n const attr = _safeRead<string | null>(el, 'getAttribute', k);\n if (attr) {\n out.push(`[${k}=\"${attr}\"]`);\n }\n }\n\n return out.join('');\n}\n"],"names":[],"mappings":"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"}
|
package/build/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { addClsInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler, addPerformanceInstrumentationHandler, addTtfbInstrumentationHandler } from './metrics/instrument.js';
|
|
2
2
|
export { addPerformanceEntries, addWebVitalsToSpan, startTrackingInteractions, startTrackingLongAnimationFrames, startTrackingLongTasks, startTrackingWebVitals } from './metrics/browserMetrics.js';
|
|
3
3
|
export { elementTimingIntegration, startTrackingElementTiming } from './metrics/elementTiming.js';
|
|
4
|
+
export { userTimingIntegration } from './metrics/userTiming.js';
|
|
4
5
|
export { extractNetworkProtocol } from './metrics/utils.js';
|
|
5
6
|
export { trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan } from './metrics/webVitalSpans.js';
|
|
6
7
|
export { whenIdleOrHidden } from './metrics/web-vitals/lib/whenIdleOrHidden.js';
|
|
@@ -13,5 +14,5 @@ export { resourceTimingToSpanAttributes } from './metrics/resourceTiming.js';
|
|
|
13
14
|
export { htmlTreeAsString } from './htmlTreeAsString.js';
|
|
14
15
|
export { isElement } from './is.js';
|
|
15
16
|
export { getAbsoluteUrl } from './instrument/location.js';
|
|
16
|
-
export { registerInpInteractionListener
|
|
17
|
+
export { registerInpInteractionListener } from './metrics/inp.js';
|
|
17
18
|
//# sourceMappingURL=index.js.map
|
package/build/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
|
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
import { browserPerformanceTimeOrigin, spanToJSON, setMeasurement, getActiveSpan, parseUrl,
|
|
1
|
+
import { browserPerformanceTimeOrigin, spanToJSON, setMeasurement, getActiveSpan, parseUrl, filterCollectedUrl, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, debug, getComponentName } from '@sentry/core';
|
|
2
2
|
import { htmlTreeAsString } from '../htmlTreeAsString.js';
|
|
3
3
|
import { WINDOW } from '../types.js';
|
|
4
|
-
import { trackClsAsStandaloneSpan } from './cls.js';
|
|
5
4
|
import { addPerformanceInstrumentationHandler, addLcpInstrumentationHandler, addClsInstrumentationHandler, addTtfbInstrumentationHandler } from './instrument.js';
|
|
6
|
-
import {
|
|
5
|
+
import { isValidLcpMetric } from './lcp.js';
|
|
7
6
|
import { resourceTimingToSpanAttributes } from './resourceTiming.js';
|
|
8
7
|
import { getBrowserPerformanceAPI, msToSec, startAndEndSpan, isMeasurementValue } from './utils.js';
|
|
9
8
|
import { getActivationStart } from './web-vitals/lib/getActivationStart.js';
|
|
10
9
|
import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry.js';
|
|
11
10
|
import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher.js';
|
|
12
11
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
13
|
-
import { URL_FULL } from '@sentry/conventions/attributes';
|
|
12
|
+
import { URL_FULL, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
13
|
+
import { BROWSER_BROWSER_PAINT_SPAN_OP } from '@sentry/conventions/op';
|
|
14
14
|
|
|
15
15
|
const MAX_INT_AS_BYTES = 2147483647;
|
|
16
16
|
let _performanceCursor = 0;
|
|
17
17
|
let _measurements = {};
|
|
18
18
|
let _lcpEntry;
|
|
19
19
|
let _clsEntry;
|
|
20
|
-
function startTrackingWebVitals({
|
|
21
|
-
recordClsStandaloneSpans,
|
|
22
|
-
recordLcpStandaloneSpans,
|
|
23
|
-
client
|
|
24
|
-
}) {
|
|
20
|
+
function startTrackingWebVitals({ trackCls, trackLcp }) {
|
|
25
21
|
const performance = getBrowserPerformanceAPI();
|
|
26
22
|
if (performance && browserPerformanceTimeOrigin()) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
const lcpCleanupCallback = recordLcpStandaloneSpans ? trackLcpAsStandaloneSpan(client) : recordLcpStandaloneSpans === false ? _trackLCP() : void 0;
|
|
31
|
-
const clsCleanupCallback = recordClsStandaloneSpans ? trackClsAsStandaloneSpan(client) : recordClsStandaloneSpans === false ? _trackCLS() : void 0;
|
|
23
|
+
const lcpCleanupCallback = trackLcp ? _trackLCP() : void 0;
|
|
24
|
+
const clsCleanupCallback = trackCls ? _trackCLS() : void 0;
|
|
32
25
|
const ttfbCleanupCallback = _trackTtfb();
|
|
33
26
|
const fpFcpCleanupCallback = _trackFpFcp();
|
|
34
27
|
return () => {
|
|
@@ -55,7 +48,7 @@ function startTrackingLongTasks() {
|
|
|
55
48
|
}
|
|
56
49
|
startAndEndSpan(parent, startTime, startTime + duration, {
|
|
57
50
|
name: "Main UI thread blocked",
|
|
58
|
-
op: "ui.
|
|
51
|
+
op: "ui.long_task",
|
|
59
52
|
attributes: {
|
|
60
53
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.browser.metrics"
|
|
61
54
|
}
|
|
@@ -97,7 +90,7 @@ function startTrackingLongAnimationFrames() {
|
|
|
97
90
|
}
|
|
98
91
|
startAndEndSpan(parent, startTime, startTime + duration, {
|
|
99
92
|
name: "Main UI thread blocked",
|
|
100
|
-
op: "ui.
|
|
93
|
+
op: "ui.long_animation_frame",
|
|
101
94
|
attributes
|
|
102
95
|
});
|
|
103
96
|
}
|
|
@@ -180,7 +173,7 @@ function addPerformanceEntries(span, options) {
|
|
|
180
173
|
if (!performance?.getEntries || !origin) {
|
|
181
174
|
return;
|
|
182
175
|
}
|
|
183
|
-
const { spanStreamingEnabled,
|
|
176
|
+
const { spanStreamingEnabled, ignoreResourceSpans } = options;
|
|
184
177
|
const timeOrigin = msToSec(origin);
|
|
185
178
|
const performanceEntries = performance.getEntries();
|
|
186
179
|
const { op, start_timestamp: transactionStartTime } = spanToJSON(span);
|
|
@@ -201,10 +194,8 @@ function addPerformanceEntries(span, options) {
|
|
|
201
194
|
_addNavigationSpans(span, entry, timeOrigin);
|
|
202
195
|
break;
|
|
203
196
|
}
|
|
204
|
-
case "
|
|
205
|
-
|
|
206
|
-
case "measure": {
|
|
207
|
-
_addMeasureSpans(span, entry, startTime, duration, timeOrigin, ignorePerformanceApiSpans);
|
|
197
|
+
case "paint": {
|
|
198
|
+
_addPaintSpan(span, entry, startTime, duration, timeOrigin);
|
|
208
199
|
break;
|
|
209
200
|
}
|
|
210
201
|
case "resource": {
|
|
@@ -273,81 +264,25 @@ function resetWebVitalState() {
|
|
|
273
264
|
_clsEntry = void 0;
|
|
274
265
|
_measurements = {};
|
|
275
266
|
}
|
|
276
|
-
function
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
function _addMeasureSpans(span, entry, startTime, duration, timeOrigin, ignorePerformanceApiSpans) {
|
|
287
|
-
if (isReact19MeasureEntry(entry)) {
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (["mark", "measure"].includes(entry.entryType) && stringMatchesSomePattern(entry.name, ignorePerformanceApiSpans)) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const navEntry = getNavigationEntry(false);
|
|
294
|
-
const requestTime = msToSec(navEntry ? navEntry.requestStart : 0);
|
|
295
|
-
const measureStartTimestamp = timeOrigin + Math.max(startTime, requestTime);
|
|
296
|
-
const startTimeStamp = timeOrigin + startTime;
|
|
297
|
-
const measureEndTimestamp = startTimeStamp + duration;
|
|
298
|
-
const attributes = {
|
|
299
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.resource.browser.metrics"
|
|
300
|
-
};
|
|
301
|
-
if (measureStartTimestamp !== startTimeStamp) {
|
|
302
|
-
attributes["sentry.browser.measure_happened_before_request"] = true;
|
|
303
|
-
attributes["sentry.browser.measure_start_time"] = measureStartTimestamp;
|
|
304
|
-
}
|
|
305
|
-
_addDetailToSpanAttributes(attributes, entry);
|
|
306
|
-
if (measureStartTimestamp <= measureEndTimestamp) {
|
|
307
|
-
startAndEndSpan(span, measureStartTimestamp, measureEndTimestamp, {
|
|
308
|
-
name: entry.name,
|
|
309
|
-
op: entry.entryType,
|
|
310
|
-
attributes
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
function _addDetailToSpanAttributes(attributes, performanceMeasure) {
|
|
315
|
-
try {
|
|
316
|
-
const detail = performanceMeasure.detail;
|
|
317
|
-
if (!detail) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
if (typeof detail === "object") {
|
|
321
|
-
for (const [key, value] of Object.entries(detail)) {
|
|
322
|
-
if (value && isPrimitive(value)) {
|
|
323
|
-
attributes[`sentry.browser.measure.detail.${key}`] = value;
|
|
324
|
-
} else if (value !== void 0) {
|
|
325
|
-
try {
|
|
326
|
-
attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);
|
|
327
|
-
} catch {
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
if (isPrimitive(detail)) {
|
|
334
|
-
attributes["sentry.browser.measure.detail"] = detail;
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
try {
|
|
338
|
-
attributes["sentry.browser.measure.detail"] = JSON.stringify(detail);
|
|
339
|
-
} catch {
|
|
267
|
+
function _addPaintSpan(span, entry, startTime, duration, timeOrigin) {
|
|
268
|
+
const startTimestamp = timeOrigin + startTime;
|
|
269
|
+
startAndEndSpan(span, startTimestamp, startTimestamp + duration, {
|
|
270
|
+
name: entry.name,
|
|
271
|
+
attributes: {
|
|
272
|
+
[SENTRY_OP]: BROWSER_BROWSER_PAINT_SPAN_OP,
|
|
273
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.resource.browser.metrics"
|
|
340
274
|
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
275
|
+
});
|
|
343
276
|
}
|
|
344
277
|
function _addNavigationSpans(span, entry, timeOrigin) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
_addPerformanceNavigationTiming(span, entry, "
|
|
278
|
+
_addPerformanceNavigationTiming(span, entry, "unloadEvent", timeOrigin, "unload_event");
|
|
279
|
+
_addPerformanceNavigationTiming(span, entry, "redirect", timeOrigin, "redirect");
|
|
280
|
+
_addPerformanceNavigationTiming(span, entry, "domContentLoadedEvent", timeOrigin, "dom_content_loaded_event");
|
|
281
|
+
_addPerformanceNavigationTiming(span, entry, "loadEvent", timeOrigin, "load_event");
|
|
282
|
+
_addPerformanceNavigationTiming(span, entry, "connect", timeOrigin, "connect");
|
|
283
|
+
_addPerformanceNavigationTiming(span, entry, "secureConnection", timeOrigin, "tls_ssl");
|
|
349
284
|
_addPerformanceNavigationTiming(span, entry, "fetch", timeOrigin, "cache");
|
|
350
|
-
_addPerformanceNavigationTiming(span, entry, "domainLookup", timeOrigin, "
|
|
285
|
+
_addPerformanceNavigationTiming(span, entry, "domainLookup", timeOrigin, "dns");
|
|
351
286
|
_addRequest(span, entry, timeOrigin);
|
|
352
287
|
}
|
|
353
288
|
function _addPerformanceNavigationTiming(span, entry, event, timeOrigin, name = event) {
|
|
@@ -415,7 +350,7 @@ function _addResourceSpans(span, entry, resourceUrl, startTime, duration, timeOr
|
|
|
415
350
|
attributes["server.address"] = parsedUrl.host;
|
|
416
351
|
}
|
|
417
352
|
attributes["url.same_origin"] = resourceUrl.includes(WINDOW.location.origin);
|
|
418
|
-
attributes[URL_FULL] = resourceUrl;
|
|
353
|
+
attributes[URL_FULL] = filterCollectedUrl(resourceUrl);
|
|
419
354
|
_setResourceRequestAttributes(entry, attributes, [
|
|
420
355
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus
|
|
421
356
|
["responseStatus", "http.response.status_code"],
|
|
@@ -522,5 +457,5 @@ function _addTtfbRequestTimeToMeasurements(_measurements2) {
|
|
|
522
457
|
}
|
|
523
458
|
}
|
|
524
459
|
|
|
525
|
-
export {
|
|
460
|
+
export { _addNavigationSpans, _addResourceSpans, _setResourceRequestAttributes, addPerformanceEntries, addWebVitalsToSpan, startTrackingInteractions, startTrackingLongAnimationFrames, startTrackingLongTasks, startTrackingWebVitals };
|
|
526
461
|
//# sourceMappingURL=browserMetrics.js.map
|