Skip to content

Commit

Permalink
fix: Avoid performance.timeOrigin if too skewed (#3356)
Browse files Browse the repository at this point in the history
Try to use the best of performance.timeOrigin or performance.timing.navigationStart as long as they are near the current time reported by Date.now.

The intention is to mitigate transactions that are reported with a huge time skew, particularly from Firefox.

This is trying to address the inconsistencies between browsers by always trying to use timeOrigin first, as long as its consistent with the current time, otherwise, use the navigationStart if its consistent with the current time, eventually fallback to date if all else fails.

We also remember what source is used for the time origin, so we can tag events and analyze later.

Co-authored-by: Rodolfo Carvalho <rodolfo.carvalho@sentry.io>
Co-authored-by: Alberto Leal <mail4alberto@gmail.com>
  • Loading branch information
3 people authored Mar 31, 2021
1 parent 28c540c commit dece89a
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions packages/utils/src/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,51 @@ export const timestampWithMs = timestampInSeconds;
*/
export const usingPerformanceAPI = platformPerformance !== undefined;

/**
* Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only.
*/
export let _browserPerformanceTimeOriginMode: string;

/**
* The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the
* performance API is available.
*/
export const browserPerformanceTimeOrigin = ((): number | undefined => {
// Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or
// performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin
// data as reliable if they are within a reasonable threshold of the current time.

const { performance } = getGlobalObject<Window>();
if (!performance) {
_browserPerformanceTimeOriginMode = 'none';
return undefined;
}
if (performance.timeOrigin) {

const threshold = 3600 * 1000;

const timeOriginIsReliable =
performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < threshold;
if (timeOriginIsReliable) {
_browserPerformanceTimeOriginMode = 'timeOrigin';
return 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.
// Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always
// a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the
// Date API.
// eslint-disable-next-line deprecation/deprecation
return (performance.timing && performance.timing.navigationStart) || Date.now();
const navigationStart = performance.timing && performance.timing.navigationStart;
const hasNavigationStart = typeof navigationStart === 'number';
const navigationStartIsReliable =
hasNavigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < threshold;
if (navigationStartIsReliable) {
_browserPerformanceTimeOriginMode = 'navigationStart';
return navigationStart;
}

// Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date.
_browserPerformanceTimeOriginMode = 'dateNow';
return Date.now();
})();

0 comments on commit dece89a

Please sign in to comment.