@sentry/browser-utils 11.0.0-alpha.0 → 11.0.0-alpha.2
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/component-name.js +28 -0
- package/build/cjs/component-name.js.map +1 -0
- package/build/cjs/getLocationHref.js +14 -0
- package/build/cjs/getLocationHref.js.map +1 -0
- package/build/cjs/index.js +36 -28
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrumentation/dom.js.map +1 -0
- package/build/cjs/{instrument → instrumentation}/history.js +5 -1
- 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/isBotUserAgent.js +15 -0
- package/build/cjs/isBotUserAgent.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} +45 -220
- package/build/cjs/performance/entries.js.map +1 -0
- package/build/cjs/performance/interactions.js +123 -0
- package/build/cjs/performance/interactions.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 +4 -30
- package/build/cjs/performance/utils.js.map +1 -0
- package/build/cjs/types.js.map +1 -1
- 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} +30 -21
- 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/component-name.js +26 -0
- package/build/esm/component-name.js.map +1 -0
- package/build/esm/getLocationHref.js +12 -0
- package/build/esm/getLocationHref.js.map +1 -0
- package/build/esm/index.js +18 -13
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrumentation/dom.js.map +1 -0
- package/build/esm/{instrument → instrumentation}/history.js +5 -2
- 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/isBotUserAgent.js +13 -0
- package/build/esm/isBotUserAgent.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} +41 -213
- package/build/esm/performance/entries.js.map +1 -0
- package/build/esm/performance/interactions.js +121 -0
- package/build/esm/performance/interactions.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/types.js.map +1 -1
- 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} +25 -16
- 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/component-name.d.ts +9 -0
- package/build/types/component-name.d.ts.map +1 -0
- package/build/types/getLocationHref.d.ts +5 -0
- package/build/types/getLocationHref.d.ts.map +1 -0
- package/build/types/index.d.ts +18 -13
- package/build/types/index.d.ts.map +1 -1
- package/build/types/{instrument → instrumentation}/dom.d.ts +1 -1
- package/build/types/instrumentation/dom.d.ts.map +1 -0
- package/build/types/{instrument → instrumentation}/history.d.ts +8 -1
- 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/{instrument → instrumentation}/xhr.d.ts +1 -1
- package/build/types/instrumentation/xhr.d.ts.map +1 -0
- package/build/types/isBotUserAgent.d.ts +5 -0
- package/build/types/isBotUserAgent.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} +4 -51
- package/build/types/performance/entries.d.ts.map +1 -0
- package/build/types/performance/interactions.d.ts +48 -0
- package/build/types/performance/interactions.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/types.d.ts +38 -1
- package/build/types/types.d.ts.map +1 -1
- package/build/types/{metrics → web-vitals}/inp.d.ts +2 -1
- 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 +5 -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}/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}/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}/location.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}/lcp.d.ts +0 -0
|
@@ -1,54 +1,29 @@
|
|
|
1
|
-
import { browserPerformanceTimeOrigin, spanToJSON,
|
|
2
|
-
import {
|
|
1
|
+
import { browserPerformanceTimeOrigin, spanToJSON, getActiveSpan, parseUrl, filterCollectedUrl, RESOURCE_SPAN_NAME_FALLBACK, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, setMeasurement } from '@sentry/core';
|
|
2
|
+
import { SENTRY_OP, CODE_FILE_PATH, CODE_FUNCTION_NAME, NETWORK_CONNECTION_EFFECTIVE_TYPE, NETWORK_CONNECTION_TYPE, NETWORK_CONNECTION_RTT, URL_SCHEME, SERVER_ADDRESS, URL_DOMAIN, HTTP_REQUEST_SAME_ORIGIN, URL_FULL, HTTP_RESPONSE_STATUS_CODE, HTTP_RESPONSE_SIZE, HTTP_RESPONSE_BODY_SIZE } from '@sentry/conventions/attributes';
|
|
3
|
+
import { UI_LONG_ANIMATION_FRAME, BROWSER_PAINT, UI_LONG_TASK } from '@sentry/conventions/op';
|
|
4
|
+
import { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver.js';
|
|
3
5
|
import { WINDOW } from '../types.js';
|
|
4
|
-
import { addPerformanceInstrumentationHandler, addLcpInstrumentationHandler, addClsInstrumentationHandler, addTtfbInstrumentationHandler } from './instrument.js';
|
|
5
|
-
import { isValidLcpMetric } from './lcp.js';
|
|
6
6
|
import { resourceTimingToSpanAttributes } from './resourceTiming.js';
|
|
7
7
|
import { getBrowserPerformanceAPI, msToSec, startAndEndSpan, isMeasurementValue } from './utils.js';
|
|
8
|
-
import { getActivationStart } from './web-vitals/lib/getActivationStart.js';
|
|
9
|
-
import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry.js';
|
|
10
|
-
import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher.js';
|
|
11
|
-
import { DEBUG_BUILD } from '../debug-build.js';
|
|
12
|
-
import { URL_FULL, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
13
|
-
import { BROWSER_BROWSER_PAINT_SPAN_OP } from '@sentry/conventions/op';
|
|
14
8
|
|
|
15
9
|
const MAX_INT_AS_BYTES = 2147483647;
|
|
16
10
|
let _performanceCursor = 0;
|
|
17
|
-
let _measurements = {};
|
|
18
|
-
let _lcpEntry;
|
|
19
|
-
let _clsEntry;
|
|
20
|
-
function startTrackingWebVitals({ trackCls, trackLcp }) {
|
|
21
|
-
const performance = getBrowserPerformanceAPI();
|
|
22
|
-
if (performance && browserPerformanceTimeOrigin()) {
|
|
23
|
-
const lcpCleanupCallback = trackLcp ? _trackLCP() : void 0;
|
|
24
|
-
const clsCleanupCallback = trackCls ? _trackCLS() : void 0;
|
|
25
|
-
const ttfbCleanupCallback = _trackTtfb();
|
|
26
|
-
const fpFcpCleanupCallback = _trackFpFcp();
|
|
27
|
-
return () => {
|
|
28
|
-
ttfbCleanupCallback();
|
|
29
|
-
fpFcpCleanupCallback();
|
|
30
|
-
lcpCleanupCallback?.();
|
|
31
|
-
clsCleanupCallback?.();
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
return () => void 0;
|
|
35
|
-
}
|
|
36
11
|
function startTrackingLongTasks() {
|
|
37
12
|
addPerformanceInstrumentationHandler("longtask", ({ entries }) => {
|
|
38
13
|
const parent = getActiveSpan();
|
|
39
14
|
if (!parent) {
|
|
40
15
|
return;
|
|
41
16
|
}
|
|
42
|
-
const {
|
|
17
|
+
const { attributes: parentAttributes, start_timestamp: parentStartTimestamp } = spanToJSON(parent);
|
|
43
18
|
for (const entry of entries) {
|
|
44
19
|
const startTime = msToSec(browserPerformanceTimeOrigin() + entry.startTime);
|
|
45
20
|
const duration = msToSec(entry.duration);
|
|
46
|
-
if (
|
|
21
|
+
if (parentAttributes[SENTRY_OP] === "navigation" && parentStartTimestamp && startTime < parentStartTimestamp) {
|
|
47
22
|
continue;
|
|
48
23
|
}
|
|
49
24
|
startAndEndSpan(parent, startTime, startTime + duration, {
|
|
50
25
|
name: "Main UI thread blocked",
|
|
51
|
-
op:
|
|
26
|
+
op: UI_LONG_TASK,
|
|
52
27
|
attributes: {
|
|
53
28
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.browser.metrics"
|
|
54
29
|
}
|
|
@@ -67,7 +42,10 @@ function startTrackingLongAnimationFrames() {
|
|
|
67
42
|
continue;
|
|
68
43
|
}
|
|
69
44
|
const startTime = msToSec(browserPerformanceTimeOrigin() + entry.startTime);
|
|
70
|
-
const {
|
|
45
|
+
const {
|
|
46
|
+
start_timestamp: parentStartTimestamp,
|
|
47
|
+
attributes: { [SENTRY_OP]: parentOp }
|
|
48
|
+
} = spanToJSON(parent);
|
|
71
49
|
if (parentOp === "navigation" && parentStartTimestamp && startTime < parentStartTimestamp) {
|
|
72
50
|
continue;
|
|
73
51
|
}
|
|
@@ -80,93 +58,23 @@ function startTrackingLongAnimationFrames() {
|
|
|
80
58
|
attributes["browser.script.invoker"] = invoker;
|
|
81
59
|
attributes["browser.script.invoker_type"] = invokerType;
|
|
82
60
|
if (sourceURL) {
|
|
83
|
-
attributes[
|
|
61
|
+
attributes[CODE_FILE_PATH] = sourceURL;
|
|
84
62
|
}
|
|
85
63
|
if (sourceFunctionName) {
|
|
86
|
-
attributes[
|
|
64
|
+
attributes[CODE_FUNCTION_NAME] = sourceFunctionName;
|
|
87
65
|
}
|
|
88
66
|
if (sourceCharPosition !== -1) {
|
|
89
67
|
attributes["browser.script.source_char_position"] = sourceCharPosition;
|
|
90
68
|
}
|
|
91
69
|
startAndEndSpan(parent, startTime, startTime + duration, {
|
|
92
70
|
name: "Main UI thread blocked",
|
|
93
|
-
op:
|
|
71
|
+
op: UI_LONG_ANIMATION_FRAME,
|
|
94
72
|
attributes
|
|
95
73
|
});
|
|
96
74
|
}
|
|
97
75
|
});
|
|
98
76
|
observer.observe({ type: "long-animation-frame", buffered: true });
|
|
99
77
|
}
|
|
100
|
-
function startTrackingInteractions() {
|
|
101
|
-
addPerformanceInstrumentationHandler("event", ({ entries }) => {
|
|
102
|
-
const parent = getActiveSpan();
|
|
103
|
-
if (!parent) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
for (const entry of entries) {
|
|
107
|
-
if (entry.name === "click") {
|
|
108
|
-
const startTime = msToSec(browserPerformanceTimeOrigin() + entry.startTime);
|
|
109
|
-
const duration = msToSec(entry.duration);
|
|
110
|
-
const spanOptions = {
|
|
111
|
-
name: htmlTreeAsString(entry.target),
|
|
112
|
-
op: `ui.interaction.${entry.name}`,
|
|
113
|
-
startTime,
|
|
114
|
-
attributes: {
|
|
115
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.browser.metrics"
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
const componentName = getComponentName(entry.target);
|
|
119
|
-
if (componentName) {
|
|
120
|
-
spanOptions.attributes["ui.component_name"] = componentName;
|
|
121
|
-
}
|
|
122
|
-
startAndEndSpan(parent, startTime, startTime + duration, spanOptions);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function _trackCLS() {
|
|
128
|
-
return addClsInstrumentationHandler(({ metric }) => {
|
|
129
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
130
|
-
if (!entry) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
_measurements["cls"] = { value: metric.value, unit: "" };
|
|
134
|
-
_clsEntry = entry;
|
|
135
|
-
}, true);
|
|
136
|
-
}
|
|
137
|
-
function _trackLCP() {
|
|
138
|
-
return addLcpInstrumentationHandler(({ metric }) => {
|
|
139
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
140
|
-
if (!entry || !isValidLcpMetric(metric.value)) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
_measurements["lcp"] = { value: metric.value, unit: "millisecond" };
|
|
144
|
-
_lcpEntry = entry;
|
|
145
|
-
}, true);
|
|
146
|
-
}
|
|
147
|
-
function _trackTtfb() {
|
|
148
|
-
return addTtfbInstrumentationHandler(({ metric }) => {
|
|
149
|
-
const entry = metric.entries[metric.entries.length - 1];
|
|
150
|
-
if (!entry) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
_measurements["ttfb"] = { value: metric.value, unit: "millisecond" };
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function _trackFpFcp() {
|
|
157
|
-
return addPerformanceInstrumentationHandler("paint", ({ entries }) => {
|
|
158
|
-
const firstHidden = getVisibilityWatcher();
|
|
159
|
-
for (const entry of entries) {
|
|
160
|
-
const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;
|
|
161
|
-
if (entry.name === "first-paint" && shouldRecord) {
|
|
162
|
-
_measurements["fp"] = { value: entry.startTime, unit: "millisecond" };
|
|
163
|
-
}
|
|
164
|
-
if (entry.name === "first-contentful-paint" && shouldRecord) {
|
|
165
|
-
_measurements["fcp"] = { value: entry.startTime, unit: "millisecond" };
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
78
|
function addPerformanceEntries(span, options) {
|
|
171
79
|
const performance = getBrowserPerformanceAPI();
|
|
172
80
|
const origin = browserPerformanceTimeOrigin();
|
|
@@ -176,7 +84,7 @@ function addPerformanceEntries(span, options) {
|
|
|
176
84
|
const { spanStreamingEnabled, ignoreResourceSpans } = options;
|
|
177
85
|
const timeOrigin = msToSec(origin);
|
|
178
86
|
const performanceEntries = performance.getEntries();
|
|
179
|
-
const {
|
|
87
|
+
const { attributes, start_timestamp: transactionStartTime } = spanToJSON(span);
|
|
180
88
|
performanceEntries.slice(_performanceCursor).forEach((entry) => {
|
|
181
89
|
const startTime = msToSec(entry.startTime);
|
|
182
90
|
const duration = msToSec(
|
|
@@ -186,7 +94,7 @@ function addPerformanceEntries(span, options) {
|
|
|
186
94
|
// 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.
|
|
187
95
|
Math.max(0, entry.duration)
|
|
188
96
|
);
|
|
189
|
-
if (
|
|
97
|
+
if (attributes[SENTRY_OP] === "navigation" && transactionStartTime && timeOrigin + startTime < transactionStartTime) {
|
|
190
98
|
return;
|
|
191
99
|
}
|
|
192
100
|
switch (entry.entryType) {
|
|
@@ -206,7 +114,8 @@ function addPerformanceEntries(span, options) {
|
|
|
206
114
|
startTime,
|
|
207
115
|
duration,
|
|
208
116
|
timeOrigin,
|
|
209
|
-
ignoreResourceSpans
|
|
117
|
+
ignoreResourceSpans,
|
|
118
|
+
spanStreamingEnabled
|
|
210
119
|
);
|
|
211
120
|
break;
|
|
212
121
|
}
|
|
@@ -215,61 +124,12 @@ function addPerformanceEntries(span, options) {
|
|
|
215
124
|
_performanceCursor = Math.max(performanceEntries.length - 1, 0);
|
|
216
125
|
_trackNavigator(span, spanStreamingEnabled);
|
|
217
126
|
}
|
|
218
|
-
function addWebVitalsToSpan(span, options) {
|
|
219
|
-
const origin = browserPerformanceTimeOrigin();
|
|
220
|
-
if (!getBrowserPerformanceAPI()?.getEntries || !origin) {
|
|
221
|
-
resetWebVitalState();
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
const { spanStreamingEnabled, recordClsOnPageloadSpan, recordLcpOnPageloadSpan } = options;
|
|
225
|
-
const timeOrigin = msToSec(origin);
|
|
226
|
-
if (spanToJSON(span).op === "pageload") {
|
|
227
|
-
_addTtfbRequestTimeToMeasurements(_measurements);
|
|
228
|
-
if (spanStreamingEnabled) {
|
|
229
|
-
const setAttr = (shortWebVitalName, value, customAttrName) => {
|
|
230
|
-
const attrKey = customAttrName ?? `browser.web_vital.${shortWebVitalName}.value`;
|
|
231
|
-
span.setAttribute(attrKey, value);
|
|
232
|
-
DEBUG_BUILD && debug.log("Setting web vital attribute", { [attrKey]: value }, "on pageload span");
|
|
233
|
-
};
|
|
234
|
-
["ttfb", "fp", "fcp"].forEach((measurementName) => {
|
|
235
|
-
if (_measurements[measurementName]) {
|
|
236
|
-
setAttr(measurementName, _measurements[measurementName].value);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
if (_measurements["ttfb.requestTime"]) {
|
|
240
|
-
setAttr("ttfb.requestTime", _measurements["ttfb.requestTime"].value, "browser.web_vital.ttfb.request_time");
|
|
241
|
-
}
|
|
242
|
-
} else {
|
|
243
|
-
if (!recordClsOnPageloadSpan) {
|
|
244
|
-
delete _measurements.cls;
|
|
245
|
-
}
|
|
246
|
-
if (!recordLcpOnPageloadSpan) {
|
|
247
|
-
delete _measurements.lcp;
|
|
248
|
-
}
|
|
249
|
-
Object.entries(_measurements).forEach(([measurementName, measurement]) => {
|
|
250
|
-
setMeasurement(measurementName, measurement.value, measurement.unit, span);
|
|
251
|
-
});
|
|
252
|
-
_setWebVitalAttributes(span, options);
|
|
253
|
-
}
|
|
254
|
-
span.setAttribute(spanStreamingEnabled ? "browser.performance.time_origin" : "performance.timeOrigin", timeOrigin);
|
|
255
|
-
span.setAttribute(
|
|
256
|
-
spanStreamingEnabled ? "browser.performance.navigation.activation_start" : "performance.activationStart",
|
|
257
|
-
getActivationStart()
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
resetWebVitalState();
|
|
261
|
-
}
|
|
262
|
-
function resetWebVitalState() {
|
|
263
|
-
_lcpEntry = void 0;
|
|
264
|
-
_clsEntry = void 0;
|
|
265
|
-
_measurements = {};
|
|
266
|
-
}
|
|
267
127
|
function _addPaintSpan(span, entry, startTime, duration, timeOrigin) {
|
|
268
128
|
const startTimestamp = timeOrigin + startTime;
|
|
269
129
|
startAndEndSpan(span, startTimestamp, startTimestamp + duration, {
|
|
270
130
|
name: entry.name,
|
|
271
131
|
attributes: {
|
|
272
|
-
[SENTRY_OP]:
|
|
132
|
+
[SENTRY_OP]: BROWSER_PAINT,
|
|
273
133
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.resource.browser.metrics"
|
|
274
134
|
}
|
|
275
135
|
});
|
|
@@ -331,7 +191,7 @@ function _addRequest(span, entry, timeOrigin) {
|
|
|
331
191
|
});
|
|
332
192
|
}
|
|
333
193
|
}
|
|
334
|
-
function _addResourceSpans(span, entry, resourceUrl, startTime, duration, timeOrigin, ignoredResourceSpanOps) {
|
|
194
|
+
function _addResourceSpans(span, entry, resourceUrl, startTime, duration, timeOrigin, ignoredResourceSpanOps, spanStreamingEnabled) {
|
|
335
195
|
if (entry.initiatorType === "xmlhttprequest" || entry.initiatorType === "fetch") {
|
|
336
196
|
return;
|
|
337
197
|
}
|
|
@@ -344,19 +204,24 @@ function _addResourceSpans(span, entry, resourceUrl, startTime, duration, timeOr
|
|
|
344
204
|
};
|
|
345
205
|
const parsedUrl = parseUrl(resourceUrl);
|
|
346
206
|
if (parsedUrl.protocol) {
|
|
347
|
-
attributes[
|
|
207
|
+
attributes[URL_SCHEME] = parsedUrl.protocol.split(":").pop();
|
|
208
|
+
}
|
|
209
|
+
const host = parsedUrl.host?.replace(/^.*@/, "");
|
|
210
|
+
if (host) {
|
|
211
|
+
attributes[SERVER_ADDRESS] = host;
|
|
348
212
|
}
|
|
349
|
-
|
|
350
|
-
|
|
213
|
+
const domain = host?.replace(/:\d+$/, "");
|
|
214
|
+
if (domain) {
|
|
215
|
+
attributes[URL_DOMAIN] = domain;
|
|
351
216
|
}
|
|
352
|
-
attributes[
|
|
217
|
+
attributes[HTTP_REQUEST_SAME_ORIGIN] = resourceUrl.includes(WINDOW.location.origin);
|
|
353
218
|
attributes[URL_FULL] = filterCollectedUrl(resourceUrl);
|
|
354
219
|
_setResourceRequestAttributes(entry, attributes, [
|
|
355
220
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus
|
|
356
|
-
["responseStatus",
|
|
357
|
-
["transferSize",
|
|
358
|
-
["encodedBodySize",
|
|
359
|
-
["decodedBodySize", "http.
|
|
221
|
+
["responseStatus", HTTP_RESPONSE_STATUS_CODE],
|
|
222
|
+
["transferSize", HTTP_RESPONSE_SIZE],
|
|
223
|
+
["encodedBodySize", HTTP_RESPONSE_BODY_SIZE],
|
|
224
|
+
["decodedBodySize", "http.response.body.decoded_size"],
|
|
360
225
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/renderBlockingStatus
|
|
361
226
|
["renderBlockingStatus", "resource.render_blocking_status"],
|
|
362
227
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/deliveryType
|
|
@@ -366,7 +231,8 @@ function _addResourceSpans(span, entry, resourceUrl, startTime, duration, timeOr
|
|
|
366
231
|
const startTimestamp = timeOrigin + startTime;
|
|
367
232
|
const endTimestamp = startTimestamp + duration;
|
|
368
233
|
startAndEndSpan(span, startTimestamp, endTimestamp, {
|
|
369
|
-
|
|
234
|
+
// With span streaming, span names have to be low cardinality, so we can't fall back to the URL.
|
|
235
|
+
name: spanStreamingEnabled ? domain || RESOURCE_SPAN_NAME_FALLBACK : resourceUrl.replace(WINDOW.location.origin, ""),
|
|
370
236
|
op,
|
|
371
237
|
attributes: attributesWithResourceTiming
|
|
372
238
|
});
|
|
@@ -380,17 +246,17 @@ function _trackNavigator(span, spanStreamingEnabled) {
|
|
|
380
246
|
if (connection) {
|
|
381
247
|
if (connection.effectiveType) {
|
|
382
248
|
span.setAttribute(
|
|
383
|
-
spanStreamingEnabled ?
|
|
249
|
+
spanStreamingEnabled ? NETWORK_CONNECTION_EFFECTIVE_TYPE : "effectiveConnectionType",
|
|
384
250
|
connection.effectiveType
|
|
385
251
|
);
|
|
386
252
|
}
|
|
387
253
|
if (connection.type) {
|
|
388
|
-
span.setAttribute(spanStreamingEnabled ?
|
|
254
|
+
span.setAttribute(spanStreamingEnabled ? NETWORK_CONNECTION_TYPE : "connectionType", connection.type);
|
|
389
255
|
}
|
|
390
256
|
if (isMeasurementValue(connection.rtt)) {
|
|
391
257
|
if (spanStreamingEnabled) {
|
|
392
|
-
span.setAttribute(
|
|
393
|
-
} else if (spanToJSON(span).
|
|
258
|
+
span.setAttribute(NETWORK_CONNECTION_RTT, connection.rtt);
|
|
259
|
+
} else if (spanToJSON(span).attributes[SENTRY_OP] === "pageload") {
|
|
394
260
|
setMeasurement("connection.rtt", connection.rtt, "millisecond");
|
|
395
261
|
}
|
|
396
262
|
}
|
|
@@ -410,31 +276,6 @@ function _trackNavigator(span, spanStreamingEnabled) {
|
|
|
410
276
|
}
|
|
411
277
|
}
|
|
412
278
|
}
|
|
413
|
-
function _setWebVitalAttributes(span, options) {
|
|
414
|
-
if (_lcpEntry && options.recordLcpOnPageloadSpan) {
|
|
415
|
-
if (_lcpEntry.element) {
|
|
416
|
-
span.setAttribute("lcp.element", htmlTreeAsString(_lcpEntry.element));
|
|
417
|
-
}
|
|
418
|
-
if (_lcpEntry.id) {
|
|
419
|
-
span.setAttribute("lcp.id", _lcpEntry.id);
|
|
420
|
-
}
|
|
421
|
-
if (_lcpEntry.url) {
|
|
422
|
-
span.setAttribute("lcp.url", _lcpEntry.url.trim().slice(0, 200));
|
|
423
|
-
}
|
|
424
|
-
if (_lcpEntry.loadTime != null) {
|
|
425
|
-
span.setAttribute("lcp.loadTime", _lcpEntry.loadTime);
|
|
426
|
-
}
|
|
427
|
-
if (_lcpEntry.renderTime != null) {
|
|
428
|
-
span.setAttribute("lcp.renderTime", _lcpEntry.renderTime);
|
|
429
|
-
}
|
|
430
|
-
span.setAttribute("lcp.size", _lcpEntry.size);
|
|
431
|
-
}
|
|
432
|
-
if (_clsEntry?.sources && options.recordClsOnPageloadSpan) {
|
|
433
|
-
_clsEntry.sources.forEach(
|
|
434
|
-
(source, index) => span.setAttribute(`cls.source.${index + 1}`, htmlTreeAsString(source.node))
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
279
|
function _setResourceRequestAttributes(entry, attributes, properties) {
|
|
439
280
|
properties.forEach(([entryKey, attributeKey]) => {
|
|
440
281
|
const entryVal = entry[entryKey];
|
|
@@ -443,19 +284,6 @@ function _setResourceRequestAttributes(entry, attributes, properties) {
|
|
|
443
284
|
}
|
|
444
285
|
});
|
|
445
286
|
}
|
|
446
|
-
function _addTtfbRequestTimeToMeasurements(_measurements2) {
|
|
447
|
-
const navEntry = getNavigationEntry(false);
|
|
448
|
-
if (!navEntry) {
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
const { responseStart, requestStart } = navEntry;
|
|
452
|
-
if (requestStart <= responseStart) {
|
|
453
|
-
_measurements2["ttfb.requestTime"] = {
|
|
454
|
-
value: responseStart - requestStart,
|
|
455
|
-
unit: "millisecond"
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
287
|
|
|
460
|
-
export { _addNavigationSpans, _addResourceSpans, _setResourceRequestAttributes, addPerformanceEntries,
|
|
461
|
-
//# sourceMappingURL=
|
|
288
|
+
export { _addNavigationSpans, _addResourceSpans, _setResourceRequestAttributes, addPerformanceEntries, startTrackingLongAnimationFrames, startTrackingLongTasks };
|
|
289
|
+
//# 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 } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n getActiveSpan,\n parseUrl,\n RESOURCE_SPAN_NAME_FALLBACK,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setMeasurement,\n spanToJSON,\n filterCollectedUrl,\n} from '@sentry/core';\nimport {\n CODE_FILE_PATH,\n CODE_FUNCTION_NAME,\n HTTP_REQUEST_SAME_ORIGIN,\n HTTP_RESPONSE_BODY_SIZE,\n HTTP_RESPONSE_SIZE,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_CONNECTION_EFFECTIVE_TYPE,\n NETWORK_CONNECTION_RTT,\n NETWORK_CONNECTION_TYPE,\n SENTRY_OP,\n SERVER_ADDRESS,\n URL_DOMAIN,\n URL_FULL,\n URL_SCHEME,\n} from '@sentry/conventions/attributes';\nimport { BROWSER_PAINT, UI_LONG_ANIMATION_FRAME, UI_LONG_TASK } from '@sentry/conventions/op';\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_FILE_PATH] = sourceURL;\n }\n if (sourceFunctionName) {\n attributes[CODE_FUNCTION_NAME] = 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\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 spanStreamingEnabled,\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_PAINT,\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 spanStreamingEnabled?: boolean,\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 // `host` is the URL authority, so it can carry userinfo, which doesn't belong on either attribute.\n const host = parsedUrl.host?.replace(/^.*@/, '');\n\n if (host) {\n attributes[SERVER_ADDRESS] = host;\n }\n\n // Unlike `server.address`, `url.domain` excludes the port.\n const domain = host?.replace(/:\\d+$/, '');\n\n if (domain) {\n attributes[URL_DOMAIN] = domain;\n }\n\n attributes[HTTP_REQUEST_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_SIZE],\n ['encodedBodySize', HTTP_RESPONSE_BODY_SIZE],\n ['decodedBodySize', 'http.response.body.decoded_size'],\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 // With span streaming, span names have to be low cardinality, so we can't fall back to the URL.\n name: spanStreamingEnabled\n ? domain || RESOURCE_SPAN_NAME_FALLBACK\n : 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":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { SENTRY_OP, SENTRY_SOURCE, SENTRY_SEGMENT_NAME_SOURCE, SENTRY_ORIGIN, SENTRY_IDLE_SPAN_FINISH_REASON, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';
|
|
2
|
+
import { UI_ACTION_CLICK, UI_INTERACTION_CLICK } from '@sentry/conventions/op';
|
|
3
|
+
import { defineIntegration, getRootSpan, spanToJSON, debug, getActiveSpan, browserPerformanceTimeOrigin } from '@sentry/core';
|
|
4
|
+
import { startIdleSpan } from '@sentry/core/browser';
|
|
5
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
6
|
+
import { htmlTreeAsString } from '../htmlTreeAsString.js';
|
|
7
|
+
import { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver.js';
|
|
8
|
+
import { isBotUserAgent } from '../isBotUserAgent.js';
|
|
9
|
+
import { WINDOW } from '../types.js';
|
|
10
|
+
import { msToSec, startAndEndSpan } from './utils.js';
|
|
11
|
+
import { getComponentName } from '../component-name.js';
|
|
12
|
+
|
|
13
|
+
const INTEGRATION_NAME = "Interactions";
|
|
14
|
+
const _interactionsIntegration = ((options = {}) => {
|
|
15
|
+
return {
|
|
16
|
+
name: INTEGRATION_NAME,
|
|
17
|
+
setup(client) {
|
|
18
|
+
if (isBotUserAgent()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const latestRoute = { name: void 0, source: void 0 };
|
|
22
|
+
let inflightRouteSpan;
|
|
23
|
+
function trackRoute(span) {
|
|
24
|
+
const { name, attributes } = spanToJSON(span);
|
|
25
|
+
latestRoute.name = name;
|
|
26
|
+
latestRoute.source = attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE];
|
|
27
|
+
}
|
|
28
|
+
client.on("spanStart", (span) => {
|
|
29
|
+
if (isRouteSpan(span)) {
|
|
30
|
+
inflightRouteSpan = span;
|
|
31
|
+
trackRoute(span);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
client.on("spanEnd", (span) => {
|
|
35
|
+
if (span !== inflightRouteSpan) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
inflightRouteSpan = void 0;
|
|
39
|
+
trackRoute(span);
|
|
40
|
+
});
|
|
41
|
+
registerInteractionListener(latestRoute, () => inflightRouteSpan, options);
|
|
42
|
+
trackInteractionsAsSpans();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
const interactionsIntegration = defineIntegration(_interactionsIntegration);
|
|
47
|
+
function isRouteSpan(span) {
|
|
48
|
+
if (getRootSpan(span) !== span) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const op = spanToJSON(span).attributes[SENTRY_OP];
|
|
52
|
+
return op === "pageload" || op === "navigation";
|
|
53
|
+
}
|
|
54
|
+
function registerInteractionListener(latestRoute, getInflightRouteSpan, idleSpanOptions) {
|
|
55
|
+
if (!WINDOW.document) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let inflightInteractionSpan;
|
|
59
|
+
addEventListener(
|
|
60
|
+
"click",
|
|
61
|
+
() => {
|
|
62
|
+
if (getInflightRouteSpan()) {
|
|
63
|
+
DEBUG_BUILD && debug.warn(
|
|
64
|
+
`[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`
|
|
65
|
+
);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (inflightInteractionSpan) {
|
|
69
|
+
inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, "interactionInterrupted");
|
|
70
|
+
inflightInteractionSpan.end();
|
|
71
|
+
inflightInteractionSpan = void 0;
|
|
72
|
+
}
|
|
73
|
+
if (!latestRoute.name) {
|
|
74
|
+
DEBUG_BUILD && debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
inflightInteractionSpan = startIdleSpan(
|
|
78
|
+
{
|
|
79
|
+
name: latestRoute.name,
|
|
80
|
+
attributes: {
|
|
81
|
+
[SENTRY_OP]: UI_ACTION_CLICK,
|
|
82
|
+
[SENTRY_SEGMENT_NAME_SOURCE]: latestRoute.source || "url",
|
|
83
|
+
[SENTRY_ORIGIN]: "auto.browser.interactions"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
idleSpanOptions
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
{ capture: true }
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function trackInteractionsAsSpans() {
|
|
93
|
+
addPerformanceInstrumentationHandler("event", ({ entries }) => {
|
|
94
|
+
const parent = getActiveSpan();
|
|
95
|
+
if (!parent) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
for (const entry of entries) {
|
|
99
|
+
if (entry.name === "click") {
|
|
100
|
+
const startTime = msToSec(browserPerformanceTimeOrigin() + entry.startTime);
|
|
101
|
+
const duration = msToSec(entry.duration);
|
|
102
|
+
const spanOptions = {
|
|
103
|
+
name: htmlTreeAsString(entry.target),
|
|
104
|
+
startTime,
|
|
105
|
+
attributes: {
|
|
106
|
+
[SENTRY_OP]: UI_INTERACTION_CLICK,
|
|
107
|
+
[SENTRY_ORIGIN]: "auto.browser.interactions"
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const componentName = getComponentName(entry.target);
|
|
111
|
+
if (componentName) {
|
|
112
|
+
spanOptions.attributes[UI_COMPONENT_NAME] = componentName;
|
|
113
|
+
}
|
|
114
|
+
startAndEndSpan(parent, startTime, startTime + duration, spanOptions);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { interactionsIntegration };
|
|
121
|
+
//# sourceMappingURL=interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.js","sources":["../../../src/performance/interactions.ts"],"sourcesContent":["import {\n SENTRY_OP,\n SENTRY_ORIGIN,\n SENTRY_IDLE_SPAN_FINISH_REASON,\n UI_COMPONENT_NAME,\n SENTRY_SOURCE,\n SENTRY_SEGMENT_NAME_SOURCE,\n} from '@sentry/conventions/attributes';\nimport { UI_INTERACTION_CLICK, UI_ACTION_CLICK } from '@sentry/conventions/op';\nimport type { IntegrationFn, Span, StartSpanOptions, TransactionSource } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n defineIntegration,\n getActiveSpan,\n getRootSpan,\n spanToJSON,\n} from '@sentry/core';\nimport { startIdleSpan } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { htmlTreeAsString } from '../htmlTreeAsString';\nimport { addPerformanceInstrumentationHandler } from '../instrumentation/performanceObserver';\nimport { isBotUserAgent } from '../isBotUserAgent';\nimport { WINDOW } from '../types';\nimport { msToSec, startAndEndSpan } from './utils';\nimport { getComponentName } from '../component-name';\n\nconst INTEGRATION_NAME = 'Interactions';\n\ninterface InteractionsOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the interaction span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout?: number;\n\n /**\n * The max. time an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout?: number;\n\n /**\n * The max. time a child span of an interaction span may run.\n * If this time is exceeded, the interaction span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout?: number;\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n}\n\nconst _interactionsIntegration = ((options: InteractionsOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n if (isBotUserAgent()) {\n return;\n }\n\n const latestRoute: RouteInfo = { name: undefined, source: undefined };\n // The pageload/navigation span that is currently in progress, if any. Clicks that happen while one\n // is open are not turned into interaction spans, as they'd compete with the route span for children.\n let inflightRouteSpan: Span | undefined;\n\n function trackRoute(span: Span): void {\n const { name, attributes } = spanToJSON(span);\n latestRoute.name = name;\n // oxlint-disable-next-line typescript/no-deprecated\n latestRoute.source = (attributes[SENTRY_SOURCE] || attributes[SENTRY_SEGMENT_NAME_SOURCE]) as\n | TransactionSource\n | undefined;\n }\n\n client.on('spanStart', span => {\n if (isRouteSpan(span)) {\n inflightRouteSpan = span;\n trackRoute(span);\n }\n });\n\n client.on('spanEnd', span => {\n if (span !== inflightRouteSpan) {\n return;\n }\n inflightRouteSpan = undefined;\n // Re-read the route on end: routing instrumentation frequently renames the pageload or navigation\n // span once the route is resolved, so this is more accurate than what we saw at span start.\n trackRoute(span);\n });\n\n registerInteractionListener(latestRoute, () => inflightRouteSpan, options);\n\n trackInteractionsAsSpans();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Captures user interactions as spans.\n *\n * Important: This integration is considered experimental and might lead to noisy spans. Use at your own risk.\n *\n *\n * Clicks that happen outside of an in-progress pageload or navigation start an idle `ui.action.click` span,\n * named after the last known route, which collects everything the interaction triggers (requests, child spans,\n * …). Additionally, `ui.interaction.click` spans are recorded for the browser's own `event` timing entries.\n *\n * The integration requires `browserTracingIntegration` (or another source of pageload/navigation spans)\n * to know which route an interaction belongs to.\n *\n * @example\n * ```ts\n * Sentry.init({\n * integrations: [Sentry.browserTracingIntegration(), Sentry.interactionsIntegration()],\n * });\n * ```\n */\nexport const interactionsIntegration = defineIntegration(_interactionsIntegration);\n\nfunction isRouteSpan(span: Span): boolean {\n if (getRootSpan(span) !== span) {\n return false;\n }\n const op = spanToJSON(span).attributes[SENTRY_OP];\n return op === 'pageload' || op === 'navigation';\n}\n\nfunction registerInteractionListener(\n latestRoute: RouteInfo,\n getInflightRouteSpan: () => Span | undefined,\n // `startIdleSpan` fills in `TRACING_DEFAULTS` for whatever is left out, which are the same defaults\n // `browserTracingIntegration` uses for its pageload and navigation spans.\n idleSpanOptions: InteractionsOptions,\n): void {\n // `document` is not available in all browser environments (e.g. web workers), and without it there is\n // nothing to click on.\n if (!WINDOW.document) {\n return;\n }\n\n let inflightInteractionSpan: Span | undefined;\n\n addEventListener(\n 'click',\n () => {\n if (getInflightRouteSpan()) {\n DEBUG_BUILD &&\n debug.warn(\n `[Tracing] Did not create ${UI_ACTION_CLICK} span because a pageload or navigation span is in progress.`,\n );\n return;\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${UI_ACTION_CLICK} span because the latest route name is missing.`);\n return;\n }\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: latestRoute.name,\n attributes: {\n [SENTRY_OP]: UI_ACTION_CLICK,\n [SENTRY_SEGMENT_NAME_SOURCE]: latestRoute.source || 'url',\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\n },\n },\n idleSpanOptions,\n );\n },\n { capture: true },\n );\n}\n\n/**\n * Record the browser's `event` timing entries for clicks as spans on the currently active span.\n */\nfunction trackInteractionsAsSpans(): 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 startTime: startTime,\n attributes: {\n [SENTRY_OP]: UI_INTERACTION_CLICK,\n [SENTRY_ORIGIN]: 'auto.browser.interactions',\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"],"names":[],"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":[],"mappings":";;;AAIA,SAAS,gBAAgB,IAAA,EAA8C;AAGrE,EAAA,OAAO,SAAS,4BAAA,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,GAAI,sBAAA,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,EAAE,4BAAA,EAA6B,IAAK,wBAAA,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;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { SENTRY_ORIGIN } from '@sentry/conventions/attributes';
|
|
1
|
+
import { SENTRY_OP, SENTRY_ORIGIN } from '@sentry/conventions/attributes';
|
|
2
2
|
import { defineIntegration, browserPerformanceTimeOrigin, spanToJSON, stringMatchesSomePattern, isPrimitive } from '@sentry/core';
|
|
3
3
|
import { getBrowserPerformanceAPI, msToSec, startAndEndSpan } from './utils.js';
|
|
4
|
-
import { getNavigationEntry } from '
|
|
4
|
+
import { getNavigationEntry } from '../web-vitals/utils.js';
|
|
5
5
|
|
|
6
6
|
const INTEGRATION_NAME = "UserTiming";
|
|
7
7
|
const _userTimingIntegration = ((options = {}) => {
|
|
@@ -16,7 +16,8 @@ const _userTimingIntegration = ((options = {}) => {
|
|
|
16
16
|
const timeOriginInSeconds = msToSec(timeOrigin);
|
|
17
17
|
let performanceCursor = 0;
|
|
18
18
|
client.on("beforeIdleSpanEnd", (idleSpan) => {
|
|
19
|
-
const {
|
|
19
|
+
const { attributes, start_timestamp: parentStartTimestamp } = spanToJSON(idleSpan);
|
|
20
|
+
const parentOp = attributes[SENTRY_OP];
|
|
20
21
|
if (parentOp !== "pageload" && parentOp !== "navigation") {
|
|
21
22
|
return;
|
|
22
23
|
}
|