Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
75 lines
3.3 KiB
Plaintext
75 lines
3.3 KiB
Plaintext
import { browserPerformanceTimeOrigin } from '@sentry/core';
|
|
import { extractNetworkProtocol, getBrowserPerformanceAPI } from './utils.js';
|
|
|
|
function getAbsoluteTime(time) {
|
|
// falsy values should be preserved so that we can later on drop undefined values and
|
|
// preserve 0 vals for cross-origin resources without proper `Timing-Allow-Origin` header.
|
|
return time ? ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000 : time;
|
|
}
|
|
|
|
/**
|
|
* Converts a PerformanceResourceTiming entry to span data for the resource span. Most importantly,
|
|
* it converts the timing values from timestamps relative to the `performance.timeOrigin` to absolute timestamps
|
|
* in seconds.
|
|
*
|
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#timestamps
|
|
*
|
|
* @param resourceTiming
|
|
* @returns An array where the first element is the attribute name and the second element is the attribute value.
|
|
*/
|
|
function resourceTimingToSpanAttributes(resourceTiming) {
|
|
const timingSpanData = {};
|
|
// Checking for only `undefined` and `null` is intentional because it's
|
|
// valid for `nextHopProtocol` to be an empty string.
|
|
if (resourceTiming.nextHopProtocol != undefined) {
|
|
const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol);
|
|
timingSpanData['network.protocol.version'] = version;
|
|
timingSpanData['network.protocol.name'] = name;
|
|
}
|
|
|
|
if (!(browserPerformanceTimeOrigin() || getBrowserPerformanceAPI()?.timeOrigin)) {
|
|
return timingSpanData;
|
|
}
|
|
|
|
return dropUndefinedKeysFromObject({
|
|
...timingSpanData,
|
|
|
|
'http.request.redirect_start': getAbsoluteTime(resourceTiming.redirectStart),
|
|
'http.request.redirect_end': getAbsoluteTime(resourceTiming.redirectEnd),
|
|
|
|
'http.request.worker_start': getAbsoluteTime(resourceTiming.workerStart),
|
|
|
|
'http.request.fetch_start': getAbsoluteTime(resourceTiming.fetchStart),
|
|
|
|
'http.request.domain_lookup_start': getAbsoluteTime(resourceTiming.domainLookupStart),
|
|
'http.request.domain_lookup_end': getAbsoluteTime(resourceTiming.domainLookupEnd),
|
|
|
|
'http.request.connect_start': getAbsoluteTime(resourceTiming.connectStart),
|
|
'http.request.secure_connection_start': getAbsoluteTime(resourceTiming.secureConnectionStart),
|
|
'http.request.connection_end': getAbsoluteTime(resourceTiming.connectEnd),
|
|
|
|
'http.request.request_start': getAbsoluteTime(resourceTiming.requestStart),
|
|
|
|
'http.request.response_start': getAbsoluteTime(resourceTiming.responseStart),
|
|
'http.request.response_end': getAbsoluteTime(resourceTiming.responseEnd),
|
|
|
|
// For TTFB we actually want the relative time from timeOrigin to responseStart
|
|
// This way, TTFB always measures the "first page load" experience.
|
|
// see: https://web.dev/articles/ttfb#measure-resource-requests
|
|
'http.request.time_to_first_byte':
|
|
resourceTiming.responseStart != null ? resourceTiming.responseStart / 1000 : undefined,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Remove properties with `undefined` as value from an object.
|
|
* In contrast to `dropUndefinedKeys` in core this funciton only works on first-level
|
|
* key-value objects and does not recursively go into object properties or arrays.
|
|
*/
|
|
function dropUndefinedKeysFromObject(attrs) {
|
|
return Object.fromEntries(Object.entries(attrs).filter(([, value]) => value != null)) ;
|
|
}
|
|
|
|
export { resourceTimingToSpanAttributes };
|
|
//# sourceMappingURL=resourceTiming.js.map
|