Skip to content

Commit 76da9e7

Browse files
authored
feat(apm): Update Span timing from absolute ref (#2479)
Use performance.timeOrigin as the absolute reference to update Span start and end timestamps. Where performance.timeOrigin is not available, fallback to performance.timing.navigationStart.
1 parent cda040f commit 76da9e7

File tree

1 file changed

+37
-21
lines changed

1 file changed

+37
-21
lines changed

packages/apm/src/integrations/tracing.ts

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ interface Activity {
9595
const global = getGlobalObject<Window>();
9696
const defaultTracingOrigins = ['localhost', /^\//];
9797

98+
if (global.performance) {
99+
// Polyfill for performance.timeOrigin.
100+
//
101+
// While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin
102+
// is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing.
103+
// tslint:disable-next-line:strict-type-predicates
104+
if (performance.timeOrigin === undefined) {
105+
// @ts-ignore
106+
// tslint:disable-next-line:deprecation
107+
performance.timeOrigin = performance.timing.navigationStart;
108+
}
109+
}
110+
98111
/**
99112
* Tracing Integration
100113
*/
@@ -382,15 +395,11 @@ export class Tracing implements Integration {
382395
// Gatekeeper if performance API not available
383396
return;
384397
}
398+
385399
logger.log('[Tracing] Adding & adjusting spans using Performance API');
386-
let navigationOffset = 0;
387-
if (
388-
transactionSpan.op === 'navigation' &&
389-
transactionSpan.data &&
390-
typeof transactionSpan.data.offset === 'number'
391-
) {
392-
navigationOffset = transactionSpan.data.offset;
393-
}
400+
401+
const timeOrigin = Tracing._msToSec(performance.timeOrigin);
402+
394403
// tslint:disable-next-line: completed-docs
395404
function addSpan(span: SpanClass): void {
396405
if (transactionSpan.spanRecorder) {
@@ -404,8 +413,8 @@ export class Tracing implements Integration {
404413
description: event,
405414
op: 'browser',
406415
});
407-
span.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry[`${event}Start`]);
408-
span.timestamp = parent.startTimestamp + Tracing._msToSec(entry[`${event}End`]);
416+
span.startTimestamp = timeOrigin + Tracing._msToSec(entry[`${event}Start`]);
417+
span.timestamp = timeOrigin + Tracing._msToSec(entry[`${event}End`]);
409418
addSpan(span);
410419
}
411420

@@ -415,15 +424,15 @@ export class Tracing implements Integration {
415424
description: 'request',
416425
op: 'browser',
417426
});
418-
request.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry.requestStart);
419-
request.timestamp = parent.startTimestamp + Tracing._msToSec(entry.responseEnd);
427+
request.startTimestamp = timeOrigin + Tracing._msToSec(entry.requestStart);
428+
request.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd);
420429
addSpan(request);
421430
const response = parent.child({
422431
description: 'response',
423432
op: 'browser',
424433
});
425-
response.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry.responseStart);
426-
response.timestamp = parent.startTimestamp + Tracing._msToSec(entry.responseEnd);
434+
response.startTimestamp = timeOrigin + Tracing._msToSec(entry.responseStart);
435+
response.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd);
427436
addSpan(response);
428437
}
429438

@@ -469,7 +478,7 @@ export class Tracing implements Integration {
469478
description: `${entry.entryType} ${entry.name}`,
470479
op: 'mark',
471480
});
472-
mark.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset;
481+
mark.startTimestamp = timeOrigin + startTime;
473482
mark.timestamp = mark.startTimestamp + duration;
474483
if (tracingInitMarkStartTime === undefined && entry.name === 'sentry-tracing-init') {
475484
tracingInitMarkStartTime = mark.startTimestamp;
@@ -483,7 +492,7 @@ export class Tracing implements Integration {
483492
if (transactionSpan.spanRecorder) {
484493
transactionSpan.spanRecorder.finishedSpans.map((finishedSpan: SpanClass) => {
485494
if (finishedSpan.description && finishedSpan.description.indexOf(resourceName) !== -1) {
486-
finishedSpan.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset;
495+
finishedSpan.startTimestamp = timeOrigin + startTime;
487496
finishedSpan.timestamp = finishedSpan.startTimestamp + duration;
488497
}
489498
});
@@ -493,7 +502,7 @@ export class Tracing implements Integration {
493502
description: `${entry.initiatorType} ${resourceName}`,
494503
op: `resource`,
495504
});
496-
resource.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset;
505+
resource.startTimestamp = timeOrigin + startTime;
497506
resource.timestamp = resource.startTimestamp + duration;
498507
// We remember the entry script end time to calculate the difference to the first init mark
499508
if (entryScriptStartEndTime === undefined && (entryScriptSrc || '').includes(resourceName)) {
@@ -649,10 +658,17 @@ export class Tracing implements Integration {
649658
});
650659
}
651660
span.finish();
652-
// If there is an offset in data, we need to shift timestamps towards it
653-
if (span.data && typeof span.data.offset === 'number' && typeof span.timestamp === 'number') {
654-
span.startTimestamp += span.data.offset;
655-
span.timestamp += span.data.offset;
661+
// If there is an offset in data, update timestamps accordingly
662+
if (
663+
global.performance &&
664+
span.data &&
665+
typeof span.data.offset === 'number' &&
666+
typeof span.timestamp === 'number'
667+
) {
668+
const timeOrigin = Tracing._msToSec(performance.timeOrigin);
669+
const duration = span.timestamp - span.startTimestamp;
670+
span.startTimestamp = timeOrigin + span.data.offset;
671+
span.timestamp = timeOrigin + duration;
656672
}
657673
}
658674
// tslint:disable-next-line: no-dynamic-delete

0 commit comments

Comments
 (0)