From 5a27736eed1338ac1cb28f82b1e8f31b443f122e Mon Sep 17 00:00:00 2001 From: k-fish Date: Fri, 24 Jun 2022 12:17:00 -0400 Subject: [PATCH] ref(perf): Add perf asset collection This adds some new measurements to collect assets for a page, only if one of the components is wrapped with the provided component from performanceForSentry. This is an experiment to check the usefulness of asset measurement in code, we can extend this into the sdk once we work out any issues with this approach. --- static/app/utils/performanceForSentry.tsx | 79 +++++++++++++++++++++++ static/app/views/performance/content.tsx | 39 +++++------ 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/static/app/utils/performanceForSentry.tsx b/static/app/utils/performanceForSentry.tsx index 91a7f46336c49d..c9f0f82ad09518 100644 --- a/static/app/utils/performanceForSentry.tsx +++ b/static/app/utils/performanceForSentry.tsx @@ -309,3 +309,82 @@ export const VisuallyCompleteWithData = ({ ); }; + +interface OpAssetMeasurementDefinition { + key: string; +} + +const OP_ASSET_MEASUREMENT_MAP: Record = { + 'resource.script': { + key: 'script', + }, + 'resource.css': { + key: 'css', + }, + 'resource.link': { + key: 'link', + }, + 'resource.img': { + key: 'img', + }, +}; +const ASSET_MEASUREMENT_ALL = 'allResources'; + +export const MeasureAssetsOnTransaction = ({children}: {children: ReactNode}) => { + useEffect(() => { + try { + const transaction: any = getCurrentSentryReactTransaction(); // Using any to override types for private api. + if (!transaction) { + return; + } + + transaction.registerBeforeFinishCallback((t: Transaction) => { + const spans: any[] = (t as any).spanRecorder?.spans; + const measurements = (t as any)._measurements; + + if (!spans) { + return; + } + + if (measurements[ASSET_MEASUREMENT_ALL]) { + return; + } + + let allTransfered = 0; + let allEncoded = 0; + let allCount = 0; + + for (const [op, definition] of Object.entries(OP_ASSET_MEASUREMENT_MAP)) { + const filtered = spans.filter(s => s.op === op); + const count = filtered.length; + const transfered = filtered.reduce( + (acc, curr) => acc + curr.data['Transfer Size'] ?? 0, + 0 + ); + const encoded = filtered.reduce( + (acc, curr) => acc + curr.data['Encoded Body Size'] ?? 0, + 0 + ); + + if (op === 'resource.script') { + t.setMeasurement(`assets.${definition.key}.encoded`, encoded, ''); + t.setMeasurement(`assets.${definition.key}.transfer`, transfered, ''); + t.setMeasurement(`assets.${definition.key}.count`, count, ''); + } + + allCount += count; + allTransfered += transfered; + allEncoded += encoded; + } + + t.setMeasurement(`${ASSET_MEASUREMENT_ALL}.encoded`, allEncoded, ''); + t.setMeasurement(`${ASSET_MEASUREMENT_ALL}.transfer`, allTransfered, ''); + t.setMeasurement(`${ASSET_MEASUREMENT_ALL}.count`, allCount, ''); + }); + } catch (_) { + // Defensive catch since this code is auxiliary. + } + }, []); + + return {children}; +}; diff --git a/static/app/views/performance/content.tsx b/static/app/views/performance/content.tsx index 42e42e35c075cf..49e044fb2962d7 100644 --- a/static/app/views/performance/content.tsx +++ b/static/app/views/performance/content.tsx @@ -13,6 +13,7 @@ import {PageFilters, Project} from 'sentry/types'; import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent'; import {MEPSettingProvider} from 'sentry/utils/performance/contexts/metricsEnhancedSetting'; import {PerformanceEventViewProvider} from 'sentry/utils/performance/contexts/performanceEventViewContext'; +import {MeasureAssetsOnTransaction} from 'sentry/utils/performanceForSentry'; import useApi from 'sentry/utils/useApi'; import useOrganization from 'sentry/utils/useOrganization'; import usePrevious from 'sentry/utils/usePrevious'; @@ -159,24 +160,26 @@ function PerformanceContent({selection, location, demoMode}: Props) { }, }} > - - handleTrendsClick({ - location, - organization, - projectPlatforms: getSelectedProjectPlatforms(location, projects), - }) - } - onboardingProject={onboardingProject} - organization={organization} - location={location} - projects={projects} - selection={selection} - withStaticFilters={withStaticFilters} - /> + + + handleTrendsClick({ + location, + organization, + projectPlatforms: getSelectedProjectPlatforms(location, projects), + }) + } + onboardingProject={onboardingProject} + organization={organization} + location={location} + projects={projects} + selection={selection} + withStaticFilters={withStaticFilters} + /> +