@@ -19,6 +19,7 @@ import {
19
19
addInpInstrumentationHandler ,
20
20
addLcpInstrumentationHandler ,
21
21
addPerformanceInstrumentationHandler ,
22
+ addTtfbInstrumentationHandler ,
22
23
} from '../instrument' ;
23
24
import { WINDOW } from '../types' ;
24
25
import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher' ;
@@ -30,6 +31,8 @@ import type {
30
31
import { _startChild , isMeasurementValue } from './utils' ;
31
32
32
33
import { createSpanEnvelope } from '@sentry/core' ;
34
+ import { getNavigationEntry } from '../web-vitals/lib/getNavigationEntry' ;
35
+ import type { TTFBMetric } from '../web-vitals/types/ttfb' ;
33
36
34
37
const MAX_INT_AS_BYTES = 2147483647 ;
35
38
@@ -68,11 +71,13 @@ export function startTrackingWebVitals(): () => void {
68
71
const fidCallback = _trackFID ( ) ;
69
72
const clsCallback = _trackCLS ( ) ;
70
73
const lcpCallback = _trackLCP ( ) ;
74
+ const ttfbCallback = _trackTtfb ( ) ;
71
75
72
76
return ( ) : void => {
73
77
fidCallback ( ) ;
74
78
clsCallback ( ) ;
75
79
lcpCallback ( ) ;
80
+ ttfbCallback ( ) ;
76
81
} ;
77
82
}
78
83
@@ -201,6 +206,18 @@ function _trackFID(): () => void {
201
206
} ) ;
202
207
}
203
208
209
+ function _trackTtfb ( ) : ( ) => void {
210
+ return addTtfbInstrumentationHandler ( ( { metric } ) => {
211
+ const entry = metric . entries [ metric . entries . length - 1 ] ;
212
+ if ( ! entry ) {
213
+ return ;
214
+ }
215
+
216
+ DEBUG_BUILD && logger . log ( '[Measurements] Adding TTFB' ) ;
217
+ _measurements [ 'ttfb' ] = { value : metric . value , unit : 'millisecond' } ;
218
+ } ) ;
219
+ }
220
+
204
221
const INP_ENTRY_MAP : Record < string , 'click' | 'hover' | 'drag' | 'press' > = {
205
222
click : 'click' ,
206
223
pointerdown : 'click' ,
@@ -308,9 +325,6 @@ export function addPerformanceEntries(transaction: Transaction): void {
308
325
309
326
const performanceEntries = performance . getEntries ( ) ;
310
327
311
- let responseStartTimestamp : number | undefined ;
312
- let requestStartTimestamp : number | undefined ;
313
-
314
328
const { op, start_timestamp : transactionStartTime } = spanToJSON ( transaction ) ;
315
329
316
330
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -326,8 +340,6 @@ export function addPerformanceEntries(transaction: Transaction): void {
326
340
switch ( entry . entryType ) {
327
341
case 'navigation' : {
328
342
_addNavigationSpans ( transaction , entry , timeOrigin ) ;
329
- responseStartTimestamp = timeOrigin + msToSec ( entry . responseStart ) ;
330
- requestStartTimestamp = timeOrigin + msToSec ( entry . requestStart ) ;
331
343
break ;
332
344
}
333
345
case 'mark' :
@@ -365,7 +377,7 @@ export function addPerformanceEntries(transaction: Transaction): void {
365
377
366
378
// Measurements are only available for pageload transactions
367
379
if ( op === 'pageload' ) {
368
- _addTtfbToMeasurements ( _measurements , responseStartTimestamp , requestStartTimestamp , transactionStartTime ) ;
380
+ _addTtfbRequestTimeToMeasurements ( _measurements ) ;
369
381
370
382
[ 'fcp' , 'fp' , 'lcp' ] . forEach ( name => {
371
383
if ( ! _measurements [ name ] || ! transactionStartTime || timeOrigin >= transactionStartTime ) {
@@ -657,40 +669,20 @@ function setResourceEntrySizeData(
657
669
}
658
670
659
671
/**
660
- * Add ttfb information to measurements
672
+ * Add ttfb request time information to measurements.
661
673
*
662
- * Exported for tests
674
+ * ttfb information is added via vendored web vitals library.
663
675
*/
664
- export function _addTtfbToMeasurements (
665
- _measurements : Measurements ,
666
- responseStartTimestamp : number | undefined ,
667
- requestStartTimestamp : number | undefined ,
668
- transactionStartTime : number | undefined ,
669
- ) : void {
670
- // Generate TTFB (Time to First Byte), which measured as the time between the beginning of the transaction and the
671
- // start of the response in milliseconds
672
- if ( typeof responseStartTimestamp === 'number' && transactionStartTime ) {
673
- DEBUG_BUILD && logger . log ( '[Measurements] Adding TTFB' ) ;
674
- _measurements [ 'ttfb' ] = {
675
- // As per https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStart,
676
- // responseStart can be 0 if the request is coming straight from the cache.
677
- // This might lead us to calculate a negative ttfb if we don't use Math.max here.
678
- //
679
- // This logic is the same as what is in the web-vitals library to calculate ttfb
680
- // https://github.com/GoogleChrome/web-vitals/blob/2301de5015e82b09925238a228a0893635854587/src/onTTFB.ts#L92
681
- // TODO(abhi): We should use the web-vitals library instead of this custom calculation.
682
- value : Math . max ( responseStartTimestamp - transactionStartTime , 0 ) * 1000 ,
676
+ function _addTtfbRequestTimeToMeasurements ( _measurements : Measurements ) : void {
677
+ const navEntry = getNavigationEntry ( ) as TTFBMetric [ 'entries' ] [ number ] ;
678
+ const { responseStart, requestStart } = navEntry ;
679
+
680
+ if ( requestStart <= responseStart ) {
681
+ DEBUG_BUILD && logger . log ( '[Measurements] Adding TTFB Request Time' ) ;
682
+ _measurements [ 'ttfb.requestTime' ] = {
683
+ value : responseStart - requestStart ,
683
684
unit : 'millisecond' ,
684
685
} ;
685
-
686
- if ( typeof requestStartTimestamp === 'number' && requestStartTimestamp <= responseStartTimestamp ) {
687
- // Capture the time spent making the request and receiving the first byte of the response.
688
- // This is the time between the start of the request and the start of the response in milliseconds.
689
- _measurements [ 'ttfb.requestTime' ] = {
690
- value : ( responseStartTimestamp - requestStartTimestamp ) * 1000 ,
691
- unit : 'millisecond' ,
692
- } ;
693
- }
694
686
}
695
687
}
696
688
0 commit comments