@@ -300,7 +300,7 @@ interface AddPerformanceEntriesOptions {
300300/** Add performance related spans to a transaction */
301301export function addPerformanceEntries ( span : Span , options : AddPerformanceEntriesOptions ) : void {
302302 const performance = getBrowserPerformanceAPI ( ) ;
303- if ( ! performance || ! WINDOW . performance . getEntries || ! browserPerformanceTimeOrigin ) {
303+ if ( ! performance || ! performance . getEntries || ! browserPerformanceTimeOrigin ) {
304304 // Gatekeeper if performance API not available
305305 return ;
306306 }
@@ -311,8 +311,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
311311
312312 const { op, start_timestamp : transactionStartTime } = spanToJSON ( span ) ;
313313
314- // eslint-disable-next-line @typescript-eslint/no-explicit-any
315- performanceEntries . slice ( _performanceCursor ) . forEach ( ( entry : Record < string , any > ) => {
314+ performanceEntries . slice ( _performanceCursor ) . forEach ( entry => {
316315 const startTime = msToSec ( entry . startTime ) ;
317316 const duration = msToSec (
318317 // Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.
@@ -328,7 +327,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
328327
329328 switch ( entry . entryType ) {
330329 case 'navigation' : {
331- _addNavigationSpans ( span , entry , timeOrigin ) ;
330+ _addNavigationSpans ( span , entry as PerformanceNavigationTiming , timeOrigin ) ;
332331 break ;
333332 }
334333 case 'mark' :
@@ -350,10 +349,9 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
350349 break ;
351350 }
352351 case 'resource' : {
353- _addResourceSpans ( span , entry , entry . name as string , startTime , duration , timeOrigin ) ;
352+ _addResourceSpans ( span , entry as PerformanceResourceTiming , entry . name , startTime , duration , timeOrigin ) ;
354353 break ;
355354 }
356- default :
357355 // Ignore other entry types.
358356 }
359357 } ) ;
@@ -411,11 +409,13 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
411409 _measurements = { } ;
412410}
413411
414- /** Create measure related spans */
412+ /**
413+ * Create measure related spans.
414+ * Exported only for tests.
415+ */
415416export function _addMeasureSpans (
416417 span : Span ,
417- // eslint-disable-next-line @typescript-eslint/no-explicit-any
418- entry : Record < string , any > ,
418+ entry : PerformanceEntry ,
419419 startTime : number ,
420420 duration : number ,
421421 timeOrigin : number ,
@@ -454,44 +454,72 @@ export function _addMeasureSpans(
454454}
455455
456456/** Instrument navigation entries */
457- // eslint-disable-next-line @typescript-eslint/no-explicit-any
458- function _addNavigationSpans ( span : Span , entry : Record < string , any > , timeOrigin : number ) : void {
459- [ 'unloadEvent' , 'redirect' , 'domContentLoadedEvent' , 'loadEvent' , 'connect' ] . forEach ( event => {
457+ function _addNavigationSpans ( span : Span , entry : PerformanceNavigationTiming , timeOrigin : number ) : void {
458+ ( [ 'unloadEvent' , 'redirect' , 'domContentLoadedEvent' , 'loadEvent' , 'connect' ] as const ) . forEach ( event => {
460459 _addPerformanceNavigationTiming ( span , entry , event , timeOrigin ) ;
461460 } ) ;
462- _addPerformanceNavigationTiming ( span , entry , 'secureConnection' , timeOrigin , 'TLS/SSL' , 'connectEnd' ) ;
463- _addPerformanceNavigationTiming ( span , entry , 'fetch' , timeOrigin , 'cache' , 'domainLookupStart' ) ;
461+ _addPerformanceNavigationTiming ( span , entry , 'secureConnection' , timeOrigin , 'TLS/SSL' ) ;
462+ _addPerformanceNavigationTiming ( span , entry , 'fetch' , timeOrigin , 'cache' ) ;
464463 _addPerformanceNavigationTiming ( span , entry , 'domainLookup' , timeOrigin , 'DNS' ) ;
464+
465465 _addRequest ( span , entry , timeOrigin ) ;
466466}
467467
468+ type StartEventName =
469+ | 'secureConnection'
470+ | 'fetch'
471+ | 'domainLookup'
472+ | 'unloadEvent'
473+ | 'redirect'
474+ | 'connect'
475+ | 'domContentLoadedEvent'
476+ | 'loadEvent' ;
477+
478+ type EndEventName =
479+ | 'connectEnd'
480+ | 'domainLookupStart'
481+ | 'domainLookupEnd'
482+ | 'unloadEventEnd'
483+ | 'redirectEnd'
484+ | 'connectEnd'
485+ | 'domContentLoadedEventEnd'
486+ | 'loadEventEnd' ;
487+
468488/** Create performance navigation related spans */
469489function _addPerformanceNavigationTiming (
470490 span : Span ,
471- // eslint-disable-next-line @typescript-eslint/no-explicit-any
472- entry : Record < string , any > ,
473- event : string ,
491+ entry : PerformanceNavigationTiming ,
492+ event : StartEventName ,
474493 timeOrigin : number ,
475- name ?: string ,
476- eventEnd ?: string ,
494+ name : string = event ,
477495) : void {
478- const end = eventEnd ? ( entry [ eventEnd ] as number | undefined ) : ( entry [ `${ event } End` ] as number | undefined ) ;
479- const start = entry [ `${ event } Start` ] as number | undefined ;
496+ const eventEnd = _getEndPropertyNameForNavigationTiming ( event ) satisfies keyof PerformanceNavigationTiming ;
497+ const end = entry [ eventEnd ] ;
498+ const start = entry [ `${ event } Start` ] ;
480499 if ( ! start || ! end ) {
481500 return ;
482501 }
483502 startAndEndSpan ( span , timeOrigin + msToSec ( start ) , timeOrigin + msToSec ( end ) , {
484- op : `browser.${ name || event } ` ,
503+ op : `browser.${ name } ` ,
485504 name : entry . name ,
486505 attributes : {
487506 [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.ui.browser.metrics' ,
488507 } ,
489508 } ) ;
490509}
491510
511+ function _getEndPropertyNameForNavigationTiming ( event : StartEventName ) : EndEventName {
512+ if ( event === 'secureConnection' ) {
513+ return 'connectEnd' ;
514+ }
515+ if ( event === 'fetch' ) {
516+ return 'domainLookupStart' ;
517+ }
518+ return `${ event } End` ;
519+ }
520+
492521/** Create request and response related spans */
493- // eslint-disable-next-line @typescript-eslint/no-explicit-any
494- function _addRequest ( span : Span , entry : Record < string , any > , timeOrigin : number ) : void {
522+ function _addRequest ( span : Span , entry : PerformanceNavigationTiming , timeOrigin : number ) : void {
495523 const requestStartTimestamp = timeOrigin + msToSec ( entry . requestStart as number ) ;
496524 const responseEndTimestamp = timeOrigin + msToSec ( entry . responseEnd as number ) ;
497525 const responseStartTimestamp = timeOrigin + msToSec ( entry . responseStart as number ) ;
@@ -518,19 +546,13 @@ function _addRequest(span: Span, entry: Record<string, any>, timeOrigin: number)
518546 }
519547}
520548
521- export interface ResourceEntry extends Record < string , unknown > {
522- initiatorType ?: string ;
523- transferSize ?: number ;
524- encodedBodySize ?: number ;
525- decodedBodySize ?: number ;
526- renderBlockingStatus ?: string ;
527- deliveryType ?: string ;
528- }
529-
530- /** Create resource-related spans */
549+ /**
550+ * Create resource-related spans.
551+ * Exported only for tests.
552+ */
531553export function _addResourceSpans (
532554 span : Span ,
533- entry : ResourceEntry ,
555+ entry : PerformanceResourceTiming ,
534556 resourceUrl : string ,
535557 startTime : number ,
536558 duration : number ,
@@ -551,13 +573,19 @@ export function _addResourceSpans(
551573 setResourceEntrySizeData ( attributes , entry , 'encodedBodySize' , 'http.response_content_length' ) ;
552574 setResourceEntrySizeData ( attributes , entry , 'decodedBodySize' , 'http.decoded_response_content_length' ) ;
553575
554- if ( entry . deliveryType != null ) {
555- attributes [ 'http.response_delivery_type' ] = entry . deliveryType ;
576+ // `deliveryType` is experimental and does not exist everywhere
577+ const deliveryType = ( entry as { deliveryType ?: 'cache' | 'navigational-prefetch' | '' } ) . deliveryType ;
578+ if ( deliveryType != null ) {
579+ attributes [ 'http.response_delivery_type' ] = deliveryType ;
556580 }
557581
558- if ( 'renderBlockingStatus' in entry ) {
559- attributes [ 'resource.render_blocking_status' ] = entry . renderBlockingStatus ;
582+ // Types do not reflect this property yet
583+ const renderBlockingStatus = ( entry as { renderBlockingStatus ?: 'render-blocking' | 'non-render-blocking' } )
584+ . renderBlockingStatus ;
585+ if ( renderBlockingStatus ) {
586+ attributes [ 'resource.render_blocking_status' ] = renderBlockingStatus ;
560587 }
588+
561589 if ( parsedUrl . protocol ) {
562590 attributes [ 'url.scheme' ] = parsedUrl . protocol . split ( ':' ) . pop ( ) ; // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.
563591 }
@@ -655,8 +683,8 @@ function _setWebVitalAttributes(span: Span): void {
655683
656684function setResourceEntrySizeData (
657685 attributes : SpanAttributes ,
658- entry : ResourceEntry ,
659- key : keyof Pick < ResourceEntry , 'transferSize' | 'encodedBodySize' | 'decodedBodySize' > ,
686+ entry : PerformanceResourceTiming ,
687+ key : keyof Pick < PerformanceResourceTiming , 'transferSize' | 'encodedBodySize' | 'decodedBodySize' > ,
660688 dataKey : 'http.response_transfer_size' | 'http.response_content_length' | 'http.decoded_response_content_length' ,
661689) : void {
662690 const entryVal = entry [ key ] ;
0 commit comments