@@ -300,7 +300,7 @@ interface AddPerformanceEntriesOptions {
300
300
/** Add performance related spans to a transaction */
301
301
export function addPerformanceEntries ( span : Span , options : AddPerformanceEntriesOptions ) : void {
302
302
const performance = getBrowserPerformanceAPI ( ) ;
303
- if ( ! performance || ! WINDOW . performance . getEntries || ! browserPerformanceTimeOrigin ) {
303
+ if ( ! performance || ! performance . getEntries || ! browserPerformanceTimeOrigin ) {
304
304
// Gatekeeper if performance API not available
305
305
return ;
306
306
}
@@ -311,8 +311,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
311
311
312
312
const { op, start_timestamp : transactionStartTime } = spanToJSON ( span ) ;
313
313
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 => {
316
315
const startTime = msToSec ( entry . startTime ) ;
317
316
const duration = msToSec (
318
317
// Inexplicably, Chrome sometimes emits a negative duration. We need to work around this.
@@ -328,7 +327,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
328
327
329
328
switch ( entry . entryType ) {
330
329
case 'navigation' : {
331
- _addNavigationSpans ( span , entry , timeOrigin ) ;
330
+ _addNavigationSpans ( span , entry as PerformanceNavigationTiming , timeOrigin ) ;
332
331
break ;
333
332
}
334
333
case 'mark' :
@@ -350,10 +349,9 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
350
349
break ;
351
350
}
352
351
case 'resource' : {
353
- _addResourceSpans ( span , entry , entry . name as string , startTime , duration , timeOrigin ) ;
352
+ _addResourceSpans ( span , entry as PerformanceResourceTiming , entry . name , startTime , duration , timeOrigin ) ;
354
353
break ;
355
354
}
356
- default :
357
355
// Ignore other entry types.
358
356
}
359
357
} ) ;
@@ -411,11 +409,13 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
411
409
_measurements = { } ;
412
410
}
413
411
414
- /** Create measure related spans */
412
+ /**
413
+ * Create measure related spans.
414
+ * Exported only for tests.
415
+ */
415
416
export function _addMeasureSpans (
416
417
span : Span ,
417
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
418
- entry : Record < string , any > ,
418
+ entry : PerformanceEntry ,
419
419
startTime : number ,
420
420
duration : number ,
421
421
timeOrigin : number ,
@@ -454,44 +454,72 @@ export function _addMeasureSpans(
454
454
}
455
455
456
456
/** 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 => {
460
459
_addPerformanceNavigationTiming ( span , entry , event , timeOrigin ) ;
461
460
} ) ;
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' ) ;
464
463
_addPerformanceNavigationTiming ( span , entry , 'domainLookup' , timeOrigin , 'DNS' ) ;
464
+
465
465
_addRequest ( span , entry , timeOrigin ) ;
466
466
}
467
467
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
+
468
488
/** Create performance navigation related spans */
469
489
function _addPerformanceNavigationTiming (
470
490
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 ,
474
493
timeOrigin : number ,
475
- name ?: string ,
476
- eventEnd ?: string ,
494
+ name : string = event ,
477
495
) : 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` ] ;
480
499
if ( ! start || ! end ) {
481
500
return ;
482
501
}
483
502
startAndEndSpan ( span , timeOrigin + msToSec ( start ) , timeOrigin + msToSec ( end ) , {
484
- op : `browser.${ name || event } ` ,
503
+ op : `browser.${ name } ` ,
485
504
name : entry . name ,
486
505
attributes : {
487
506
[ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.ui.browser.metrics' ,
488
507
} ,
489
508
} ) ;
490
509
}
491
510
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
+
492
521
/** 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 {
495
523
const requestStartTimestamp = timeOrigin + msToSec ( entry . requestStart as number ) ;
496
524
const responseEndTimestamp = timeOrigin + msToSec ( entry . responseEnd as number ) ;
497
525
const responseStartTimestamp = timeOrigin + msToSec ( entry . responseStart as number ) ;
@@ -518,19 +546,13 @@ function _addRequest(span: Span, entry: Record<string, any>, timeOrigin: number)
518
546
}
519
547
}
520
548
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
+ */
531
553
export function _addResourceSpans (
532
554
span : Span ,
533
- entry : ResourceEntry ,
555
+ entry : PerformanceResourceTiming ,
534
556
resourceUrl : string ,
535
557
startTime : number ,
536
558
duration : number ,
@@ -551,13 +573,19 @@ export function _addResourceSpans(
551
573
setResourceEntrySizeData ( attributes , entry , 'encodedBodySize' , 'http.response_content_length' ) ;
552
574
setResourceEntrySizeData ( attributes , entry , 'decodedBodySize' , 'http.decoded_response_content_length' ) ;
553
575
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 ;
556
580
}
557
581
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 ;
560
587
}
588
+
561
589
if ( parsedUrl . protocol ) {
562
590
attributes [ 'url.scheme' ] = parsedUrl . protocol . split ( ':' ) . pop ( ) ; // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.
563
591
}
@@ -655,8 +683,8 @@ function _setWebVitalAttributes(span: Span): void {
655
683
656
684
function setResourceEntrySizeData (
657
685
attributes : SpanAttributes ,
658
- entry : ResourceEntry ,
659
- key : keyof Pick < ResourceEntry , 'transferSize' | 'encodedBodySize' | 'decodedBodySize' > ,
686
+ entry : PerformanceResourceTiming ,
687
+ key : keyof Pick < PerformanceResourceTiming , 'transferSize' | 'encodedBodySize' | 'decodedBodySize' > ,
660
688
dataKey : 'http.response_transfer_size' | 'http.response_content_length' | 'http.decoded_response_content_length' ,
661
689
) : void {
662
690
const entryVal = entry [ key ] ;
0 commit comments