123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import type {Measurement} from 'sentry/types/event';
- import {MobileVital, WebVital} from 'sentry/utils/fields';
- import {
- MOBILE_VITAL_DETAILS,
- WEB_VITAL_DETAILS,
- } from 'sentry/utils/performance/vitals/constants';
- import type {Vital} from 'sentry/utils/performance/vitals/types';
- import type {TraceTree} from './traceTree';
- import type {TraceTreeNode} from './traceTreeNode';
- // cls is not included as it is a cumulative layout shift and not a single point in time
- const RENDERABLE_MEASUREMENTS = [
- WebVital.TTFB,
- WebVital.FP,
- WebVital.FCP,
- WebVital.LCP,
- MobileVital.TIME_TO_FULL_DISPLAY,
- MobileVital.TIME_TO_INITIAL_DISPLAY,
- ]
- .map(n => n.replace('measurements.', ''))
- .reduce((acc, curr) => {
- acc[curr] = true;
- return acc;
- }, {});
- const WEB_VITALS = [
- WebVital.TTFB,
- WebVital.FP,
- WebVital.FCP,
- WebVital.LCP,
- WebVital.CLS,
- WebVital.FID,
- WebVital.INP,
- WebVital.REQUEST_TIME,
- ].map(n => n.replace('measurements.', ''));
- const MOBILE_VITALS = [
- MobileVital.APP_START_COLD,
- MobileVital.APP_START_WARM,
- MobileVital.TIME_TO_INITIAL_DISPLAY,
- MobileVital.TIME_TO_FULL_DISPLAY,
- MobileVital.FRAMES_TOTAL,
- MobileVital.FRAMES_SLOW,
- MobileVital.FRAMES_FROZEN,
- MobileVital.FRAMES_SLOW_RATE,
- MobileVital.FRAMES_FROZEN_RATE,
- MobileVital.STALL_COUNT,
- MobileVital.STALL_TOTAL_TIME,
- MobileVital.STALL_LONGEST_TIME,
- MobileVital.STALL_PERCENTAGE,
- ].map(n => n.replace('measurements.', ''));
- const WEB_VITALS_LOOKUP = new Set<string>(WEB_VITALS);
- const MOBILE_VITALS_LOOKUP = new Set<string>(MOBILE_VITALS);
- const COLLECTABLE_MEASUREMENTS = [...WEB_VITALS, ...MOBILE_VITALS].map(n =>
- n.replace('measurements.', '')
- );
- const MEASUREMENT_ACRONYM_MAPPING = {
- [MobileVital.TIME_TO_FULL_DISPLAY.replace('measurements.', '')]: 'TTFD',
- [MobileVital.TIME_TO_INITIAL_DISPLAY.replace('measurements.', '')]: 'TTID',
- };
- const MEASUREMENT_THRESHOLDS = {
- [WebVital.TTFB.replace('measurements.', '')]: 600,
- [WebVital.FP.replace('measurements.', '')]: 3000,
- [WebVital.FCP.replace('measurements.', '')]: 3000,
- [WebVital.LCP.replace('measurements.', '')]: 4000,
- [MobileVital.TIME_TO_INITIAL_DISPLAY.replace('measurements.', '')]: 2000,
- };
- export const TRACE_MEASUREMENT_LOOKUP: Record<string, Vital> = {};
- for (const key in {...MOBILE_VITAL_DETAILS, ...WEB_VITAL_DETAILS}) {
- TRACE_MEASUREMENT_LOOKUP[key.replace('measurements.', '')] = {
- ...MOBILE_VITAL_DETAILS[key],
- ...WEB_VITAL_DETAILS[key],
- };
- }
- function traceMeasurementToTimestamp(
- start_timestamp: number,
- measurement: number,
- unit: string
- ) {
- if (unit === 'second') {
- return (start_timestamp + measurement) * 1e3;
- }
- if (unit === 'millisecond') {
- return start_timestamp + measurement;
- }
- if (unit === 'nanosecond') {
- return (start_timestamp + measurement) * 1e-6;
- }
- throw new TypeError(`Unsupported measurement unit', ${unit}`);
- }
- // Collects measurements from a trace node and adds them to the indicators stored on trace tree
- export function collectTraceMeasurements(
- node: TraceTreeNode<TraceTree.NodeValue>,
- start_timestamp: number,
- measurements: Record<string, Measurement> | undefined,
- vitals: Map<TraceTreeNode<TraceTree.NodeValue>, TraceTree.CollectedVital[]>,
- vital_types: Set<'web' | 'mobile'>
- ): TraceTree.Indicator[] {
- const indicators: TraceTree.Indicator[] = [];
- if (!measurements) {
- return indicators;
- }
- for (const measurement of COLLECTABLE_MEASUREMENTS) {
- const value = measurements[measurement];
- if (!value || typeof value.value !== 'number') {
- continue;
- }
- if (!vitals.has(node)) {
- vitals.set(node, []);
- }
- WEB_VITALS_LOOKUP.has(measurement) && vital_types.add('web');
- MOBILE_VITALS_LOOKUP.has(measurement) && vital_types.add('mobile');
- const vital = vitals.get(node)!;
- vital.push({
- key: measurement,
- measurement: value,
- });
- if (!RENDERABLE_MEASUREMENTS[measurement]) {
- continue;
- }
- const timestamp = traceMeasurementToTimestamp(
- start_timestamp,
- value.value,
- value.unit ?? 'millisecond'
- );
- indicators.push({
- start: timestamp,
- duration: 0,
- measurement: value,
- poor: MEASUREMENT_THRESHOLDS[measurement]
- ? value.value > MEASUREMENT_THRESHOLDS[measurement]
- : false,
- type: measurement as TraceTree.Indicator['type'],
- label: (MEASUREMENT_ACRONYM_MAPPING[measurement] ?? measurement).toUpperCase(),
- });
- }
- return indicators;
- }
|