@sentry/browser-utils 11.0.0-alpha.0 → 11.0.0-alpha.1
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/index.js +29 -28
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrumentation/dom.js.map +1 -0
- package/build/cjs/instrumentation/history.js.map +1 -0
- package/build/cjs/instrumentation/location.js.map +1 -0
- package/build/cjs/{metrics/instrument.js → instrumentation/performanceObserver.js} +44 -32
- package/build/cjs/instrumentation/performanceObserver.js.map +1 -0
- package/build/cjs/instrumentation/xhr.js.map +1 -0
- package/build/cjs/{metrics → performance}/elementTiming.js +2 -2
- package/build/cjs/performance/elementTiming.js.map +1 -0
- package/build/cjs/{metrics/browserMetrics.js → performance/entries.js} +22 -175
- package/build/cjs/performance/entries.js.map +1 -0
- package/build/cjs/performance/resourceTiming.js.map +1 -0
- package/build/cjs/{metrics → performance}/userTiming.js +4 -3
- package/build/cjs/performance/userTiming.js.map +1 -0
- package/build/cjs/{metrics → performance}/utils.js +1 -27
- package/build/cjs/performance/utils.js.map +1 -0
- package/build/cjs/{metrics → web-vitals}/inp.js +4 -4
- package/build/cjs/web-vitals/inp.js.map +1 -0
- package/build/cjs/web-vitals/lcp.js.map +1 -0
- package/build/cjs/web-vitals/reportEvents.js +31 -0
- package/build/cjs/web-vitals/reportEvents.js.map +1 -0
- package/build/cjs/{metrics/webVitalSpans.js → web-vitals/spans.js} +11 -10
- package/build/cjs/web-vitals/spans.js.map +1 -0
- package/build/cjs/web-vitals/tracking.js +164 -0
- package/build/cjs/web-vitals/tracking.js.map +1 -0
- package/build/cjs/web-vitals/utils.js +99 -0
- package/build/cjs/web-vitals/utils.js.map +1 -0
- package/build/esm/index.js +14 -13
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrumentation/dom.js.map +1 -0
- package/build/esm/instrumentation/history.js.map +1 -0
- package/build/esm/instrumentation/location.js.map +1 -0
- package/build/esm/{metrics/instrument.js → instrumentation/performanceObserver.js} +42 -30
- package/build/esm/instrumentation/performanceObserver.js.map +1 -0
- package/build/esm/instrumentation/xhr.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/{metrics → performance}/elementTiming.js +1 -1
- package/build/esm/performance/elementTiming.js.map +1 -0
- package/build/esm/{metrics/browserMetrics.js → performance/entries.js} +15 -166
- package/build/esm/performance/entries.js.map +1 -0
- package/build/esm/performance/resourceTiming.js.map +1 -0
- package/build/esm/{metrics → performance}/userTiming.js +4 -3
- package/build/esm/performance/userTiming.js.map +1 -0
- package/build/esm/{metrics → performance}/utils.js +3 -28
- package/build/esm/performance/utils.js.map +1 -0
- package/build/esm/{metrics → web-vitals}/inp.js +1 -1
- package/build/esm/web-vitals/inp.js.map +1 -0
- package/build/esm/web-vitals/lcp.js.map +1 -0
- package/build/esm/web-vitals/reportEvents.js +29 -0
- package/build/esm/web-vitals/reportEvents.js.map +1 -0
- package/build/esm/{metrics/webVitalSpans.js → web-vitals/spans.js} +7 -6
- package/build/esm/web-vitals/spans.js.map +1 -0
- package/build/esm/web-vitals/tracking.js +161 -0
- package/build/esm/web-vitals/tracking.js.map +1 -0
- package/build/esm/web-vitals/utils.js +91 -0
- package/build/esm/web-vitals/utils.js.map +1 -0
- package/build/types/index.d.ts +13 -12
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrumentation/dom.d.ts.map +1 -0
- package/build/types/instrumentation/history.d.ts.map +1 -0
- package/build/types/instrumentation/location.d.ts.map +1 -0
- package/build/types/{metrics/instrument.d.ts → instrumentation/performanceObserver.d.ts} +3 -3
- package/build/types/instrumentation/performanceObserver.d.ts.map +1 -0
- package/build/types/instrumentation/xhr.d.ts.map +1 -0
- package/build/types/performance/elementTiming.d.ts.map +1 -0
- package/build/types/{metrics/browserMetrics.d.ts → performance/entries.d.ts} +3 -46
- package/build/types/performance/entries.d.ts.map +1 -0
- package/build/types/performance/resourceTiming.d.ts.map +1 -0
- package/build/types/performance/userTiming.d.ts.map +1 -0
- package/build/types/{metrics → performance}/utils.d.ts +1 -17
- package/build/types/performance/utils.d.ts.map +1 -0
- package/build/types/web-vitals/inp.d.ts.map +1 -0
- package/build/types/web-vitals/lcp.d.ts.map +1 -0
- package/build/types/web-vitals/reportEvents.d.ts +18 -0
- package/build/types/web-vitals/reportEvents.d.ts.map +1 -0
- package/build/types/{metrics/webVitalSpans.d.ts → web-vitals/spans.d.ts} +3 -3
- package/build/types/web-vitals/spans.d.ts.map +1 -0
- package/build/types/web-vitals/tracking.d.ts +46 -0
- package/build/types/web-vitals/tracking.d.ts.map +1 -0
- package/build/types/{metrics/web-vitals/lib/globalListeners.d.ts → web-vitals/utils.d.ts} +16 -1
- package/build/types/web-vitals/utils.d.ts.map +1 -0
- package/package.json +4 -3
- package/build/cjs/instrument/dom.js.map +0 -1
- package/build/cjs/instrument/history.js.map +0 -1
- package/build/cjs/instrument/location.js.map +0 -1
- package/build/cjs/instrument/xhr.js.map +0 -1
- package/build/cjs/metrics/browserMetrics.js.map +0 -1
- package/build/cjs/metrics/elementTiming.js.map +0 -1
- package/build/cjs/metrics/inp.js.map +0 -1
- package/build/cjs/metrics/instrument.js.map +0 -1
- package/build/cjs/metrics/lcp.js.map +0 -1
- package/build/cjs/metrics/resourceTiming.js.map +0 -1
- package/build/cjs/metrics/userTiming.js.map +0 -1
- package/build/cjs/metrics/utils.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getCLS.js +0 -46
- package/build/cjs/metrics/web-vitals/getCLS.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getINP.js +0 -60
- package/build/cjs/metrics/web-vitals/getINP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/getLCP.js +0 -62
- package/build/cjs/metrics/web-vitals/getLCP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js +0 -87
- package/build/cjs/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js +0 -11
- package/build/cjs/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js +0 -27
- package/build/cjs/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js +0 -31
- package/build/cjs/metrics/web-vitals/lib/bindReporter.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js +0 -8
- package/build/cjs/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js +0 -11
- package/build/cjs/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js +0 -17
- package/build/cjs/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -44
- package/build/cjs/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js +0 -18
- package/build/cjs/metrics/web-vitals/lib/globalListeners.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/initMetric.js +0 -34
- package/build/cjs/metrics/web-vitals/lib/initMetric.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/initUnique.js +0 -16
- package/build/cjs/metrics/web-vitals/lib/initUnique.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/observe.js +0 -20
- package/build/cjs/metrics/web-vitals/lib/observe.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/onHidden.js +0 -16
- package/build/cjs/metrics/web-vitals/lib/onHidden.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -32
- package/build/cjs/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/runOnce.js +0 -14
- package/build/cjs/metrics/web-vitals/lib/runOnce.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js +0 -14
- package/build/cjs/metrics/web-vitals/lib/whenActivated.js.map +0 -1
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -22
- package/build/cjs/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
- package/build/cjs/metrics/web-vitals/onFCP.js +0 -37
- package/build/cjs/metrics/web-vitals/onFCP.js.map +0 -1
- package/build/cjs/metrics/web-vitals/onTTFB.js +0 -35
- package/build/cjs/metrics/web-vitals/onTTFB.js.map +0 -1
- package/build/cjs/metrics/webVitalSpans.js.map +0 -1
- package/build/esm/instrument/dom.js.map +0 -1
- package/build/esm/instrument/history.js.map +0 -1
- package/build/esm/instrument/location.js.map +0 -1
- package/build/esm/instrument/xhr.js.map +0 -1
- package/build/esm/metrics/browserMetrics.js.map +0 -1
- package/build/esm/metrics/elementTiming.js.map +0 -1
- package/build/esm/metrics/inp.js.map +0 -1
- package/build/esm/metrics/instrument.js.map +0 -1
- package/build/esm/metrics/lcp.js.map +0 -1
- package/build/esm/metrics/resourceTiming.js.map +0 -1
- package/build/esm/metrics/userTiming.js.map +0 -1
- package/build/esm/metrics/utils.js.map +0 -1
- package/build/esm/metrics/web-vitals/getCLS.js +0 -43
- package/build/esm/metrics/web-vitals/getCLS.js.map +0 -1
- package/build/esm/metrics/web-vitals/getINP.js +0 -57
- package/build/esm/metrics/web-vitals/getINP.js.map +0 -1
- package/build/esm/metrics/web-vitals/getLCP.js +0 -59
- package/build/esm/metrics/web-vitals/getLCP.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js +0 -85
- package/build/esm/metrics/web-vitals/lib/InteractionManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js +0 -9
- package/build/esm/metrics/web-vitals/lib/LCPEntryManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js +0 -25
- package/build/esm/metrics/web-vitals/lib/LayoutShiftManager.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/bindReporter.js +0 -29
- package/build/esm/metrics/web-vitals/lib/bindReporter.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js +0 -6
- package/build/esm/metrics/web-vitals/lib/generateUniqueID.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js +0 -9
- package/build/esm/metrics/web-vitals/lib/getActivationStart.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js +0 -15
- package/build/esm/metrics/web-vitals/lib/getNavigationEntry.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js +0 -42
- package/build/esm/metrics/web-vitals/lib/getVisibilityWatcher.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/globalListeners.js +0 -15
- package/build/esm/metrics/web-vitals/lib/globalListeners.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/initMetric.js +0 -32
- package/build/esm/metrics/web-vitals/lib/initMetric.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/initUnique.js +0 -14
- package/build/esm/metrics/web-vitals/lib/initUnique.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/observe.js +0 -18
- package/build/esm/metrics/web-vitals/lib/observe.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/onHidden.js +0 -14
- package/build/esm/metrics/web-vitals/lib/onHidden.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js +0 -29
- package/build/esm/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/runOnce.js +0 -12
- package/build/esm/metrics/web-vitals/lib/runOnce.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/whenActivated.js +0 -12
- package/build/esm/metrics/web-vitals/lib/whenActivated.js.map +0 -1
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js +0 -20
- package/build/esm/metrics/web-vitals/lib/whenIdleOrHidden.js.map +0 -1
- package/build/esm/metrics/web-vitals/onFCP.js +0 -34
- package/build/esm/metrics/web-vitals/onFCP.js.map +0 -1
- package/build/esm/metrics/web-vitals/onTTFB.js +0 -32
- package/build/esm/metrics/web-vitals/onTTFB.js.map +0 -1
- package/build/esm/metrics/webVitalSpans.js.map +0 -1
- package/build/types/instrument/dom.d.ts.map +0 -1
- package/build/types/instrument/history.d.ts.map +0 -1
- package/build/types/instrument/location.d.ts.map +0 -1
- package/build/types/instrument/xhr.d.ts.map +0 -1
- package/build/types/metrics/browserMetrics.d.ts.map +0 -1
- package/build/types/metrics/elementTiming.d.ts.map +0 -1
- package/build/types/metrics/inp.d.ts.map +0 -1
- package/build/types/metrics/instrument.d.ts.map +0 -1
- package/build/types/metrics/lcp.d.ts.map +0 -1
- package/build/types/metrics/resourceTiming.d.ts.map +0 -1
- package/build/types/metrics/userTiming.d.ts.map +0 -1
- package/build/types/metrics/utils.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getCLS.d.ts +0 -26
- package/build/types/metrics/web-vitals/getCLS.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getINP.d.ts +0 -34
- package/build/types/metrics/web-vitals/getINP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/getLCP.d.ts +0 -16
- package/build/types/metrics/web-vitals/getLCP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts +0 -37
- package/build/types/metrics/web-vitals/lib/InteractionManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts +0 -5
- package/build/types/metrics/web-vitals/lib/LCPEntryManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/LayoutShiftManager.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/bindReporter.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/generateUniqueID.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/getActivationStart.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/getNavigationEntry.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts +0 -5
- package/build/types/metrics/web-vitals/lib/getVisibilityWatcher.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/globalListeners.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts +0 -21
- package/build/types/metrics/web-vitals/lib/initMetric.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts +0 -7
- package/build/types/metrics/web-vitals/lib/initUnique.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/observe.d.ts +0 -23
- package/build/types/metrics/web-vitals/lib/observe.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts +0 -15
- package/build/types/metrics/web-vitals/lib/onHidden.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts +0 -15
- package/build/types/metrics/web-vitals/lib/polyfills/interactionCountPolyfill.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/runOnce.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts +0 -2
- package/build/types/metrics/web-vitals/lib/whenActivated.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts +0 -6
- package/build/types/metrics/web-vitals/lib/whenIdleOrHidden.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/onFCP.d.ts +0 -11
- package/build/types/metrics/web-vitals/onFCP.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/onTTFB.d.ts +0 -20
- package/build/types/metrics/web-vitals/onTTFB.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/base.d.ts +0 -103
- package/build/types/metrics/web-vitals/types/base.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/cls.d.ts +0 -58
- package/build/types/metrics/web-vitals/types/cls.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/fcp.d.ts +0 -47
- package/build/types/metrics/web-vitals/types/fcp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/inp.d.ts +0 -150
- package/build/types/metrics/web-vitals/types/inp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/lcp.d.ts +0 -74
- package/build/types/metrics/web-vitals/types/lcp.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types/ttfb.d.ts +0 -60
- package/build/types/metrics/web-vitals/types/ttfb.d.ts.map +0 -1
- package/build/types/metrics/web-vitals/types.d.ts +0 -78
- package/build/types/metrics/web-vitals/types.d.ts.map +0 -1
- package/build/types/metrics/webVitalSpans.d.ts.map +0 -1
- /package/build/cjs/{instrument → instrumentation}/dom.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/history.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/location.js +0 -0
- /package/build/cjs/{instrument → instrumentation}/xhr.js +0 -0
- /package/build/cjs/{metrics → performance}/resourceTiming.js +0 -0
- /package/build/cjs/{metrics → web-vitals}/lcp.js +0 -0
- /package/build/esm/{instrument → instrumentation}/dom.js +0 -0
- /package/build/esm/{instrument → instrumentation}/history.js +0 -0
- /package/build/esm/{instrument → instrumentation}/location.js +0 -0
- /package/build/esm/{instrument → instrumentation}/xhr.js +0 -0
- /package/build/esm/{metrics → performance}/resourceTiming.js +0 -0
- /package/build/esm/{metrics → web-vitals}/lcp.js +0 -0
- /package/build/types/{instrument → instrumentation}/dom.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/history.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/location.d.ts +0 -0
- /package/build/types/{instrument → instrumentation}/xhr.d.ts +0 -0
- /package/build/types/{metrics → performance}/elementTiming.d.ts +0 -0
- /package/build/types/{metrics → performance}/resourceTiming.d.ts +0 -0
- /package/build/types/{metrics → performance}/userTiming.d.ts +0 -0
- /package/build/types/{metrics → web-vitals}/inp.d.ts +0 -0
- /package/build/types/{metrics → web-vitals}/lcp.d.ts +0 -0
|
@@ -1,51 +1,27 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
|
+
const attributes = require('@sentry/conventions/attributes');
|
|
5
|
+
const op = require('@sentry/conventions/op');
|
|
4
6
|
const htmlTreeAsString = require('../htmlTreeAsString.js');
|
|
7
|
+
const performanceObserver = require('../instrumentation/performanceObserver.js');
|
|
5
8
|
const types = require('../types.js');
|
|
6
|
-
const instrument = require('./instrument.js');
|
|
7
|
-
const lcp = require('./lcp.js');
|
|
8
9
|
const resourceTiming = require('./resourceTiming.js');
|
|
9
10
|
const utils = require('./utils.js');
|
|
10
|
-
const getActivationStart = require('./web-vitals/lib/getActivationStart.js');
|
|
11
|
-
const getNavigationEntry = require('./web-vitals/lib/getNavigationEntry.js');
|
|
12
|
-
const getVisibilityWatcher = require('./web-vitals/lib/getVisibilityWatcher.js');
|
|
13
|
-
const debugBuild = require('../debug-build.js');
|
|
14
|
-
const attributes = require('@sentry/conventions/attributes');
|
|
15
|
-
const op = require('@sentry/conventions/op');
|
|
16
11
|
|
|
17
12
|
const MAX_INT_AS_BYTES = 2147483647;
|
|
18
13
|
let _performanceCursor = 0;
|
|
19
|
-
let _measurements = {};
|
|
20
|
-
let _lcpEntry;
|
|
21
|
-
let _clsEntry;
|
|
22
|
-
function startTrackingWebVitals({ trackCls, trackLcp }) {
|
|
23
|
-
const performance = utils.getBrowserPerformanceAPI();
|
|
24
|
-
if (performance && core.browserPerformanceTimeOrigin()) {
|
|
25
|
-
const lcpCleanupCallback = trackLcp ? _trackLCP() : void 0;
|
|
26
|
-
const clsCleanupCallback = trackCls ? _trackCLS() : void 0;
|
|
27
|
-
const ttfbCleanupCallback = _trackTtfb();
|
|
28
|
-
const fpFcpCleanupCallback = _trackFpFcp();
|
|
29
|
-
return () => {
|
|
30
|
-
ttfbCleanupCallback();
|
|
31
|
-
fpFcpCleanupCallback();
|
|
32
|
-
lcpCleanupCallback?.();
|
|
33
|
-
clsCleanupCallback?.();
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return () => void 0;
|
|
37
|
-
}
|
|
38
14
|
function startTrackingLongTasks() {
|
|
39
|
-
|
|
15
|
+
performanceObserver.addPerformanceInstrumentationHandler("longtask", ({ entries }) => {
|
|
40
16
|
const parent = core.getActiveSpan();
|
|
41
17
|
if (!parent) {
|
|
42
18
|
return;
|
|
43
19
|
}
|
|
44
|
-
const {
|
|
20
|
+
const { attributes: parentAttributes, start_timestamp: parentStartTimestamp } = core.spanToJSON(parent);
|
|
45
21
|
for (const entry of entries) {
|
|
46
22
|
const startTime = utils.msToSec(core.browserPerformanceTimeOrigin() + entry.startTime);
|
|
47
23
|
const duration = utils.msToSec(entry.duration);
|
|
48
|
-
if (
|
|
24
|
+
if (parentAttributes[attributes.SENTRY_OP] === "navigation" && parentStartTimestamp && startTime < parentStartTimestamp) {
|
|
49
25
|
continue;
|
|
50
26
|
}
|
|
51
27
|
utils.startAndEndSpan(parent, startTime, startTime + duration, {
|
|
@@ -69,38 +45,41 @@ function startTrackingLongAnimationFrames() {
|
|
|
69
45
|
continue;
|
|
70
46
|
}
|
|
71
47
|
const startTime = utils.msToSec(core.browserPerformanceTimeOrigin() + entry.startTime);
|
|
72
|
-
const {
|
|
48
|
+
const {
|
|
49
|
+
start_timestamp: parentStartTimestamp,
|
|
50
|
+
attributes: { [attributes.SENTRY_OP]: parentOp }
|
|
51
|
+
} = core.spanToJSON(parent);
|
|
73
52
|
if (parentOp === "navigation" && parentStartTimestamp && startTime < parentStartTimestamp) {
|
|
74
53
|
continue;
|
|
75
54
|
}
|
|
76
55
|
const duration = utils.msToSec(entry.duration);
|
|
77
|
-
const attributes = {
|
|
56
|
+
const attributes$1 = {
|
|
78
57
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.browser.metrics"
|
|
79
58
|
};
|
|
80
59
|
const initialScript = entry.scripts[0];
|
|
81
60
|
const { invoker, invokerType, sourceURL, sourceFunctionName, sourceCharPosition } = initialScript;
|
|
82
|
-
attributes["browser.script.invoker"] = invoker;
|
|
83
|
-
attributes["browser.script.invoker_type"] = invokerType;
|
|
61
|
+
attributes$1["browser.script.invoker"] = invoker;
|
|
62
|
+
attributes$1["browser.script.invoker_type"] = invokerType;
|
|
84
63
|
if (sourceURL) {
|
|
85
|
-
attributes["code.filepath"] = sourceURL;
|
|
64
|
+
attributes$1["code.filepath"] = sourceURL;
|
|
86
65
|
}
|
|
87
66
|
if (sourceFunctionName) {
|
|
88
|
-
attributes["code.function"] = sourceFunctionName;
|
|
67
|
+
attributes$1["code.function"] = sourceFunctionName;
|
|
89
68
|
}
|
|
90
69
|
if (sourceCharPosition !== -1) {
|
|
91
|
-
attributes["browser.script.source_char_position"] = sourceCharPosition;
|
|
70
|
+
attributes$1["browser.script.source_char_position"] = sourceCharPosition;
|
|
92
71
|
}
|
|
93
72
|
utils.startAndEndSpan(parent, startTime, startTime + duration, {
|
|
94
73
|
name: "Main UI thread blocked",
|
|
95
74
|
op: "ui.long_animation_frame",
|
|
96
|
-
attributes
|
|
75
|
+
attributes: attributes$1
|
|
97
76
|
});
|
|
98
77
|
}
|
|
99
78
|
});
|
|
100
79
|
observer.observe({ type: "long-animation-frame", buffered: true });
|
|
101
80
|
}
|
|
102
81
|
function startTrackingInteractions() {
|
|
103
|
-
|
|
82
|
+
performanceObserver.addPerformanceInstrumentationHandler("event", ({ entries }) => {
|
|
104
83
|
const parent = core.getActiveSpan();
|
|
105
84
|
if (!parent) {
|
|
106
85
|
return;
|
|
@@ -126,49 +105,6 @@ function startTrackingInteractions() {
|
|
|
126
105
|
}
|
|
127
106
|
});
|
|
128
107
|
}
|
|
129
|
-
function _trackCLS() {
|
|
130
|
-
return instrument.addClsInstrumentationHandler(({ metric }) => {
|
|
131
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
132
|
-
if (!entry) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
_measurements["cls"] = { value: metric.value, unit: "" };
|
|
136
|
-
_clsEntry = entry;
|
|
137
|
-
}, true);
|
|
138
|
-
}
|
|
139
|
-
function _trackLCP() {
|
|
140
|
-
return instrument.addLcpInstrumentationHandler(({ metric }) => {
|
|
141
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
142
|
-
if (!entry || !lcp.isValidLcpMetric(metric.value)) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
_measurements["lcp"] = { value: metric.value, unit: "millisecond" };
|
|
146
|
-
_lcpEntry = entry;
|
|
147
|
-
}, true);
|
|
148
|
-
}
|
|
149
|
-
function _trackTtfb() {
|
|
150
|
-
return instrument.addTtfbInstrumentationHandler(({ metric }) => {
|
|
151
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
152
|
-
if (!entry) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
_measurements["ttfb"] = { value: metric.value, unit: "millisecond" };
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
function _trackFpFcp() {
|
|
159
|
-
return instrument.addPerformanceInstrumentationHandler("paint", ({ entries }) => {
|
|
160
|
-
const firstHidden = getVisibilityWatcher.getVisibilityWatcher();
|
|
161
|
-
for (const entry of entries) {
|
|
162
|
-
const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;
|
|
163
|
-
if (entry.name === "first-paint" && shouldRecord) {
|
|
164
|
-
_measurements["fp"] = { value: entry.startTime, unit: "millisecond" };
|
|
165
|
-
}
|
|
166
|
-
if (entry.name === "first-contentful-paint" && shouldRecord) {
|
|
167
|
-
_measurements["fcp"] = { value: entry.startTime, unit: "millisecond" };
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
108
|
function addPerformanceEntries(span, options) {
|
|
173
109
|
const performance = utils.getBrowserPerformanceAPI();
|
|
174
110
|
const origin = core.browserPerformanceTimeOrigin();
|
|
@@ -178,7 +114,7 @@ function addPerformanceEntries(span, options) {
|
|
|
178
114
|
const { spanStreamingEnabled, ignoreResourceSpans } = options;
|
|
179
115
|
const timeOrigin = utils.msToSec(origin);
|
|
180
116
|
const performanceEntries = performance.getEntries();
|
|
181
|
-
const {
|
|
117
|
+
const { attributes: attributes$1, start_timestamp: transactionStartTime } = core.spanToJSON(span);
|
|
182
118
|
performanceEntries.slice(_performanceCursor).forEach((entry) => {
|
|
183
119
|
const startTime = utils.msToSec(entry.startTime);
|
|
184
120
|
const duration = utils.msToSec(
|
|
@@ -188,7 +124,7 @@ function addPerformanceEntries(span, options) {
|
|
|
188
124
|
// TODO: Investigate why this happens and how to properly mitigate. For now, this is a workaround to prevent transactions being dropped due to negative duration spans.
|
|
189
125
|
Math.max(0, entry.duration)
|
|
190
126
|
);
|
|
191
|
-
if (
|
|
127
|
+
if (attributes$1[attributes.SENTRY_OP] === "navigation" && transactionStartTime && timeOrigin + startTime < transactionStartTime) {
|
|
192
128
|
return;
|
|
193
129
|
}
|
|
194
130
|
switch (entry.entryType) {
|
|
@@ -217,55 +153,6 @@ function addPerformanceEntries(span, options) {
|
|
|
217
153
|
_performanceCursor = Math.max(performanceEntries.length - 1, 0);
|
|
218
154
|
_trackNavigator(span, spanStreamingEnabled);
|
|
219
155
|
}
|
|
220
|
-
function addWebVitalsToSpan(span, options) {
|
|
221
|
-
const origin = core.browserPerformanceTimeOrigin();
|
|
222
|
-
if (!utils.getBrowserPerformanceAPI()?.getEntries || !origin) {
|
|
223
|
-
resetWebVitalState();
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const { spanStreamingEnabled, recordClsOnPageloadSpan, recordLcpOnPageloadSpan } = options;
|
|
227
|
-
const timeOrigin = utils.msToSec(origin);
|
|
228
|
-
if (core.spanToJSON(span).op === "pageload") {
|
|
229
|
-
_addTtfbRequestTimeToMeasurements(_measurements);
|
|
230
|
-
if (spanStreamingEnabled) {
|
|
231
|
-
const setAttr = (shortWebVitalName, value, customAttrName) => {
|
|
232
|
-
const attrKey = customAttrName ?? `browser.web_vital.${shortWebVitalName}.value`;
|
|
233
|
-
span.setAttribute(attrKey, value);
|
|
234
|
-
debugBuild.DEBUG_BUILD && core.debug.log("Setting web vital attribute", { [attrKey]: value }, "on pageload span");
|
|
235
|
-
};
|
|
236
|
-
["ttfb", "fp", "fcp"].forEach((measurementName) => {
|
|
237
|
-
if (_measurements[measurementName]) {
|
|
238
|
-
setAttr(measurementName, _measurements[measurementName].value);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
if (_measurements["ttfb.requestTime"]) {
|
|
242
|
-
setAttr("ttfb.requestTime", _measurements["ttfb.requestTime"].value, "browser.web_vital.ttfb.request_time");
|
|
243
|
-
}
|
|
244
|
-
} else {
|
|
245
|
-
if (!recordClsOnPageloadSpan) {
|
|
246
|
-
delete _measurements.cls;
|
|
247
|
-
}
|
|
248
|
-
if (!recordLcpOnPageloadSpan) {
|
|
249
|
-
delete _measurements.lcp;
|
|
250
|
-
}
|
|
251
|
-
Object.entries(_measurements).forEach(([measurementName, measurement]) => {
|
|
252
|
-
core.setMeasurement(measurementName, measurement.value, measurement.unit, span);
|
|
253
|
-
});
|
|
254
|
-
_setWebVitalAttributes(span, options);
|
|
255
|
-
}
|
|
256
|
-
span.setAttribute(spanStreamingEnabled ? "browser.performance.time_origin" : "performance.timeOrigin", timeOrigin);
|
|
257
|
-
span.setAttribute(
|
|
258
|
-
spanStreamingEnabled ? "browser.performance.navigation.activation_start" : "performance.activationStart",
|
|
259
|
-
getActivationStart.getActivationStart()
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
resetWebVitalState();
|
|
263
|
-
}
|
|
264
|
-
function resetWebVitalState() {
|
|
265
|
-
_lcpEntry = void 0;
|
|
266
|
-
_clsEntry = void 0;
|
|
267
|
-
_measurements = {};
|
|
268
|
-
}
|
|
269
156
|
function _addPaintSpan(span, entry, startTime, duration, timeOrigin) {
|
|
270
157
|
const startTimestamp = timeOrigin + startTime;
|
|
271
158
|
utils.startAndEndSpan(span, startTimestamp, startTimestamp + duration, {
|
|
@@ -392,7 +279,7 @@ function _trackNavigator(span, spanStreamingEnabled) {
|
|
|
392
279
|
if (utils.isMeasurementValue(connection.rtt)) {
|
|
393
280
|
if (spanStreamingEnabled) {
|
|
394
281
|
span.setAttribute("network.connection.rtt", connection.rtt);
|
|
395
|
-
} else if (core.spanToJSON(span).
|
|
282
|
+
} else if (core.spanToJSON(span).attributes[attributes.SENTRY_OP] === "pageload") {
|
|
396
283
|
core.setMeasurement("connection.rtt", connection.rtt, "millisecond");
|
|
397
284
|
}
|
|
398
285
|
}
|
|
@@ -412,31 +299,6 @@ function _trackNavigator(span, spanStreamingEnabled) {
|
|
|
412
299
|
}
|
|
413
300
|
}
|
|
414
301
|
}
|
|
415
|
-
function _setWebVitalAttributes(span, options) {
|
|
416
|
-
if (_lcpEntry && options.recordLcpOnPageloadSpan) {
|
|
417
|
-
if (_lcpEntry.element) {
|
|
418
|
-
span.setAttribute("lcp.element", htmlTreeAsString.htmlTreeAsString(_lcpEntry.element));
|
|
419
|
-
}
|
|
420
|
-
if (_lcpEntry.id) {
|
|
421
|
-
span.setAttribute("lcp.id", _lcpEntry.id);
|
|
422
|
-
}
|
|
423
|
-
if (_lcpEntry.url) {
|
|
424
|
-
span.setAttribute("lcp.url", _lcpEntry.url.trim().slice(0, 200));
|
|
425
|
-
}
|
|
426
|
-
if (_lcpEntry.loadTime != null) {
|
|
427
|
-
span.setAttribute("lcp.loadTime", _lcpEntry.loadTime);
|
|
428
|
-
}
|
|
429
|
-
if (_lcpEntry.renderTime != null) {
|
|
430
|
-
span.setAttribute("lcp.renderTime", _lcpEntry.renderTime);
|
|
431
|
-
}
|
|
432
|
-
span.setAttribute("lcp.size", _lcpEntry.size);
|
|
433
|
-
}
|
|
434
|
-
if (_clsEntry?.sources && options.recordClsOnPageloadSpan) {
|
|
435
|
-
_clsEntry.sources.forEach(
|
|
436
|
-
(source, index) => span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString.htmlTreeAsString(source.node))
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
302
|
function _setResourceRequestAttributes(entry, attributes, properties) {
|
|
441
303
|
properties.forEach(([entryKey, attributeKey]) => {
|
|
442
304
|
const entryVal = entry[entryKey];
|
|
@@ -445,27 +307,12 @@ function _setResourceRequestAttributes(entry, attributes, properties) {
|
|
|
445
307
|
}
|
|
446
308
|
});
|
|
447
309
|
}
|
|
448
|
-
function _addTtfbRequestTimeToMeasurements(_measurements2) {
|
|
449
|
-
const navEntry = getNavigationEntry.getNavigationEntry(false);
|
|
450
|
-
if (!navEntry) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
const { responseStart, requestStart } = navEntry;
|
|
454
|
-
if (requestStart <= responseStart) {
|
|
455
|
-
_measurements2["ttfb.requestTime"] = {
|
|
456
|
-
value: responseStart - requestStart,
|
|
457
|
-
unit: "millisecond"
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
310
|
|
|
462
311
|
exports._addNavigationSpans = _addNavigationSpans;
|
|
463
312
|
exports._addResourceSpans = _addResourceSpans;
|
|
464
313
|
exports._setResourceRequestAttributes = _setResourceRequestAttributes;
|
|
465
314
|
exports.addPerformanceEntries = addPerformanceEntries;
|
|
466
|
-
exports.addWebVitalsToSpan = addWebVitalsToSpan;
|
|
467
315
|
exports.startTrackingInteractions = startTrackingInteractions;
|
|
468
316
|
exports.startTrackingLongAnimationFrames = startTrackingLongAnimationFrames;
|
|
469
317
|
exports.startTrackingLongTasks = startTrackingLongTasks;
|
|
470
|
-
|
|
471
|
-
//# sourceMappingURL=browserMetrics.js.map
|
|
318
|
+
//# sourceMappingURL=entries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entries.js","sources":["../../../src/performance/entries.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Span, SpanAttributes, StartSpanOptions } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n getActiveSpan,\n getComponentName,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setMeasurement,\n spanToJSON,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { SENTRY_OP, URL_FULL } from '@sentry/conventions/attributes';\nimport { BROWSER_BROWSER_PAINT_SPAN_OP } from '@sentry/conventions/op';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport {\n addPerformanceInstrumentationHandler,\n type PerformanceLongAnimationFrameTiming,\n} from '../instrumentation/performanceObserver';\nimport { WINDOW } from '../types';\nimport { resourceTimingToSpanAttributes } from './resourceTiming';\nimport { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';\n\ninterface NavigatorNetworkInformation {\n readonly connection?: NetworkInformation;\n}\n\n// http://wicg.github.io/netinfo/#connection-types\ntype ConnectionType = 'bluetooth' | 'cellular' | 'ethernet' | 'mixed' | 'none' | 'other' | 'unknown' | 'wifi' | 'wimax';\n\n// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum\ntype EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';\n\n// http://wicg.github.io/netinfo/#dom-megabit\ntype Megabit = number;\n// http://wicg.github.io/netinfo/#dom-millisecond\ntype Millisecond = number;\n\n// http://wicg.github.io/netinfo/#networkinformation-interface\ninterface NetworkInformation extends EventTarget {\n // http://wicg.github.io/netinfo/#type-attribute\n readonly type?: ConnectionType;\n // http://wicg.github.io/netinfo/#effectivetype-attribute\n readonly effectiveType?: EffectiveConnectionType;\n // http://wicg.github.io/netinfo/#downlinkmax-attribute\n readonly downlinkMax?: Megabit;\n // http://wicg.github.io/netinfo/#downlink-attribute\n readonly downlink?: Megabit;\n // http://wicg.github.io/netinfo/#rtt-attribute\n readonly rtt?: Millisecond;\n // http://wicg.github.io/netinfo/#savedata-attribute\n readonly saveData?: boolean;\n // http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection\n onchange?: EventListener;\n}\n\n// https://w3c.github.io/device-memory/#sec-device-memory-js-api\ninterface NavigatorDeviceMemory {\n readonly deviceMemory?: number;\n}\n\nconst MAX_INT_AS_BYTES = 2147483647;\n\nlet _performanceCursor: number = 0;\n\n/**\n * Start tracking long tasks.\n */\nexport function startTrackingLongTasks(): void {\n addPerformanceInstrumentationHandler('longtask', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n\n const { attributes: parentAttributes, start_timestamp: parentStartTimestamp } = spanToJSON(parent);\n\n for (const entry of entries) {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n if (parentAttributes[SENTRY_OP] === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding a span if the long task started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long_task',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n });\n}\n\n/**\n * Start tracking long animation frames.\n */\nexport function startTrackingLongAnimationFrames(): void {\n // NOTE: the current web-vitals version (3.5.2) does not support long-animation-frame, so\n // we directly observe `long-animation-frame` events instead of through the web-vitals\n // `observe` helper function.\n const observer = new PerformanceObserver(list => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of list.getEntries() as PerformanceLongAnimationFrameTiming[]) {\n if (!entry.scripts[0]) {\n continue;\n }\n\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n\n const {\n start_timestamp: parentStartTimestamp,\n attributes: { [SENTRY_OP]: parentOp },\n } = spanToJSON(parent);\n\n if (parentOp === 'navigation' && parentStartTimestamp && startTime < parentStartTimestamp) {\n // Skip adding the span if the long animation frame started before the navigation started.\n // `startAndEndSpan` will otherwise adjust the parent's start time to the span's start\n // time, potentially skewing the duration of the actual navigation as reported via our\n // routing instrumentations\n continue;\n }\n const duration = msToSec(entry.duration);\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n };\n\n const initialScript = entry.scripts[0];\n const { invoker, invokerType, sourceURL, sourceFunctionName, sourceCharPosition } = initialScript;\n attributes['browser.script.invoker'] = invoker;\n attributes['browser.script.invoker_type'] = invokerType;\n if (sourceURL) {\n attributes['code.filepath'] = sourceURL;\n }\n if (sourceFunctionName) {\n attributes['code.function'] = sourceFunctionName;\n }\n if (sourceCharPosition !== -1) {\n attributes['browser.script.source_char_position'] = sourceCharPosition;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, {\n name: 'Main UI thread blocked',\n op: 'ui.long_animation_frame',\n attributes,\n });\n }\n });\n\n observer.observe({ type: 'long-animation-frame', buffered: true });\n}\n\n/**\n * Start tracking interaction events.\n */\nexport function startTrackingInteractions(): void {\n addPerformanceInstrumentationHandler('event', ({ entries }) => {\n const parent = getActiveSpan();\n if (!parent) {\n return;\n }\n for (const entry of entries) {\n if (entry.name === 'click') {\n const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime);\n const duration = msToSec(entry.duration);\n\n const spanOptions: StartSpanOptions & Required<Pick<StartSpanOptions, 'attributes'>> = {\n name: htmlTreeAsString(entry.target),\n op: `ui.interaction.${entry.name}`,\n startTime: startTime,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n };\n\n const componentName = getComponentName(entry.target);\n if (componentName) {\n spanOptions.attributes['ui.component_name'] = componentName;\n }\n\n startAndEndSpan(parent, startTime, startTime + duration, spanOptions);\n }\n }\n });\n}\n\ninterface AddPerformanceEntriesOptions {\n /**\n * Resource spans with `op`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignoreResourceSpans: Array<'resource.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>;\n\n /**\n * Whether span streaming is enabled.\n */\n spanStreamingEnabled?: boolean;\n}\n\n/** Add performance related spans to a transaction */\nexport function addPerformanceEntries(span: Span, options: AddPerformanceEntriesOptions): void {\n const performance = getBrowserPerformanceAPI();\n const origin = browserPerformanceTimeOrigin();\n if (!performance?.getEntries || !origin) {\n // Gatekeeper if performance API not available\n return;\n }\n\n const { spanStreamingEnabled, ignoreResourceSpans } = options;\n\n const timeOrigin = msToSec(origin);\n\n const performanceEntries = performance.getEntries();\n\n const { attributes, start_timestamp: transactionStartTime } = spanToJSON(span);\n\n performanceEntries.slice(_performanceCursor).forEach(entry => {\n const startTime = msToSec(entry.startTime);\n const duration = msToSec(\n // Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.\n // There is a SO post attempting to explain this, but it leaves one with open questions: https://stackoverflow.com/questions/23191918/peformance-getentries-and-negative-duration-display\n // The way we clamp the value is probably not accurate, since we have observed this happen for things that may take a while to load, like for example the replay worker.\n // TODO: Investigate why this happens and how to properly mitigate. For now, this is a workaround to prevent transactions being dropped due to negative duration spans.\n Math.max(0, entry.duration),\n );\n\n if (\n attributes[SENTRY_OP] === 'navigation' &&\n transactionStartTime &&\n timeOrigin + startTime < transactionStartTime\n ) {\n return;\n }\n\n switch (entry.entryType) {\n case 'navigation': {\n _addNavigationSpans(span, entry as PerformanceNavigationTiming, timeOrigin);\n break;\n }\n case 'paint': {\n _addPaintSpan(span, entry, startTime, duration, timeOrigin);\n break;\n }\n case 'resource': {\n _addResourceSpans(\n span,\n entry as PerformanceResourceTiming,\n entry.name,\n startTime,\n duration,\n timeOrigin,\n ignoreResourceSpans,\n );\n break;\n }\n // Ignore other entry types.\n }\n });\n\n _performanceCursor = Math.max(performanceEntries.length - 1, 0);\n\n _trackNavigator(span, spanStreamingEnabled);\n}\n\n/** Create a span for a browser paint performance entry. */\nfunction _addPaintSpan(\n span: Span,\n entry: PerformanceEntry,\n startTime: number,\n duration: number,\n timeOrigin: number,\n): void {\n const startTimestamp = timeOrigin + startTime;\n\n startAndEndSpan(span, startTimestamp, startTimestamp + duration, {\n name: entry.name,\n attributes: {\n [SENTRY_OP]: BROWSER_BROWSER_PAINT_SPAN_OP,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n },\n });\n}\n\n/**\n * Instrument navigation entries\n * exported only for tests\n */\nexport function _addNavigationSpans(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n _addPerformanceNavigationTiming(span, entry, 'unloadEvent', timeOrigin, 'unload_event');\n _addPerformanceNavigationTiming(span, entry, 'redirect', timeOrigin, 'redirect');\n _addPerformanceNavigationTiming(span, entry, 'domContentLoadedEvent', timeOrigin, 'dom_content_loaded_event');\n _addPerformanceNavigationTiming(span, entry, 'loadEvent', timeOrigin, 'load_event');\n _addPerformanceNavigationTiming(span, entry, 'connect', timeOrigin, 'connect');\n _addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin, 'tls_ssl');\n _addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin, 'cache');\n _addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin, 'dns');\n\n _addRequest(span, entry, timeOrigin);\n}\n\ntype StartEventName =\n | 'secureConnection'\n | 'fetch'\n | 'domainLookup'\n | 'unloadEvent'\n | 'redirect'\n | 'connect'\n | 'domContentLoadedEvent'\n | 'loadEvent';\n\ntype EndEventName =\n | 'domainLookupStart'\n | 'domainLookupEnd'\n | 'unloadEventEnd'\n | 'redirectEnd'\n | 'connectEnd'\n | 'domContentLoadedEventEnd'\n | 'loadEventEnd';\n\n/** Create performance navigation related spans */\nfunction _addPerformanceNavigationTiming(\n span: Span,\n entry: PerformanceNavigationTiming,\n event: StartEventName,\n timeOrigin: number,\n name: string = event,\n): void {\n const eventEnd = _getEndPropertyNameForNavigationTiming(event) satisfies keyof PerformanceNavigationTiming;\n const end = entry[eventEnd];\n const start = entry[`${event}Start`];\n if (!start || !end) {\n return;\n }\n startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {\n op: `browser.${name}`,\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n ...(event === 'redirect' && entry.redirectCount != null ? { 'http.redirect_count': entry.redirectCount } : {}),\n },\n });\n}\n\nfunction _getEndPropertyNameForNavigationTiming(event: StartEventName): EndEventName {\n if (event === 'secureConnection') {\n return 'connectEnd';\n }\n if (event === 'fetch') {\n return 'domainLookupStart';\n }\n return `${event}End`;\n}\n\n/** Create request and response related spans */\nfunction _addRequest(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {\n const requestStartTimestamp = timeOrigin + msToSec(entry.requestStart);\n const responseEndTimestamp = timeOrigin + msToSec(entry.responseEnd);\n const responseStartTimestamp = timeOrigin + msToSec(entry.responseStart);\n if (entry.responseEnd) {\n // It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in.\n // In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0.\n // In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect\n // these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.\n startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {\n op: 'browser.request',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n\n startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {\n op: 'browser.response',\n name: entry.name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',\n },\n });\n }\n}\n\n/**\n * Create resource-related spans.\n * Exported only for tests.\n */\nexport function _addResourceSpans(\n span: Span,\n entry: PerformanceResourceTiming,\n resourceUrl: string,\n startTime: number,\n duration: number,\n timeOrigin: number,\n ignoredResourceSpanOps?: Array<string>,\n): void {\n // we already instrument based on fetch and xhr, so we don't need to\n // duplicate spans here.\n if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {\n return;\n }\n\n const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other';\n if (ignoredResourceSpanOps?.includes(op)) {\n return;\n }\n\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',\n };\n\n const parsedUrl = parseUrl(resourceUrl);\n\n if (parsedUrl.protocol) {\n attributes['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.\n }\n\n if (parsedUrl.host) {\n attributes['server.address'] = parsedUrl.host;\n }\n\n attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);\n\n attributes[URL_FULL] = filterCollectedUrl(resourceUrl);\n\n _setResourceRequestAttributes(entry, attributes, [\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n ['responseStatus', 'http.response.status_code'],\n\n ['transferSize', 'http.response_transfer_size'],\n ['encodedBodySize', 'http.response_content_length'],\n ['decodedBodySize', 'http.decoded_response_content_length'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/renderBlockingStatus\n ['renderBlockingStatus', 'resource.render_blocking_status'],\n\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/deliveryType\n ['deliveryType', 'http.response_delivery_type'],\n ]);\n\n const attributesWithResourceTiming: SpanAttributes = { ...attributes, ...resourceTimingToSpanAttributes(entry) };\n\n const startTimestamp = timeOrigin + startTime;\n const endTimestamp = startTimestamp + duration;\n\n startAndEndSpan(span, startTimestamp, endTimestamp, {\n name: resourceUrl.replace(WINDOW.location.origin, ''),\n op,\n attributes: attributesWithResourceTiming,\n });\n}\n\n/**\n * Capture the information of the user agent.\n * TODO v11: Remove non-span-streaming attributes and measurements once we removed transactions\n */\nfunction _trackNavigator(span: Span, spanStreamingEnabled: boolean | undefined): void {\n const navigator = WINDOW.navigator as null | (Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory);\n if (!navigator) {\n return;\n }\n\n // track network connectivity\n const connection = navigator.connection;\n if (connection) {\n if (connection.effectiveType) {\n span.setAttribute(\n spanStreamingEnabled ? 'network.connection.effective_type' : 'effectiveConnectionType',\n connection.effectiveType,\n );\n }\n\n if (connection.type) {\n span.setAttribute(spanStreamingEnabled ? 'network.connection.type' : 'connectionType', connection.type);\n }\n\n if (isMeasurementValue(connection.rtt)) {\n if (spanStreamingEnabled) {\n span.setAttribute('network.connection.rtt', connection.rtt);\n } else if (spanToJSON(span).attributes[SENTRY_OP] === 'pageload') {\n // Measurements are only recorded on the pageload span, matching the historical\n // behavior where `connection.rtt` was only flushed for pageload transactions.\n setMeasurement('connection.rtt', connection.rtt, 'millisecond');\n }\n }\n }\n\n if (isMeasurementValue(navigator.deviceMemory)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.memory.estimated_capacity', navigator.deviceMemory);\n } else {\n span.setAttribute('deviceMemory', `${navigator.deviceMemory} GB`);\n }\n }\n\n if (isMeasurementValue(navigator.hardwareConcurrency)) {\n if (spanStreamingEnabled) {\n span.setAttribute('device.processor_count', navigator.hardwareConcurrency);\n } else {\n span.setAttribute('hardwareConcurrency', String(navigator.hardwareConcurrency));\n }\n }\n}\n\ntype ExperimentalResourceTimingProperty =\n | 'renderBlockingStatus'\n | 'deliveryType'\n // For some reason, TS during build, errors on `responseStatus` not being a property of\n // PerformanceResourceTiming while it actually is. Hence, we're adding it here.\n // Perhaps because response status is not yet available in Webkit/Safari.\n // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus\n | 'responseStatus';\n\n/**\n * Use this to set any attributes we can take directly form the PerformanceResourceTiming entry.\n *\n * This is just a mapping function for entry->attribute to keep bundle-size minimal.\n * Experimental properties are also accepted (see {@link ExperimentalResourceTimingProperty}).\n * Assumes that all entry properties might be undefined for browser-specific differences.\n * Only accepts string and number values for now and also sets 0-values.\n */\nexport function _setResourceRequestAttributes(\n entry: Partial<PerformanceResourceTiming> & Partial<Record<ExperimentalResourceTimingProperty, number | string>>,\n attributes: SpanAttributes,\n properties: [keyof PerformanceResourceTiming | ExperimentalResourceTimingProperty, string][],\n): void {\n properties.forEach(([entryKey, attributeKey]) => {\n const entryVal = entry[entryKey];\n if (\n entryVal != null &&\n ((typeof entryVal === 'number' && entryVal < MAX_INT_AS_BYTES) || typeof entryVal === 'string')\n ) {\n attributes[attributeKey] = entryVal;\n }\n });\n}\n"],"names":["addPerformanceInstrumentationHandler","getActiveSpan","spanToJSON","msToSec","browserPerformanceTimeOrigin","SENTRY_OP","startAndEndSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","attributes","htmlTreeAsString","getComponentName","getBrowserPerformanceAPI","BROWSER_BROWSER_PAINT_SPAN_OP","parseUrl","WINDOW","URL_FULL","filterCollectedUrl","resourceTimingToSpanAttributes","isMeasurementValue","setMeasurement"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceTiming.js","sources":["../../../src/performance/resourceTiming.ts"],"sourcesContent":["import type { SpanAttributes } from '@sentry/core';\nimport { browserPerformanceTimeOrigin } from '@sentry/core';\nimport { extractNetworkProtocol, getBrowserPerformanceAPI } from './utils';\n\nfunction getAbsoluteTime(time: number | undefined): number | undefined {\n // falsy values should be preserved so that we can later on drop undefined values and\n // preserve 0 vals for cross-origin resources without proper `Timing-Allow-Origin` header.\n return time ? ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000 : time;\n}\n\n/**\n * Converts a PerformanceResourceTiming entry to span data for the resource span. Most importantly,\n * it converts the timing values from timestamps relative to the `performance.timeOrigin` to absolute timestamps\n * in seconds.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#timestamps\n *\n * @param resourceTiming\n * @returns An array where the first element is the attribute name and the second element is the attribute value.\n */\nexport function resourceTimingToSpanAttributes(resourceTiming: PerformanceResourceTiming): SpanAttributes {\n const timingSpanData: SpanAttributes = {};\n // Checking for only `undefined` and `null` is intentional because it's\n // valid for `nextHopProtocol` to be an empty string.\n if (resourceTiming.nextHopProtocol != undefined) {\n const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol);\n timingSpanData['network.protocol.version'] = version;\n timingSpanData['network.protocol.name'] = name;\n }\n\n if (!(browserPerformanceTimeOrigin() || getBrowserPerformanceAPI()?.timeOrigin)) {\n return timingSpanData;\n }\n\n return dropUndefinedKeysFromObject({\n ...timingSpanData,\n\n 'http.request.redirect_start': getAbsoluteTime(resourceTiming.redirectStart),\n 'http.request.redirect_end': getAbsoluteTime(resourceTiming.redirectEnd),\n\n 'http.request.worker_start': getAbsoluteTime(resourceTiming.workerStart),\n\n 'http.request.fetch_start': getAbsoluteTime(resourceTiming.fetchStart),\n\n 'http.request.domain_lookup_start': getAbsoluteTime(resourceTiming.domainLookupStart),\n 'http.request.domain_lookup_end': getAbsoluteTime(resourceTiming.domainLookupEnd),\n\n 'http.request.connect_start': getAbsoluteTime(resourceTiming.connectStart),\n 'http.request.secure_connection_start': getAbsoluteTime(resourceTiming.secureConnectionStart),\n 'http.request.connection_end': getAbsoluteTime(resourceTiming.connectEnd),\n\n 'http.request.request_start': getAbsoluteTime(resourceTiming.requestStart),\n\n 'http.request.response_start': getAbsoluteTime(resourceTiming.responseStart),\n 'http.request.response_end': getAbsoluteTime(resourceTiming.responseEnd),\n\n // For TTFB we actually want the relative time from timeOrigin to responseStart\n // This way, TTFB always measures the \"first page load\" experience.\n // see: https://web.dev/articles/ttfb#measure-resource-requests\n 'http.request.time_to_first_byte':\n resourceTiming.responseStart != null ? resourceTiming.responseStart / 1000 : undefined,\n });\n}\n\n/**\n * Remove properties with `undefined` as value from an object.\n * In contrast to `dropUndefinedKeys` in core this funciton only works on first-level\n * key-value objects and does not recursively go into object properties or arrays.\n */\nfunction dropUndefinedKeysFromObject<T extends object>(attrs: T): Partial<T> {\n return Object.fromEntries(Object.entries(attrs).filter(([, value]) => value != null)) as Partial<T>;\n}\n"],"names":["browserPerformanceTimeOrigin","extractNetworkProtocol","getBrowserPerformanceAPI"],"mappings":";;;;;AAIA,SAAS,gBAAgB,IAAA,EAA8C;AAGrE,EAAA,OAAO,SAASA,iCAAA,EAA6B,IAAK,WAAA,CAAY,UAAA,IAAc,QAAQ,GAAA,GAAO,IAAA;AAC7F;AAYO,SAAS,+BAA+B,cAAA,EAA2D;AACxG,EAAA,MAAM,iBAAiC,EAAC;AAGxC,EAAA,IAAI,cAAA,CAAe,mBAAmB,MAAA,EAAW;AAC/C,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAIC,4BAAA,CAAuB,eAAe,eAAe,CAAA;AAC/E,IAAA,cAAA,CAAe,0BAA0B,CAAA,GAAI,OAAA;AAC7C,IAAA,cAAA,CAAe,uBAAuB,CAAA,GAAI,IAAA;AAAA,EAC5C;AAEA,EAAA,IAAI,EAAED,iCAAA,EAA6B,IAAKE,8BAAA,IAA4B,UAAA,CAAA,EAAa;AAC/E,IAAA,OAAO,cAAA;AAAA,EACT;AAEA,EAAA,OAAO,2BAAA,CAA4B;AAAA,IACjC,GAAG,cAAA;AAAA,IAEH,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,aAAa,CAAA;AAAA,IAC3E,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA,IAEvE,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA,IAEvE,0BAAA,EAA4B,eAAA,CAAgB,cAAA,CAAe,UAAU,CAAA;AAAA,IAErE,kCAAA,EAAoC,eAAA,CAAgB,cAAA,CAAe,iBAAiB,CAAA;AAAA,IACpF,gCAAA,EAAkC,eAAA,CAAgB,cAAA,CAAe,eAAe,CAAA;AAAA,IAEhF,4BAAA,EAA8B,eAAA,CAAgB,cAAA,CAAe,YAAY,CAAA;AAAA,IACzE,sCAAA,EAAwC,eAAA,CAAgB,cAAA,CAAe,qBAAqB,CAAA;AAAA,IAC5F,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,UAAU,CAAA;AAAA,IAExE,4BAAA,EAA8B,eAAA,CAAgB,cAAA,CAAe,YAAY,CAAA;AAAA,IAEzE,6BAAA,EAA+B,eAAA,CAAgB,cAAA,CAAe,aAAa,CAAA;AAAA,IAC3E,2BAAA,EAA6B,eAAA,CAAgB,cAAA,CAAe,WAAW,CAAA;AAAA;AAAA;AAAA;AAAA,IAKvE,mCACE,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,cAAA,CAAe,gBAAgB,GAAA,GAAO;AAAA,GAChF,CAAA;AACH;AAOA,SAAS,4BAA8C,KAAA,EAAsB;AAC3E,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,MAAA,CAAO,CAAC,GAAG,KAAK,CAAA,KAAM,KAAA,IAAS,IAAI,CAAC,CAAA;AACtF;;;;"}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const attributes = require('@sentry/conventions/attributes');
|
|
4
4
|
const core = require('@sentry/core');
|
|
5
5
|
const utils = require('./utils.js');
|
|
6
|
-
const
|
|
6
|
+
const utils$1 = require('../web-vitals/utils.js');
|
|
7
7
|
|
|
8
8
|
const INTEGRATION_NAME = "UserTiming";
|
|
9
9
|
const _userTimingIntegration = ((options = {}) => {
|
|
@@ -18,11 +18,12 @@ const _userTimingIntegration = ((options = {}) => {
|
|
|
18
18
|
const timeOriginInSeconds = utils.msToSec(timeOrigin);
|
|
19
19
|
let performanceCursor = 0;
|
|
20
20
|
client.on("beforeIdleSpanEnd", (idleSpan) => {
|
|
21
|
-
const {
|
|
21
|
+
const { attributes: attributes$1, start_timestamp: parentStartTimestamp } = core.spanToJSON(idleSpan);
|
|
22
|
+
const parentOp = attributes$1[attributes.SENTRY_OP];
|
|
22
23
|
if (parentOp !== "pageload" && parentOp !== "navigation") {
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
const requestTime = utils.msToSec(
|
|
26
|
+
const requestTime = utils.msToSec(utils$1.getNavigationEntry(false)?.requestStart ?? 0);
|
|
26
27
|
const performanceEntries = performance.getEntries();
|
|
27
28
|
for (const entry of performanceEntries.slice(performanceCursor)) {
|
|
28
29
|
if (entry.entryType !== "mark" && entry.entryType !== "measure") {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userTiming.js","sources":["../../../src/performance/userTiming.ts"],"sourcesContent":["import { SENTRY_OP, SENTRY_ORIGIN } from '@sentry/conventions/attributes';\nimport type { IntegrationFn, Span, SpanAttributes, SpanAttributeValue } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n defineIntegration,\n isPrimitive,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core';\nimport { getBrowserPerformanceAPI, msToSec, startAndEndSpan } from './utils';\nimport { getNavigationEntry } from '../web-vitals/utils';\n\ninterface UserTimingOptions {\n /**\n * User Timing entries with names matching any of these strings or regular expressions will not be emitted.\n *\n * Default: []\n */\n ignore?: Array<string | RegExp>;\n}\n\nconst INTEGRATION_NAME = 'UserTiming';\n\nconst _userTimingIntegration = ((options: UserTimingOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const performance = getBrowserPerformanceAPI();\n const timeOrigin = browserPerformanceTimeOrigin();\n if (!performance?.getEntries || !timeOrigin) {\n return;\n }\n const timeOriginInSeconds = msToSec(timeOrigin);\n let performanceCursor = 0;\n\n client.on('beforeIdleSpanEnd', idleSpan => {\n const { attributes, start_timestamp: parentStartTimestamp } = spanToJSON(idleSpan);\n const parentOp = attributes[SENTRY_OP];\n\n if (parentOp !== 'pageload' && parentOp !== 'navigation') {\n return;\n }\n\n const requestTime = msToSec(getNavigationEntry(false)?.requestStart ?? 0);\n const performanceEntries = performance.getEntries();\n\n for (const entry of performanceEntries.slice(performanceCursor)) {\n if (entry.entryType !== 'mark' && entry.entryType !== 'measure') {\n continue;\n }\n\n const startTime = msToSec(entry.startTime);\n const absoluteStartTime = timeOriginInSeconds + startTime;\n\n if (parentOp === 'navigation' && parentStartTimestamp && absoluteStartTime < parentStartTimestamp) {\n continue;\n }\n\n _addUserTimingSpan(\n idleSpan,\n entry,\n startTime,\n msToSec(Math.max(0, entry.duration)),\n timeOriginInSeconds,\n requestTime,\n options.ignore ?? [],\n );\n }\n\n performanceCursor = performanceEntries.length;\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures spans created with the browser's User Timing APIs, `performance.mark` and `performance.measure`.\n *\n * The integration must be explicitly added to `Sentry.init`. Entries are attached to the active pageload or\n * navigation span when it ends.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [\n * Sentry.browserTracingIntegration(),\n * Sentry.userTimingIntegration({\n * ignore: ['third-party-mark', /framework-measure/],\n * }),\n * ],\n * });\n * ```\n */\nexport const userTimingIntegration = defineIntegration(_userTimingIntegration);\n\n/**\n * Creates a span for a browser User Timing entry.\n * Exported only for tests.\n */\nexport function _addUserTimingSpan(\n parentSpan: Span,\n entry: PerformanceEntry,\n startTime: number,\n duration: number,\n timeOrigin: number,\n requestTime: number,\n ignore: Array<string | RegExp>,\n): void {\n if (isReact19MeasureEntry(entry) || stringMatchesSomePattern(entry.name, ignore)) {\n return;\n }\n\n // Measures can reference arbitrary timestamps, including timestamps before the page request started.\n const spanStartTimestamp = timeOrigin + Math.max(startTime, requestTime);\n const originalStartTimestamp = timeOrigin + startTime;\n const spanEndTimestamp = originalStartTimestamp + duration;\n\n const attributes: SpanAttributes = {\n [SENTRY_ORIGIN]: `auto.browser.user_timing.${entry.entryType}`,\n };\n\n if (spanStartTimestamp !== originalStartTimestamp) {\n attributes['sentry.browser.measure_happened_before_request'] = true;\n attributes['sentry.browser.measure_start_time'] = spanStartTimestamp;\n }\n\n addDetailToSpanAttributes(attributes, entry as PerformanceMeasure);\n\n // Third-party measurements can contain timestamps which would produce invalid spans.\n if (spanStartTimestamp <= spanEndTimestamp) {\n startAndEndSpan(parentSpan, spanStartTimestamp, spanEndTimestamp, {\n name: entry.name,\n op: entry.entryType,\n attributes,\n });\n }\n}\n\n/**\n * React 19.2+ creates performance.measure entries for component renders.\n * We can identify them by the `detail.devtools.track` property being set to 'Components ⚛'.\n * See https://react.dev/reference/dev-tools/react-performance-tracks.\n */\nfunction isReact19MeasureEntry(entry: PerformanceEntry): boolean | void {\n if (entry.entryType !== 'measure') {\n return;\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return (entry as PerformanceMeasure).detail.devtools.track === 'Components ⚛';\n } catch {\n return;\n }\n}\n\nfunction addDetailToSpanAttributes(attributes: SpanAttributes, entry: PerformanceMeasure): void {\n try {\n // Accessing detail can throw in some browsers due to security restrictions.\n const detail = entry.detail;\n if (!detail) {\n return;\n }\n\n if (typeof detail === 'object') {\n for (const [key, value] of Object.entries(detail)) {\n if (value && isPrimitive(value)) {\n attributes[`sentry.browser.measure.detail.${key}`] = value as SpanAttributeValue;\n } else if (value !== undefined) {\n try {\n attributes[`sentry.browser.measure.detail.${key}`] = JSON.stringify(value);\n } catch {\n // User-provided detail values are not guaranteed to be serializable.\n }\n }\n }\n return;\n }\n\n if (isPrimitive(detail)) {\n attributes['sentry.browser.measure.detail'] = detail as SpanAttributeValue;\n return;\n }\n\n try {\n attributes['sentry.browser.measure.detail'] = JSON.stringify(detail);\n } catch {\n // User-provided detail values are not guaranteed to be serializable.\n }\n } catch {\n // Accessing detail can throw in some browsers due to security restrictions.\n }\n}\n"],"names":["getBrowserPerformanceAPI","browserPerformanceTimeOrigin","msToSec","attributes","spanToJSON","SENTRY_OP","getNavigationEntry","defineIntegration","stringMatchesSomePattern","SENTRY_ORIGIN","startAndEndSpan","isPrimitive"],"mappings":"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"}
|
|
@@ -2,13 +2,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
const types = require('../types.js');
|
|
5
|
-
const onHidden = require('./web-vitals/lib/onHidden.js');
|
|
6
5
|
|
|
7
6
|
function isMeasurementValue(value) {
|
|
8
7
|
return typeof value === "number" && isFinite(value);
|
|
9
8
|
}
|
|
10
9
|
function startAndEndSpan(parentSpan, startTimeInSeconds, endTime, { ...ctx }) {
|
|
11
|
-
const parentStartTime = core.
|
|
10
|
+
const parentStartTime = core.spanToStaticSpanJSON(parentSpan).start_timestamp;
|
|
12
11
|
if (parentStartTime && parentStartTime > startTimeInSeconds) {
|
|
13
12
|
if (typeof parentSpan.updateStartTime === "function") {
|
|
14
13
|
parentSpan.updateStartTime(startTimeInSeconds);
|
|
@@ -59,35 +58,10 @@ function supportsWebVital(entryType) {
|
|
|
59
58
|
return false;
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
|
-
function listenForWebVitalReportEvents(client, collectorCallback) {
|
|
63
|
-
let pageloadSpan;
|
|
64
|
-
let collected = false;
|
|
65
|
-
function _runCollectorCallbackOnce(event) {
|
|
66
|
-
if (!collected && pageloadSpan) {
|
|
67
|
-
collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
|
|
68
|
-
}
|
|
69
|
-
collected = true;
|
|
70
|
-
}
|
|
71
|
-
onHidden.onHidden(() => {
|
|
72
|
-
_runCollectorCallbackOnce("pagehide");
|
|
73
|
-
});
|
|
74
|
-
const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
|
|
75
|
-
if (!options?.isRedirect) {
|
|
76
|
-
_runCollectorCallbackOnce("navigation");
|
|
77
|
-
unsubscribeStartNavigation();
|
|
78
|
-
unsubscribeAfterStartPageLoadSpan();
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
|
|
82
|
-
pageloadSpan = span;
|
|
83
|
-
unsubscribeAfterStartPageLoadSpan();
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
61
|
|
|
87
62
|
exports.extractNetworkProtocol = extractNetworkProtocol;
|
|
88
63
|
exports.getBrowserPerformanceAPI = getBrowserPerformanceAPI;
|
|
89
64
|
exports.isMeasurementValue = isMeasurementValue;
|
|
90
|
-
exports.listenForWebVitalReportEvents = listenForWebVitalReportEvents;
|
|
91
65
|
exports.msToSec = msToSec;
|
|
92
66
|
exports.startAndEndSpan = startAndEndSpan;
|
|
93
67
|
exports.supportsWebVital = supportsWebVital;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/performance/utils.ts"],"sourcesContent":["import type { SentrySpan, Span, SpanTimeInput, StartSpanOptions } from '@sentry/core';\nimport { spanToStaticSpanJSON, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport { WINDOW } from '../types';\n\n/**\n * Checks if a given value is a valid measurement value.\n */\nexport function isMeasurementValue(value: unknown): value is number {\n return typeof value === 'number' && isFinite(value);\n}\n\n/**\n * Helper function to start child on transactions. This function will make sure that the transaction will\n * use the start timestamp of the created child span if it is earlier than the transactions actual\n * start timestamp.\n */\nexport function startAndEndSpan(\n parentSpan: Span,\n startTimeInSeconds: number,\n endTime: SpanTimeInput,\n { ...ctx }: StartSpanOptions,\n): Span | undefined {\n const parentStartTime = spanToStaticSpanJSON(parentSpan).start_timestamp;\n if (parentStartTime && parentStartTime > startTimeInSeconds) {\n // We can only do this for SentrySpans...\n if (typeof (parentSpan as Partial<SentrySpan>).updateStartTime === 'function') {\n (parentSpan as SentrySpan).updateStartTime(startTimeInSeconds);\n }\n }\n\n // The return value only exists for tests\n return withActiveSpan(parentSpan, () => {\n const span = startInactiveSpan({\n startTime: startTimeInSeconds,\n ...ctx,\n });\n\n if (span) {\n span.end(endTime);\n }\n\n return span;\n });\n}\n\n/** Get the browser performance API. */\nexport function getBrowserPerformanceAPI(): Performance | undefined {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n return WINDOW.addEventListener && WINDOW.performance;\n}\n\n/**\n * Converts from milliseconds to seconds\n * @param time time in ms\n */\nexport function msToSec(time: number): number {\n return time / 1000;\n}\n\n/**\n * Converts ALPN protocol ids to name and version.\n *\n * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)\n * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol\n */\nexport function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } {\n let name = 'unknown';\n let version = 'unknown';\n let _name = '';\n for (const char of nextHopProtocol) {\n // http/1.1 etc.\n if (char === '/') {\n [name, version] = nextHopProtocol.split('/') as [string, string];\n break;\n }\n // h2, h3 etc.\n if (!isNaN(Number(char))) {\n name = _name === 'h' ? 'http' : _name;\n version = nextHopProtocol.split(_name)[1] as string;\n break;\n }\n _name += char;\n }\n if (_name === nextHopProtocol) {\n // webrtc, ftp, etc.\n name = _name;\n }\n return { name, version };\n}\n\n/**\n * Generic support check for web vitals\n */\nexport function supportsWebVital(entryType: 'layout-shift' | 'largest-contentful-paint'): boolean {\n try {\n return PerformanceObserver.supportedEntryTypes.includes(entryType);\n } catch {\n return false;\n }\n}\n"],"names":["spanToStaticSpanJSON","withActiveSpan","startInactiveSpan","WINDOW"],"mappings":";;;;;AAOO,SAAS,mBAAmB,KAAA,EAAiC;AAClE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,QAAA,CAAS,KAAK,CAAA;AACpD;AAOO,SAAS,gBACd,UAAA,EACA,kBAAA,EACA,SACA,EAAE,GAAG,KAAI,EACS;AAClB,EAAA,MAAM,eAAA,GAAkBA,yBAAA,CAAqB,UAAU,CAAA,CAAE,eAAA;AACzD,EAAA,IAAI,eAAA,IAAmB,kBAAkB,kBAAA,EAAoB;AAE3D,IAAA,IAAI,OAAQ,UAAA,CAAmC,eAAA,KAAoB,UAAA,EAAY;AAC7E,MAAC,UAAA,CAA0B,gBAAgB,kBAAkB,CAAA;AAAA,IAC/D;AAAA,EACF;AAGA,EAAA,OAAOC,mBAAA,CAAe,YAAY,MAAM;AACtC,IAAA,MAAM,OAAOC,sBAAA,CAAkB;AAAA,MAC7B,SAAA,EAAW,kBAAA;AAAA,MACX,GAAG;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,IAClB;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH;AAGO,SAAS,wBAAA,GAAoD;AAElE,EAAA,OAAOC,YAAA,CAAO,oBAAoBA,YAAA,CAAO,WAAA;AAC3C;AAMO,SAAS,QAAQ,IAAA,EAAsB;AAC5C,EAAA,OAAO,IAAA,GAAO,GAAA;AAChB;AAQO,SAAS,uBAAuB,eAAA,EAA4D;AACjG,EAAA,IAAI,IAAA,GAAO,SAAA;AACX,EAAA,IAAI,OAAA,GAAU,SAAA;AACd,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAElC,IAAA,IAAI,SAAS,GAAA,EAAK;AAChB,MAAA,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,eAAA,CAAgB,MAAM,GAAG,CAAA;AAC3C,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,IAAI,CAAC,CAAA,EAAG;AACxB,MAAA,IAAA,GAAO,KAAA,KAAU,MAAM,MAAA,GAAS,KAAA;AAChC,MAAA,OAAA,GAAU,eAAA,CAAgB,KAAA,CAAM,KAAK,CAAA,CAAE,CAAC,CAAA;AACxC,MAAA;AAAA,IACF;AACA,IAAA,KAAA,IAAS,IAAA;AAAA,EACX;AACA,EAAA,IAAI,UAAU,eAAA,EAAiB;AAE7B,IAAA,IAAA,GAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AACzB;AAKO,SAAS,iBAAiB,SAAA,EAAiE;AAChG,EAAA,IAAI;AACF,IAAA,OAAO,mBAAA,CAAoB,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA;AAAA,EACnE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;;;;;;;"}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
const htmlTreeAsString = require('../htmlTreeAsString.js');
|
|
5
5
|
const types = require('../types.js');
|
|
6
|
-
const
|
|
6
|
+
const performanceObserver = require('../instrumentation/performanceObserver.js');
|
|
7
7
|
|
|
8
8
|
const LAST_INTERACTIONS = [];
|
|
9
9
|
const INTERACTIONS_SPAN_MAP = /* @__PURE__ */ new Map();
|
|
@@ -80,7 +80,7 @@ function registerInpInteractionListener() {
|
|
|
80
80
|
const activeSpan = core.getActiveSpan();
|
|
81
81
|
const activeRootSpan = activeSpan && core.getRootSpan(activeSpan);
|
|
82
82
|
entries.forEach((entry) => {
|
|
83
|
-
if (!
|
|
83
|
+
if (!performanceObserver.isPerformanceEventTiming(entry)) {
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
const interactionId = entry.interactionId;
|
|
@@ -102,8 +102,8 @@ function registerInpInteractionListener() {
|
|
|
102
102
|
});
|
|
103
103
|
});
|
|
104
104
|
};
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
performanceObserver.addPerformanceInstrumentationHandler("event", handleEntries);
|
|
106
|
+
performanceObserver.addPerformanceInstrumentationHandler("first-input", handleEntries);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
exports.INP_ENTRY_MAP = INP_ENTRY_MAP;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inp.js","sources":["../../../src/web-vitals/inp.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, getRootSpan, isBrowser } from '@sentry/core';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { WINDOW } from '../types';\nimport { addPerformanceInstrumentationHandler, isPerformanceEventTiming } from '../instrumentation/performanceObserver';\n\ninterface InteractionContext {\n span: Span | undefined;\n elementName: string;\n}\n\nconst LAST_INTERACTIONS: number[] = [];\nconst INTERACTIONS_SPAN_MAP = new Map<number, InteractionContext>();\n\n// Map to store element names by timestamp, since we get the DOM event before the PerformanceObserver entry\nconst ELEMENT_NAME_TIMESTAMP_MAP = new Map<number, string>();\n\n/**\n * 60 seconds is the maximum for a plausible INP value\n * (source: Me)\n */\nexport const MAX_PLAUSIBLE_INP_DURATION = 60;\n\nexport const INP_ENTRY_MAP: Record<string, 'click' | 'hover' | 'drag' | 'press'> = {\n click: 'click',\n pointerdown: 'click',\n pointerup: 'click',\n mousedown: 'click',\n mouseup: 'click',\n touchstart: 'click',\n touchend: 'click',\n mouseover: 'hover',\n mouseout: 'hover',\n mouseenter: 'hover',\n mouseleave: 'hover',\n pointerover: 'hover',\n pointerout: 'hover',\n pointerenter: 'hover',\n pointerleave: 'hover',\n dragstart: 'drag',\n dragend: 'drag',\n drag: 'drag',\n dragenter: 'drag',\n dragleave: 'drag',\n dragover: 'drag',\n drop: 'drag',\n keydown: 'press',\n keyup: 'press',\n keypress: 'press',\n input: 'press',\n};\n\n/**\n * Look up a cached interaction context (element name + root span) by interactionId.\n * Returns undefined if no context was cached for this interaction.\n */\nexport function getCachedInteractionContext(interactionId: number | undefined): InteractionContext | undefined {\n return interactionId != null ? INTERACTIONS_SPAN_MAP.get(interactionId) : undefined;\n}\n\n/**\n * Register a listener to cache route information for INP interactions.\n */\nexport function registerInpInteractionListener(): void {\n // Listen for all interaction events that could contribute to INP\n const interactionEvents = Object.keys(INP_ENTRY_MAP);\n if (isBrowser()) {\n interactionEvents.forEach(eventType => {\n WINDOW.addEventListener(eventType, captureElementFromEvent, { capture: true, passive: true });\n });\n }\n\n /**\n * Captures the element name from a DOM event and stores it in the ELEMENT_NAME_TIMESTAMP_MAP.\n */\n function captureElementFromEvent(event: Event): void {\n const target = event.target as HTMLElement | null;\n if (!target) {\n return;\n }\n\n const elementName = htmlTreeAsString(target);\n const timestamp = Math.round(event.timeStamp);\n\n // Store the element name by timestamp so we can match it with the PerformanceEntry\n ELEMENT_NAME_TIMESTAMP_MAP.set(timestamp, elementName);\n\n // Clean up old\n if (ELEMENT_NAME_TIMESTAMP_MAP.size > 50) {\n const firstKey = ELEMENT_NAME_TIMESTAMP_MAP.keys().next().value;\n if (firstKey !== undefined) {\n ELEMENT_NAME_TIMESTAMP_MAP.delete(firstKey);\n }\n }\n }\n\n /**\n * Tries to get the element name from the timestamp map.\n */\n function resolveElementNameFromEntry(entry: PerformanceEntry): string {\n const timestamp = Math.round(entry.startTime);\n let elementName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp);\n\n // try nearby timestamps (±5ms)\n if (!elementName) {\n for (let offset = -5; offset <= 5; offset++) {\n const nearbyName = ELEMENT_NAME_TIMESTAMP_MAP.get(timestamp + offset);\n if (nearbyName) {\n elementName = nearbyName;\n break;\n }\n }\n }\n\n return elementName || '<unknown>';\n }\n\n const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan && getRootSpan(activeSpan);\n\n entries.forEach(entry => {\n if (!isPerformanceEventTiming(entry)) {\n return;\n }\n\n const interactionId = entry.interactionId;\n if (interactionId == null) {\n return;\n }\n\n // If the interaction was already recorded before, nothing more to do\n if (INTERACTIONS_SPAN_MAP.has(interactionId)) {\n return;\n }\n\n const elementName = entry.target ? htmlTreeAsString(entry.target) : resolveElementNameFromEntry(entry);\n\n // We keep max. 10 interactions in the list, then remove the oldest one & clean up\n if (LAST_INTERACTIONS.length > 10) {\n const last = LAST_INTERACTIONS.shift() as number;\n INTERACTIONS_SPAN_MAP.delete(last);\n }\n\n // We add the interaction to the list of recorded interactions\n // and store both the span and element name for this interaction\n LAST_INTERACTIONS.push(interactionId);\n INTERACTIONS_SPAN_MAP.set(interactionId, {\n span: activeRootSpan,\n elementName,\n });\n });\n };\n\n addPerformanceInstrumentationHandler('event', handleEntries);\n addPerformanceInstrumentationHandler('first-input', handleEntries);\n}\n"],"names":["isBrowser","WINDOW","htmlTreeAsString","getActiveSpan","getRootSpan","isPerformanceEventTiming","addPerformanceInstrumentationHandler"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lcp.js","sources":["../../../src/web-vitals/lcp.ts"],"sourcesContent":["/**\n * 60 seconds is the maximum for a plausible LCP value.\n */\nexport const MAX_PLAUSIBLE_LCP_DURATION = 60_000;\n\nexport function isValidLcpMetric(lcpValue: number | undefined): lcpValue is number {\n return lcpValue != null && lcpValue > 0 && lcpValue <= MAX_PLAUSIBLE_LCP_DURATION;\n}\n"],"names":[],"mappings":";;AAGO,MAAM,0BAAA,GAA6B;AAEnC,SAAS,iBAAiB,QAAA,EAAkD;AACjF,EAAA,OAAO,QAAA,IAAY,IAAA,IAAQ,QAAA,GAAW,CAAA,IAAK,QAAA,IAAY,0BAAA;AACzD;;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const utils = require('./utils.js');
|
|
4
|
+
|
|
5
|
+
function listenForWebVitalReportEvents(client, collectorCallback) {
|
|
6
|
+
let pageloadSpan;
|
|
7
|
+
let collected = false;
|
|
8
|
+
function _runCollectorCallbackOnce(event) {
|
|
9
|
+
if (!collected && pageloadSpan) {
|
|
10
|
+
collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
|
|
11
|
+
}
|
|
12
|
+
collected = true;
|
|
13
|
+
}
|
|
14
|
+
utils.onHidden(() => {
|
|
15
|
+
_runCollectorCallbackOnce("pagehide");
|
|
16
|
+
});
|
|
17
|
+
const unsubscribeStartNavigation = client.on("beforeStartNavigationSpan", (_, options) => {
|
|
18
|
+
if (!options?.isRedirect) {
|
|
19
|
+
_runCollectorCallbackOnce("navigation");
|
|
20
|
+
unsubscribeStartNavigation();
|
|
21
|
+
unsubscribeAfterStartPageLoadSpan();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const unsubscribeAfterStartPageLoadSpan = client.on("afterStartPageLoadSpan", (span) => {
|
|
25
|
+
pageloadSpan = span;
|
|
26
|
+
unsubscribeAfterStartPageLoadSpan();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.listenForWebVitalReportEvents = listenForWebVitalReportEvents;
|
|
31
|
+
//# sourceMappingURL=reportEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reportEvents.js","sources":["../../../src/web-vitals/reportEvents.ts"],"sourcesContent":["import type { Client, Span } from '@sentry/core';\nimport { onHidden } from './utils';\n\nexport type WebVitalReportEvent = 'pagehide' | 'navigation';\n\n/**\n * Listens for events on which we want to collect a previously accumulated web vital value.\n * Currently, this includes:\n *\n * - pagehide (i.e. user minimizes browser window, hides tab, etc)\n * - soft navigation (we only care about the vital of the initially loaded route)\n *\n * As a \"side-effect\", this function will also collect the span id of the pageload span.\n *\n * @param collectorCallback the callback to be called when the first of these events is triggered. Parameters:\n * - event: the event that triggered the reporting of the web vital value.\n * - pageloadSpanId: the span id of the pageload span. This is used to link the web vital span to the pageload span.\n * - pageloadSpan: the pageload span instance. This is used for full access to the pageload span for span streaming.\n */\nexport function listenForWebVitalReportEvents(\n client: Client,\n collectorCallback: (event: WebVitalReportEvent, pageloadSpanId: string, pageloadSpan?: Span) => void,\n) {\n let pageloadSpan: Span | undefined;\n\n let collected = false;\n function _runCollectorCallbackOnce(event: WebVitalReportEvent) {\n if (!collected && pageloadSpan) {\n collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);\n }\n collected = true;\n }\n\n onHidden(() => {\n _runCollectorCallbackOnce('pagehide');\n });\n\n const unsubscribeStartNavigation = client.on('beforeStartNavigationSpan', (_, options) => {\n // we only want to collect LCP if we actually navigate. Redirects should be ignored.\n if (!options?.isRedirect) {\n _runCollectorCallbackOnce('navigation');\n unsubscribeStartNavigation();\n unsubscribeAfterStartPageLoadSpan();\n }\n });\n\n const unsubscribeAfterStartPageLoadSpan = client.on('afterStartPageLoadSpan', span => {\n pageloadSpan = span;\n unsubscribeAfterStartPageLoadSpan();\n });\n}\n"],"names":["onHidden"],"mappings":";;;;AAmBO,SAAS,6BAAA,CACd,QACA,iBAAA,EACA;AACA,EAAA,IAAI,YAAA;AAEJ,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,SAAS,0BAA0B,KAAA,EAA4B;AAC7D,IAAA,IAAI,CAAC,aAAa,YAAA,EAAc;AAC9B,MAAA,iBAAA,CAAkB,KAAA,EAAO,YAAA,CAAa,WAAA,EAAY,CAAE,QAAQ,YAAY,CAAA;AAAA,IAC1E;AACA,IAAA,SAAA,GAAY,IAAA;AAAA,EACd;AAEA,EAAAA,cAAA,CAAS,MAAM;AACb,IAAA,yBAAA,CAA0B,UAAU,CAAA;AAAA,EACtC,CAAC,CAAA;AAED,EAAA,MAAM,6BAA6B,MAAA,CAAO,EAAA,CAAG,2BAAA,EAA6B,CAAC,GAAG,OAAA,KAAY;AAExF,IAAA,IAAI,CAAC,SAAS,UAAA,EAAY;AACxB,MAAA,yBAAA,CAA0B,YAAY,CAAA;AACtC,MAAA,0BAAA,EAA2B;AAC3B,MAAA,iCAAA,EAAkC;AAAA,IACpC;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAM,iCAAA,GAAoC,MAAA,CAAO,EAAA,CAAG,wBAAA,EAA0B,CAAA,IAAA,KAAQ;AACpF,IAAA,YAAA,GAAe,IAAA;AACf,IAAA,iCAAA,EAAkC;AAAA,EACpC,CAAC,CAAA;AACH;;;;"}
|