UNPKG

@sentry/utils

Version:
181 lines (157 loc) 7.6 kB
Object.defineProperty(exports, '__esModule', { value: true }); var global = require('./global.js'); var node = require('./node.js'); /** * An object that can return the current timestamp in seconds since the UNIX epoch. */ /** * A TimestampSource implementation for environments that do not support the Performance Web API natively. * * Note that this TimestampSource does not use a monotonic clock. A call to `nowSeconds` may return a timestamp earlier * than a previously returned value. We do not try to emulate a monotonic behavior in order to facilitate debugging. It * is more obvious to explain "why does my span have negative duration" than "why my spans have zero duration". */ var dateTimestampSource = { nowSeconds: () => Date.now() / 1000, }; /** * A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance} * for accessing a high-resolution monotonic clock. */ /** * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not * support the API. * * Wrapping the native API works around differences in behavior from different browsers. */ function getBrowserPerformance() { const { performance } = global.getGlobalObject(); if (!performance || !performance.now) { return undefined; } // Replace performance.timeOrigin with our own timeOrigin based on Date.now(). // // This is a partial workaround for browsers reporting performance.timeOrigin such that performance.timeOrigin + // performance.now() gives a date arbitrarily in the past. // // Additionally, computing timeOrigin in this way fills the gap for browsers where performance.timeOrigin is // undefined. // // The assumption that performance.timeOrigin + performance.now() ~= Date.now() is flawed, but we depend on it to // interact with data coming out of performance entries. // // Note that despite recommendations against it in the spec, browsers implement the Performance API with a clock that // might stop when the computer is asleep (and perhaps under other circumstances). Such behavior causes // performance.timeOrigin + performance.now() to have an arbitrary skew over Date.now(). In laptop computers, we have // observed skews that can be as long as days, weeks or months. // // See https://github.com/getsentry/sentry-javascript/issues/2590. // // BUG: despite our best intentions, this workaround has its limitations. It mostly addresses timings of pageload // transactions, but ignores the skew built up over time that can aversely affect timestamps of navigation // transactions of long-lived web pages. var timeOrigin = Date.now() - performance.now(); return { now: () => performance.now(), timeOrigin, }; } /** * Returns the native Performance API implementation from Node.js. Returns undefined in old Node.js versions that don't * implement the API. */ function getNodePerformance() { try { var perfHooks = node.dynamicRequire(module, 'perf_hooks') ; return perfHooks.performance; } catch (_) { return undefined; } } /** * The Performance API implementation for the current platform, if available. */ var platformPerformance = node.isNodeEnv() ? getNodePerformance() : getBrowserPerformance(); var timestampSource = platformPerformance === undefined ? dateTimestampSource : { nowSeconds: () => (platformPerformance.timeOrigin + platformPerformance.now()) / 1000, }; /** * Returns a timestamp in seconds since the UNIX epoch using the Date API. */ var dateTimestampInSeconds = dateTimestampSource.nowSeconds.bind(dateTimestampSource); /** * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the * availability of the Performance API. * * See `usingPerformanceAPI` to test whether the Performance API is used. * * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The * skew can grow to arbitrary amounts like days, weeks or months. * See https://github.com/getsentry/sentry-javascript/issues/2590. */ var timestampInSeconds = timestampSource.nowSeconds.bind(timestampSource); // Re-exported with an old name for backwards-compatibility. var timestampWithMs = timestampInSeconds; /** * A boolean that is true when timestampInSeconds uses the Performance API to produce monotonic timestamps. */ var usingPerformanceAPI = platformPerformance !== undefined; /** * Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only. */ exports._browserPerformanceTimeOriginMode = void 0; /** * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the * performance API is available. */ var browserPerformanceTimeOrigin = (() => { // 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 } = global.getGlobalObject(); if (!performance || !performance.now) { exports._browserPerformanceTimeOriginMode = 'none'; return undefined; } var threshold = 3600 * 1000; var performanceNow = performance.now(); var dateNow = Date.now(); // if timeOrigin isn't available set delta to threshold so it isn't used var timeOriginDelta = performance.timeOrigin ? Math.abs(performance.timeOrigin + performanceNow - dateNow) : threshold; var timeOriginIsReliable = timeOriginDelta < threshold; // 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. var navigationStart = performance.timing && performance.timing.navigationStart; var hasNavigationStart = typeof navigationStart === 'number'; // if navigationStart isn't available set delta to threshold so it isn't used var navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold; var navigationStartIsReliable = navigationStartDelta < threshold; if (timeOriginIsReliable || navigationStartIsReliable) { // Use the more reliable time origin if (timeOriginDelta <= navigationStartDelta) { exports._browserPerformanceTimeOriginMode = 'timeOrigin'; return performance.timeOrigin; } else { exports._browserPerformanceTimeOriginMode = 'navigationStart'; return navigationStart; } } // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date. exports._browserPerformanceTimeOriginMode = 'dateNow'; return dateNow; })(); exports.browserPerformanceTimeOrigin = browserPerformanceTimeOrigin; exports.dateTimestampInSeconds = dateTimestampInSeconds; exports.timestampInSeconds = timestampInSeconds; exports.timestampWithMs = timestampWithMs; exports.usingPerformanceAPI = usingPerformanceAPI; //# sourceMappingURL=time.js.map