Skip to content

Commit cb00d62

Browse files
authored
feat(rca): Fetch regression data from events endpoint (#68286)
If the flag is present, call the hook to fetch data from the events endpoint with span metrics data instead.
1 parent b07d487 commit cb00d62

File tree

2 files changed

+96
-7
lines changed

2 files changed

+96
-7
lines changed

static/app/components/events/eventStatisticalDetector/aggregateSpanDiff.tsx

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import {t} from 'sentry/locale';
77
import type {Event, Project} from 'sentry/types';
88
import {useRelativeDateTime} from 'sentry/utils/profiling/hooks/useRelativeDateTime';
99
import {useApiQuery} from 'sentry/utils/queryClient';
10+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
1011
import {useLocation} from 'sentry/utils/useLocation';
1112
import useOrganization from 'sentry/utils/useOrganization';
1213
import {spanDetailsRouteWithQuery} from 'sentry/views/performance/transactionSummary/transactionSpans/spanDetails/utils';
14+
import {useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
1315

1416
import {EventRegressionTable} from './eventRegressionTable';
1517

@@ -26,6 +28,7 @@ interface SpanDiff {
2628

2729
interface UseFetchAdvancedAnalysisProps {
2830
breakpoint: string;
31+
enabled: boolean;
2932
end: string;
3033
projectId: string;
3134
start: string;
@@ -38,6 +41,7 @@ function useFetchAdvancedAnalysis({
3841
end,
3942
breakpoint,
4043
projectId,
44+
enabled,
4145
}: UseFetchAdvancedAnalysisProps) {
4246
const organization = useOrganization();
4347
return useApiQuery<SpanDiff[]>(
@@ -57,6 +61,7 @@ function useFetchAdvancedAnalysis({
5761
{
5862
staleTime: 60000,
5963
retry: false,
64+
enabled,
6065
}
6166
);
6267
}
@@ -74,6 +79,9 @@ interface AggregateSpanDiffProps {
7479
function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
7580
const location = useLocation();
7681
const organization = useOrganization();
82+
const isSpansOnly = organization.features.includes(
83+
'statistical-detectors-rca-spans-only'
84+
);
7785

7886
const [causeType, setCauseType] = useState<'duration' | 'throughput'>('duration');
7987

@@ -85,17 +93,83 @@ function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
8593
relativeDays: 7,
8694
retentionDays: 30,
8795
});
88-
const {data, isLoading, isError} = useFetchAdvancedAnalysis({
96+
97+
const {
98+
data: rcaData,
99+
isLoading: isRcaLoading,
100+
isError: isRcaError,
101+
} = useFetchAdvancedAnalysis({
89102
transaction,
90103
start: (start as Date).toISOString(),
91104
end: (end as Date).toISOString(),
92105
breakpoint: breakpointTimestamp,
93106
projectId: project.id,
107+
enabled: !isSpansOnly,
108+
});
109+
110+
// Initialize the search query with has:span.group because only
111+
// specific operations have their span.group recorded in the span
112+
// metrics dataset
113+
const search = new MutableSearch('has:span.group');
114+
search.addFilterValue('transaction', transaction);
115+
116+
const {
117+
data: spansData,
118+
isLoading: isSpansDataLoading,
119+
isError: isSpansDataError,
120+
} = useSpanMetrics({
121+
search,
122+
fields: [
123+
'span.op',
124+
'any(span.description)',
125+
'span.group',
126+
`regression_score(span.self_time,${breakpoint})`,
127+
`avg_by_timestamp(span.self_time,less,${breakpoint})`,
128+
`avg_by_timestamp(span.self_time,greater,${breakpoint})`,
129+
`epm_by_timestamp(less,${breakpoint})`,
130+
`epm_by_timestamp(greater,${breakpoint})`,
131+
],
132+
sorts: [{field: `regression_score(span.self_time,${breakpoint})`, kind: 'desc'}],
133+
limit: 10,
134+
enabled: isSpansOnly,
135+
referrer: 'api.performance.transactions.statistical-detector-root-cause-analysis',
94136
});
95137

96138
const tableData = useMemo(() => {
139+
if (isSpansOnly) {
140+
return spansData?.map(row => {
141+
const commonProps = {
142+
operation: row['span.op'],
143+
group: row['span.group'],
144+
description: row['any(span.description)'] || undefined,
145+
};
146+
147+
if (causeType === 'throughput') {
148+
const throughputBefore = row[`epm_by_timestamp(less,${breakpoint})`];
149+
const throughputAfter = row[`epm_by_timestamp(greater,${breakpoint})`];
150+
return {
151+
...commonProps,
152+
throughputBefore,
153+
throughputAfter,
154+
percentageChange: throughputAfter / throughputBefore - 1,
155+
};
156+
}
157+
158+
const durationBefore =
159+
row[`avg_by_timestamp(span.self_time,less,${breakpoint})`] / 1e3;
160+
const durationAfter =
161+
row[`avg_by_timestamp(span.self_time,greater,${breakpoint})`] / 1e3;
162+
return {
163+
...commonProps,
164+
durationBefore,
165+
durationAfter,
166+
percentageChange: durationAfter / durationBefore - 1,
167+
};
168+
});
169+
}
170+
97171
return (
98-
data?.map(row => {
172+
rcaData?.map(row => {
99173
if (causeType === 'throughput') {
100174
return {
101175
operation: row.span_op,
@@ -106,6 +180,7 @@ function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
106180
percentageChange: row.spm_after / row.spm_before - 1,
107181
};
108182
}
183+
109184
return {
110185
operation: row.span_op,
111186
group: row.span_group,
@@ -116,7 +191,7 @@ function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
116191
};
117192
}) || []
118193
);
119-
}, [data, causeType]);
194+
}, [isSpansOnly, rcaData, spansData, causeType, breakpoint]);
120195

121196
const tableOptions = useMemo(() => {
122197
return {
@@ -153,7 +228,7 @@ function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
153228
onChange={setCauseType}
154229
>
155230
<SegmentedControl.Item key="duration">
156-
{t('Duration (P95)')}
231+
{isSpansOnly ? t('Average Duration') : t('Duration (P95)')}
157232
</SegmentedControl.Item>
158233
<SegmentedControl.Item key="throughput">
159234
{t('Throughput')}
@@ -165,9 +240,8 @@ function AggregateSpanDiff({event, project}: AggregateSpanDiffProps) {
165240
causeType={causeType}
166241
columns={ADDITIONAL_COLUMNS}
167242
data={tableData}
168-
isLoading={isLoading}
169-
isError={isError}
170-
// renderers={renderers}
243+
isLoading={isSpansOnly ? isSpansDataLoading : isRcaLoading}
244+
isError={isSpansOnly ? isSpansDataError : isRcaError}
171245
options={tableOptions}
172246
/>
173247
</EventDataSection>

static/app/views/starfish/types.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ export const SPAN_FUNCTIONS = [
8484
'http_error_count',
8585
] as const;
8686

87+
const BREAKPOINT_CONDITIONS = ['less', 'greater'] as const;
88+
type BreakpointCondition = (typeof BREAKPOINT_CONDITIONS)[number];
89+
90+
type RegressionFunctions = [
91+
`regression_score(${string},${string})`,
92+
`avg_by_timestamp(${string},${BreakpointCondition},${string})`,
93+
`epm_by_timestamp(${BreakpointCondition},${string})`,
94+
][number];
95+
96+
type SpanAnyFunction = `any(${string})`;
97+
8798
export type SpanFunctions = (typeof SPAN_FUNCTIONS)[number];
8899

89100
export type MetricsResponse = {
@@ -102,6 +113,10 @@ export type MetricsResponse = {
102113
'http_response_rate(5)': number;
103114
} & {
104115
['project.id']: number;
116+
} & {
117+
[Function in RegressionFunctions]: number;
118+
} & {
119+
[Function in SpanAnyFunction]: string;
105120
};
106121

107122
export type MetricsFilters = {

0 commit comments

Comments
 (0)