@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
191 lines • 6.57 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapOperationForVisualization = void 0;
const ensureTimestamp_1 = require("../ensureTimestamp");
const orderArray = [
'longtask',
'long-animation-frame',
'computed-span',
'component-render',
'measure',
'resource',
'resource-ember',
'asset',
'iframe',
];
const ASSET_EXTENSIONS = [
'.mp3',
'.mp4',
'.webm',
'.wav',
'.ogg',
'.flac',
'.aac',
'.aiff',
'.wma',
'.m4a',
'.flv',
'.avi',
'.mov',
'.wmv',
'.mpg',
'.mpeg',
'.mkv',
'.jpg',
'.jpeg',
'.png',
'.gif',
'.webp',
'.bmp',
'.tiff',
'.svg',
'.ico',
'.css',
'.scss',
'.less',
'.styl',
'.html',
'.htm',
'.xml',
'.js',
];
const order = Object.fromEntries(orderArray.map((type, idx) => [type, idx]));
const mapOperationForVisualization = (traceRecording, { collapseRenders = true, collapseAssets = true, collapseEmberResources = false, collapseIframes = false, displayResources = true, displayMeasures = true, } = {}) => {
const allEntries = traceRecording.entries;
if (!allEntries)
return null;
const preMappedEntries = allEntries.flatMap((entry) => {
if (entry.span.type === 'component-render-start') {
return [];
}
const mapped = {
span: entry.span,
annotation: entry.annotation,
groupName: entry.span.name,
type: entry.span.type,
};
let overrideGroupName;
let { type } = mapped;
if (type === 'resource') {
const filename = (mapped.span.performanceEntry?.name ?? mapped.span.name)
.split('/')
.at(-1)
?.split('?')
.at(0);
const extension = filename?.split('.').at(-1);
if (filename === '$file' ||
(extension && ASSET_EXTENSIONS.includes(`.${extension}`))) {
overrideGroupName = overrideGroupName ?? extension;
type = 'asset';
}
}
if (collapseRenders && type === 'component-render') {
overrideGroupName = 'renders';
}
if (collapseAssets && type === 'asset') {
overrideGroupName = 'assets';
}
if (collapseIframes && type === 'iframe') {
overrideGroupName = 'iframes';
}
if (type === 'asset' || type === 'iframe') {
overrideGroupName =
overrideGroupName ?? mapped.groupName.split('/').at(-1);
}
if (type === 'measure' &&
(entry.span.name.endsWith('/tti') || entry.span.name.endsWith('/ttr'))) {
// remove suffix from measure name
overrideGroupName = entry.span.name.split('/').slice(0, -1).join('/');
}
if (entry.span.name.startsWith('https://')) {
const shortenedName = entry.span.name.split('zendesk.com').at(-1);
if (mapped.span.attributes?.initiatorType === 'xmlhttprequest') {
overrideGroupName = collapseEmberResources
? 'ember-resource'
: overrideGroupName ?? shortenedName;
type = 'resource-ember';
}
if (type === 'resource') {
overrideGroupName = overrideGroupName ?? shortenedName;
}
}
return {
...mapped,
overrideGroupName,
type,
};
});
const mappedEntries = preMappedEntries.map((mapped, idx) => {
if (mapped.groupName.startsWith('graphql/')) {
const clientName = mapped.span.attributes?.apolloClientName;
const commonName = mapped.overrideGroupName ?? mapped.groupName;
if (clientName === 'local' && mapped.span.attributes?.feature) {
const { feature } = mapped.span.attributes;
const matchingResourceTask = preMappedEntries.find((t) => t.span.attributes?.feature === feature && t.type === 'resource');
if (matchingResourceTask) {
matchingResourceTask.groupName = commonName;
}
return {
...mapped,
groupName: commonName,
type: 'resource',
};
}
return {
...mapped,
groupName: commonName,
type: 'resource',
};
}
return {
...mapped,
groupName: mapped.overrideGroupName ?? mapped.groupName,
};
});
const entriesFromComputedSpans = Object.entries(traceRecording.computedSpans).map(([name, computedSpan]) => ({
groupName: name,
type: 'computed-span',
span: {
type: 'computed-span',
duration: computedSpan.duration,
name,
startTime: (0, ensureTimestamp_1.adjustTimestampBy)(traceRecording.startTime, computedSpan.startOffset),
relatedTo: traceRecording.relatedTo,
},
annotation: {
id: traceRecording.id,
occurrence: 1,
operationRelativeStartTime: computedSpan.startOffset,
operationRelativeEndTime: computedSpan.startOffset + computedSpan.duration,
},
}));
const entriesWithComputedSpans = [
...mappedEntries,
...entriesFromComputedSpans,
].sort((a, b) => {
const orderA = order[a.type] ?? 100;
const orderB = order[b.type] ?? 100;
return orderA - orderB;
});
const spansWithDuration = entriesWithComputedSpans
.filter((task) => task.span.duration > 0)
.filter((task) => (displayResources || task.type !== 'resource') &&
(displayMeasures || task.type !== 'measure'));
const spanEvents = entriesWithComputedSpans.filter((entry) => entry.span.duration === 0);
const spanTypes = new Set(spansWithDuration.map((entry) => entry.type));
const uniqueGroups = [
...new Set(spansWithDuration.map((task) => task.groupName)),
];
return {
name: traceRecording.name,
spansWithDuration,
uniqueGroups,
spanEvents,
spanTypes,
duration: traceRecording.duration ??
traceRecording.entries.at(-1)?.annotation.operationRelativeEndTime ??
0,
};
};
exports.mapOperationForVisualization = mapOperationForVisualization;
//# sourceMappingURL=mapOperationForVisualization.js.map
;