import { debug, browserPerformanceTimeOrigin, timestampInSeconds, getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import { DEBUG_BUILD } from '../debug-build.js'; import { htmlTreeAsString } from '../htmlTreeAsString.js'; import { addClsInstrumentationHandler } from './instrument.js'; import { supportsWebVital, listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan } from './utils.js'; function trackClsAsStandaloneSpan(client) { let standaloneCLsValue = 0; let standaloneClsEntry; if (!supportsWebVital("layout-shift")) { return; } const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => { const entry = metric.entries[metric.entries.length - 1]; if (!entry) { return; } standaloneCLsValue = metric.value; standaloneClsEntry = entry; }, true); listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => { _sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent); cleanupClsHandler(); }); } function _sendStandaloneClsSpan(clsValue, entry, pageloadSpanId, reportEvent) { DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`); const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds(); const routeName = getCurrentScope().getScopeData().transactionName; const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : "Layout shift"; const attributes = { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.cls", [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "ui.webvital.cls", [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0, // attach the pageload span id to the CLS span so that we can link them in the UI "sentry.pageload.span_id": pageloadSpanId, // describes what triggered the web vital to be reported "sentry.report_event": reportEvent }; if (entry?.sources) { entry.sources.forEach((source, index) => { attributes[`cls.source.${index + 1}`] = htmlTreeAsString(source.node); }); } const span = startStandaloneWebVitalSpan({ name, transaction: routeName, attributes, startTime }); if (span) { span.addEvent("cls", { [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: "", [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: clsValue }); span.end(startTime); } } export { _sendStandaloneClsSpan, trackClsAsStandaloneSpan }; //# sourceMappingURL=cls.js.map