@@ -27,7 +27,7 @@ import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan
2727import { getActivationStart } from './web-vitals/lib/getActivationStart' ;
2828import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry' ;
2929import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher' ;
30-
30+ import { debug } from '@sentry/core' ;
3131interface NavigatorNetworkInformation {
3232 readonly connection ?: NetworkInformation ;
3333}
@@ -336,6 +336,11 @@ interface AddPerformanceEntriesOptions {
336336 * Default: []
337337 */
338338 ignorePerformanceApiSpans : Array < string | RegExp > ;
339+
340+ /**
341+ * Whether span streaming is enabled.
342+ */
343+ spanStreamingEnabled ?: boolean ;
339344}
340345
341346/** Add performance related spans to a transaction */
@@ -347,6 +352,14 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
347352 return ;
348353 }
349354
355+ const {
356+ spanStreamingEnabled,
357+ ignorePerformanceApiSpans,
358+ ignoreResourceSpans,
359+ recordClsOnPageloadSpan,
360+ recordLcpOnPageloadSpan,
361+ } = options ;
362+
350363 const timeOrigin = msToSec ( origin ) ;
351364
352365 const performanceEntries = performance . getEntries ( ) ;
@@ -375,7 +388,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
375388 case 'mark' :
376389 case 'paint' :
377390 case 'measure' : {
378- _addMeasureSpans ( span , entry , startTime , duration , timeOrigin , options . ignorePerformanceApiSpans ) ;
391+ _addMeasureSpans ( span , entry , startTime , duration , timeOrigin , ignorePerformanceApiSpans ) ;
379392
380393 // capture web vitals
381394 const firstHidden = getVisibilityWatcher ( ) ;
@@ -398,7 +411,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
398411 startTime ,
399412 duration ,
400413 timeOrigin ,
401- options . ignoreResourceSpans ,
414+ ignoreResourceSpans ,
402415 ) ;
403416 break ;
404417 }
@@ -408,25 +421,51 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
408421
409422 _performanceCursor = Math . max ( performanceEntries . length - 1 , 0 ) ;
410423
411- _trackNavigator ( span ) ;
424+ _trackNavigator ( span , spanStreamingEnabled ) ;
412425
413426 // Measurements are only available for pageload transactions
414427 if ( op === 'pageload' ) {
415428 _addTtfbRequestTimeToMeasurements ( _measurements ) ;
416429
417- // If CLS standalone spans are enabled, don't record CLS as a measurement
418- if ( ! options . recordClsOnPageloadSpan ) {
419- delete _measurements . cls ;
420- }
430+ if ( spanStreamingEnabled ) {
431+ const setAttr = ( shortWebVitalName : string , value : number , customAttrName ?: string ) => {
432+ const attrKey = customAttrName ?? `browser.web_vital.${ shortWebVitalName } .value` ;
433+ span . setAttribute ( attrKey , value ) ;
434+ debug . log ( 'Setting web vital attribute' , { [ attrKey ] : value } , 'on pageload span' ) ;
435+ } ;
436+ // for streamed pageload spans, we add the web vital measurements as attributes.
437+ // We omit LCP, CLS and INP because they're tracked separately as spans
438+ if ( _measurements [ 'ttfb' ] ) {
439+ setAttr ( 'ttfb' , _measurements [ 'ttfb' ] . value ) ;
440+ }
441+ if ( _measurements [ 'ttfb.requestTime' ] ) {
442+ setAttr ( 'ttfb.requestTime' , _measurements [ 'ttfb.requestTime' ] . value , 'browser.web_vital.ttfb.request_time' ) ;
443+ }
444+ if ( _measurements [ 'fp' ] ) {
445+ setAttr ( 'fp' , _measurements [ 'fp' ] . value ) ;
446+ }
447+ if ( _measurements [ 'fcp' ] ) {
448+ setAttr ( 'fcp' , _measurements [ 'fcp' ] . value ) ;
449+ }
450+ } else {
451+ // TODO (V11): Remove this else branch once we remove v1 standalone spans and transactions
421452
422- // If LCP standalone spans are enabled, don't record LCP as a measurement
423- if ( ! options . recordLcpOnPageloadSpan ) {
424- delete _measurements . lcp ;
425- }
453+ // If CLS standalone spans are enabled, don't record CLS as a measurement
454+ if ( ! recordClsOnPageloadSpan ) {
455+ delete _measurements . cls ;
456+ }
426457
427- Object . entries ( _measurements ) . forEach ( ( [ measurementName , measurement ] ) => {
428- setMeasurement ( measurementName , measurement . value , measurement . unit ) ;
429- } ) ;
458+ // If LCP standalone spans are enabled, don't record LCP as a measurement
459+ if ( ! recordLcpOnPageloadSpan ) {
460+ delete _measurements . lcp ;
461+ }
462+
463+ Object . entries ( _measurements ) . forEach ( ( [ measurementName , measurement ] ) => {
464+ setMeasurement ( measurementName , measurement . value , measurement . unit ) ;
465+ } ) ;
466+
467+ _setWebVitalAttributes ( span , options ) ;
468+ }
430469
431470 // Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on
432471 span . setAttribute ( 'performance.timeOrigin' , timeOrigin ) ;
@@ -438,8 +477,6 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
438477 // This is user action is called "activation" and the time between navigation and activation is stored in
439478 // the `activationStart` attribute of the "navigation" PerformanceEntry.
440479 span . setAttribute ( 'performance.activationStart' , getActivationStart ( ) ) ;
441-
442- _setWebVitalAttributes ( span , options ) ;
443480 }
444481
445482 _lcpEntry = undefined ;
@@ -734,8 +771,9 @@ export function _addResourceSpans(
734771
735772/**
736773 * Capture the information of the user agent.
774+ * TODO v11: Remove non-span-streaming attributes and measurements once we removed transactions
737775 */
738- function _trackNavigator ( span : Span ) : void {
776+ function _trackNavigator ( span : Span , spanStreamingEnabled : boolean | undefined ) : void {
739777 const navigator = WINDOW . navigator as null | ( Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory ) ;
740778 if ( ! navigator ) {
741779 return ;
@@ -745,24 +783,37 @@ function _trackNavigator(span: Span): void {
745783 const connection = navigator . connection ;
746784 if ( connection ) {
747785 if ( connection . effectiveType ) {
748- span . setAttribute ( 'effectiveConnectionType' , connection . effectiveType ) ;
786+ span . setAttribute (
787+ spanStreamingEnabled ? 'network.connection.effective_type' : 'effectiveConnectionType' ,
788+ connection . effectiveType ,
789+ ) ;
749790 }
750791
751792 if ( connection . type ) {
752- span . setAttribute ( 'connectionType' , connection . type ) ;
793+ span . setAttribute ( spanStreamingEnabled ? 'network.connection.type' : 'connectionType' , connection . type ) ;
753794 }
754795
755796 if ( isMeasurementValue ( connection . rtt ) ) {
756797 _measurements [ 'connection.rtt' ] = { value : connection . rtt , unit : 'millisecond' } ;
798+ if ( spanStreamingEnabled ) {
799+ span . setAttribute ( 'network.connection.rtt' , connection . rtt ) ;
800+ }
757801 }
758802 }
759803
760804 if ( isMeasurementValue ( navigator . deviceMemory ) ) {
761- span . setAttribute ( 'deviceMemory' , `${ navigator . deviceMemory } GB` ) ;
805+ if ( spanStreamingEnabled ) {
806+ span . setAttribute ( 'device.memory.estimated_capacity' , navigator . deviceMemory ) ;
807+ } else {
808+ span . setAttribute ( 'deviceMemory' , `${ navigator . deviceMemory } GB` ) ;
809+ }
762810 }
763811
764812 if ( isMeasurementValue ( navigator . hardwareConcurrency ) ) {
765- span . setAttribute ( 'hardwareConcurrency' , String ( navigator . hardwareConcurrency ) ) ;
813+ span . setAttribute (
814+ spanStreamingEnabled ? 'device.processor_count' : 'hardwareConcurrency' ,
815+ String ( navigator . hardwareConcurrency ) ,
816+ ) ;
766817 }
767818}
768819
0 commit comments