diff --git a/packages/apm/src/integrations/tracing.ts b/packages/apm/src/integrations/tracing.ts index 631fdbe085ca..27dc92a993c2 100644 --- a/packages/apm/src/integrations/tracing.ts +++ b/packages/apm/src/integrations/tracing.ts @@ -95,6 +95,19 @@ interface Activity { const global = getGlobalObject(); const defaultTracingOrigins = ['localhost', /^\//]; +if (global.performance) { + // Polyfill for performance.timeOrigin. + // + // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin + // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing. + // tslint:disable-next-line:strict-type-predicates + if (performance.timeOrigin === undefined) { + // @ts-ignore + // tslint:disable-next-line:deprecation + performance.timeOrigin = performance.timing.navigationStart; + } +} + /** * Tracing Integration */ @@ -382,15 +395,11 @@ export class Tracing implements Integration { // Gatekeeper if performance API not available return; } + logger.log('[Tracing] Adding & adjusting spans using Performance API'); - let navigationOffset = 0; - if ( - transactionSpan.op === 'navigation' && - transactionSpan.data && - typeof transactionSpan.data.offset === 'number' - ) { - navigationOffset = transactionSpan.data.offset; - } + + const timeOrigin = Tracing._msToSec(performance.timeOrigin); + // tslint:disable-next-line: completed-docs function addSpan(span: SpanClass): void { if (transactionSpan.spanRecorder) { @@ -404,8 +413,8 @@ export class Tracing implements Integration { description: event, op: 'browser', }); - span.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry[`${event}Start`]); - span.timestamp = parent.startTimestamp + Tracing._msToSec(entry[`${event}End`]); + span.startTimestamp = timeOrigin + Tracing._msToSec(entry[`${event}Start`]); + span.timestamp = timeOrigin + Tracing._msToSec(entry[`${event}End`]); addSpan(span); } @@ -415,15 +424,15 @@ export class Tracing implements Integration { description: 'request', op: 'browser', }); - request.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry.requestStart); - request.timestamp = parent.startTimestamp + Tracing._msToSec(entry.responseEnd); + request.startTimestamp = timeOrigin + Tracing._msToSec(entry.requestStart); + request.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); addSpan(request); const response = parent.child({ description: 'response', op: 'browser', }); - response.startTimestamp = parent.startTimestamp + Tracing._msToSec(entry.responseStart); - response.timestamp = parent.startTimestamp + Tracing._msToSec(entry.responseEnd); + response.startTimestamp = timeOrigin + Tracing._msToSec(entry.responseStart); + response.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); addSpan(response); } @@ -469,7 +478,7 @@ export class Tracing implements Integration { description: `${entry.entryType} ${entry.name}`, op: 'mark', }); - mark.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset; + mark.startTimestamp = timeOrigin + startTime; mark.timestamp = mark.startTimestamp + duration; if (tracingInitMarkStartTime === undefined && entry.name === 'sentry-tracing-init') { tracingInitMarkStartTime = mark.startTimestamp; @@ -483,7 +492,7 @@ export class Tracing implements Integration { if (transactionSpan.spanRecorder) { transactionSpan.spanRecorder.finishedSpans.map((finishedSpan: SpanClass) => { if (finishedSpan.description && finishedSpan.description.indexOf(resourceName) !== -1) { - finishedSpan.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset; + finishedSpan.startTimestamp = timeOrigin + startTime; finishedSpan.timestamp = finishedSpan.startTimestamp + duration; } }); @@ -493,7 +502,7 @@ export class Tracing implements Integration { description: `${entry.initiatorType} ${resourceName}`, op: `resource`, }); - resource.startTimestamp = transactionSpan.startTimestamp + startTime - navigationOffset; + resource.startTimestamp = timeOrigin + startTime; resource.timestamp = resource.startTimestamp + duration; // We remember the entry script end time to calculate the difference to the first init mark if (entryScriptStartEndTime === undefined && (entryScriptSrc || '').includes(resourceName)) { @@ -649,10 +658,17 @@ export class Tracing implements Integration { }); } span.finish(); - // If there is an offset in data, we need to shift timestamps towards it - if (span.data && typeof span.data.offset === 'number' && typeof span.timestamp === 'number') { - span.startTimestamp += span.data.offset; - span.timestamp += span.data.offset; + // If there is an offset in data, update timestamps accordingly + if ( + global.performance && + span.data && + typeof span.data.offset === 'number' && + typeof span.timestamp === 'number' + ) { + const timeOrigin = Tracing._msToSec(performance.timeOrigin); + const duration = span.timestamp - span.startTimestamp; + span.startTimestamp = timeOrigin + span.data.offset; + span.timestamp = timeOrigin + duration; } } // tslint:disable-next-line: no-dynamic-delete