Skip to content

Commit e54d9f4

Browse files
authored
ref(insights): perform one query per queue module chart (#92407)
This pr updates the queue module to make one query per chart. This will make it easer to link insights -> explore The data before and after is equivalent Before ![image](https://github.com/user-attachments/assets/8bf64a9d-8005-4382-bea1-93e3108d4b58) After ![image](https://github.com/user-attachments/assets/51d0599d-b487-499b-b096-fa2873f2fb85)
1 parent 95fb310 commit e54d9f4

15 files changed

+133
-164
lines changed

static/app/components/charts/chartWidgetLoader-unmocked-imports.spec.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,6 @@ jest.mock(
120120
})),
121121
})
122122
);
123-
jest.mock('sentry/views/insights/queues/queries/usePublishQueuesTimeSeriesQuery', () => ({
124-
usePublishQueuesTimeSeriesQuery: jest.fn(() => ({
125-
data: {},
126-
isPending: false,
127-
error: null,
128-
})),
129-
}));
130-
jest.mock('sentry/views/insights/queues/queries/useProcessQueuesTimeSeriesQuery', () => ({
131-
useProcessQueuesTimeSeriesQuery: jest.fn(() => ({
132-
data: {
133-
'avg(messaging.message.receive.latency)': {},
134-
},
135-
isPending: false,
136-
error: null,
137-
})),
138-
}));
139123
jest.mock(
140124
'sentry/views/insights/common/components/widgets/hooks/useDatabaseLandingDurationQuery',
141125
() => ({
@@ -210,6 +194,11 @@ jest.mock('sentry/views/insights/common/queries/useTopNDiscoverSeries', () => ({
210194
isPending: false,
211195
error: null,
212196
})),
197+
useTopNSpanMetricsSeries: jest.fn(() => ({
198+
data: [mockDiscoverSeries('transaction_a,abc123')],
199+
isPending: false,
200+
error: null,
201+
})),
213202
}));
214203
jest.mock('sentry/views/insights/common/queries/useDiscoverSeries', () => ({
215204
useEAPSeries: jest.fn(() => ({
@@ -259,6 +248,7 @@ jest.mock('sentry/views/insights/common/queries/useDiscoverSeries', () => ({
259248
'avg(http.response_content_length)': {},
260249
'avg(http.response_transfer_size)': {},
261250
'avg(http.decoded_response_content_length)': {},
251+
'avg(messaging.message.receive.latency)': {},
262252
},
263253
isPending: false,
264254
error: null,

static/app/views/insights/common/components/insightsTimeSeriesWidget.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function InsightsTimeSeriesWidget(props: InsightsTimeSeriesWidgetProps) {
7979

8080
const hasChartActionsEnabled =
8181
organization.features.includes('insights-chart-actions') && useEap;
82-
const yAxes: string[] = [];
82+
const yAxes = new Set<string>();
8383

8484
const visualizationProps: TimeSeriesWidgetVisualizationProps = {
8585
showLegend: props.showLegend,
@@ -95,7 +95,8 @@ export function InsightsTimeSeriesWidget(props: InsightsTimeSeriesWidgetProps) {
9595
? Area
9696
: Bars;
9797

98-
yAxes.push(timeSeries.yAxis);
98+
// yAxis should not contain whitespace, some yAxes are like `epm() span.op:queue.publish`
99+
yAxes.add(timeSeries?.yAxis?.split(' ')[0] ?? '');
99100

100101
return new PlottableDataConstructor(timeSeries, {
101102
color: serie.color ?? COMMON_COLORS(theme)[timeSeries.yAxis],
@@ -164,6 +165,8 @@ export function InsightsTimeSeriesWidget(props: InsightsTimeSeriesWidgetProps) {
164165
chartType = ChartType.BAR;
165166
}
166167

168+
const yAxisArray = [...yAxes];
169+
167170
return (
168171
<ChartContainer height={props.height}>
169172
<Widget
@@ -187,13 +190,13 @@ export function InsightsTimeSeriesWidget(props: InsightsTimeSeriesWidgetProps) {
187190
{hasChartActionsEnabled && (
188191
<OpenInExploreButton
189192
chartType={chartType}
190-
yAxes={yAxes}
193+
yAxes={yAxisArray}
191194
title={props.title}
192195
search={props.search}
193196
/>
194197
)}
195198
{hasChartActionsEnabled && (
196-
<CreateAlertButton yAxis={yAxes[0]} search={props.search} />
199+
<CreateAlertButton yAxis={yAxisArray[0]} search={props.search} />
197200
)}
198201
{props.loaderSource !== 'releases-drawer' && (
199202
<Button

static/app/views/insights/common/components/widgets/queuesLandingLatencyChartWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default function QueuesLandingLatencyChartWidget(props: LoadableChartWidg
77
<LatencyChart
88
{...props}
99
id="queuesLandingLatencyChartWidget"
10-
referrer={Referrer.QUEUES_LANDING_CHARTS}
10+
referrer={Referrer.QUEUE_LANDING_LATENCY_CHART}
1111
/>
1212
);
1313
}

static/app/views/insights/common/components/widgets/queuesLandingThroughputChartWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function QueuesLandingThroughputChartWidget(
99
<ThroughputChart
1010
{...props}
1111
id="queuesLandingThroughputChartWidget"
12-
referrer={Referrer.QUEUES_LANDING_CHARTS}
12+
referrer={Referrer.QUEUE_LANDING_THROUGHPUT_CHART}
1313
/>
1414
);
1515
}

static/app/views/insights/common/components/widgets/queuesSummaryLatencyChartWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function QueuesSummaryLatencyChartWidget(props: LoadableChartWidg
1515
<LatencyChart
1616
{...props}
1717
id="queuesSummaryLatencyChartWidget"
18-
referrer={Referrer.QUEUES_SUMMARY_CHARTS}
18+
referrer={Referrer.QUEUES_SUMMARY_LATENCY_CHART}
1919
destination={destination}
2020
/>
2121
);

static/app/views/insights/common/components/widgets/queuesSummaryThroughputChartWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function QueuesSummaryThroughputChartWidget(
1717
<ThroughputChart
1818
{...props}
1919
id="queuesSummaryThroughputChartWidget"
20-
referrer={Referrer.QUEUES_SUMMARY_CHARTS}
20+
referrer={Referrer.QUEUES_SUMMARY_THROUGHPUT_CHART}
2121
destination={destination}
2222
/>
2323
);

static/app/views/insights/queues/charts/latencyChart.spec.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('latencyChart', () => {
4747
<LatencyChart
4848
id="latency-chart-test"
4949
destination="events"
50-
referrer={Referrer.QUEUES_SUMMARY_CHARTS}
50+
referrer={Referrer.QUEUES_SUMMARY_LATENCY_CHART}
5151
/>,
5252
{organization}
5353
);
@@ -56,11 +56,7 @@ describe('latencyChart', () => {
5656
'/organizations/org-slug/events-stats/',
5757
expect.objectContaining({
5858
query: expect.objectContaining({
59-
yAxis: [
60-
'avg(span.duration)',
61-
'avg(messaging.message.receive.latency)',
62-
'epm()',
63-
],
59+
yAxis: ['avg(span.duration)', 'avg(messaging.message.receive.latency)'],
6460
query: 'span.op:queue.process messaging.destination.name:events',
6561
}),
6662
})

static/app/views/insights/queues/charts/latencyChart.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import cloneDeep from 'lodash/cloneDeep';
33
import {t} from 'sentry/locale';
44
import type {PageFilters} from 'sentry/types/core';
55
import {defined} from 'sentry/utils';
6+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
67
// Our loadable chart widgets use this to render, so this import is ok
78
// eslint-disable-next-line no-restricted-imports
89
import {InsightsAreaChartWidget} from 'sentry/views/insights/common/components/insightsAreaChartWidget';
9-
import {useProcessQueuesTimeSeriesQuery} from 'sentry/views/insights/queues/queries/useProcessQueuesTimeSeriesQuery';
10+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
1011
import type {Referrer} from 'sentry/views/insights/queues/referrers';
1112
import {FIELD_ALIASES} from 'sentry/views/insights/queues/settings';
1213

@@ -19,15 +20,24 @@ interface Props {
1920
}
2021

2122
export function LatencyChart({id, error, destination, referrer, pageFilters}: Props) {
23+
const search = new MutableSearch('span.op:queue.process');
24+
if (destination) {
25+
search.addFilterValue('messaging.destination.name', destination, false);
26+
}
27+
2228
const {
2329
data,
2430
isPending,
2531
error: latencyError,
26-
} = useProcessQueuesTimeSeriesQuery({
27-
destination,
32+
} = useSpanMetricsSeries(
33+
{
34+
yAxis: ['avg(span.duration)', 'avg(messaging.message.receive.latency)'],
35+
search,
36+
transformAliasToInputFormat: true,
37+
},
2838
referrer,
29-
pageFilters,
30-
});
39+
pageFilters
40+
);
3141

3242
const messageReceiveLatencySeries = cloneDeep(
3343
data['avg(messaging.message.receive.latency)']
@@ -58,6 +68,7 @@ export function LatencyChart({id, error, destination, referrer, pageFilters}: Pr
5868
return (
5969
<InsightsAreaChartWidget
6070
id={id}
71+
search={search}
6172
title={t('Average Duration')}
6273
series={[messageReceiveLatencySeries, data['avg(span.duration)']]}
6374
aliases={FIELD_ALIASES}

static/app/views/insights/queues/charts/throughputChart.spec.tsx

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,22 @@ describe('throughputChart', () => {
2626
url: `/organizations/${organization.slug}/events-stats/`,
2727
method: 'GET',
2828
body: {
29-
data: [[1739378162, [{count: 1}]]],
29+
'queue.process': {
30+
data: [[1739378162, [{count: 1}]]],
31+
meta: {fields: {epm: 'rate'}, units: {epm: '1/second'}},
32+
},
33+
'queue.publish': {
34+
data: [[1739378162, [{count: 1}]]],
35+
meta: {fields: {epm: 'rate'}, units: {epm: '1/second'}},
36+
},
3037
},
3138
});
3239
});
3340
it('renders', async () => {
3441
render(
3542
<ThroughputChart
3643
id="throughput-chart-test"
37-
referrer={Referrer.QUEUES_SUMMARY_CHARTS}
44+
referrer={Referrer.QUEUES_SUMMARY_THROUGHPUT_CHART}
3845
/>,
3946
{organization}
4047
);
@@ -43,21 +50,10 @@ describe('throughputChart', () => {
4350
'/organizations/org-slug/events-stats/',
4451
expect.objectContaining({
4552
query: expect.objectContaining({
46-
yAxis: [
47-
'avg(span.duration)',
48-
'avg(messaging.message.receive.latency)',
49-
'epm()',
50-
],
51-
query: 'span.op:queue.process',
52-
}),
53-
})
54-
);
55-
expect(eventsStatsMock).toHaveBeenCalledWith(
56-
'/organizations/org-slug/events-stats/',
57-
expect.objectContaining({
58-
query: expect.objectContaining({
59-
yAxis: ['avg(span.duration)', 'epm()'],
60-
query: 'span.op:queue.publish',
53+
yAxis: 'epm()',
54+
field: ['epm()', 'span.op'],
55+
topEvents: '2',
56+
query: 'span.op:[queue.publish, queue.process]',
6157
}),
6258
})
6359
);

static/app/views/insights/queues/charts/throughputChart.tsx

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import {useTheme} from '@emotion/react';
22

33
import {t} from 'sentry/locale';
44
import type {PageFilters} from 'sentry/types/core';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
// Our loadable chart widgets use this to render, so this import is ok
67
// eslint-disable-next-line no-restricted-imports
78
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
9+
import type {DiscoverSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
10+
import {useTopNSpanMetricsSeries} from 'sentry/views/insights/common/queries/useTopNDiscoverSeries';
811
import {renameDiscoverSeries} from 'sentry/views/insights/common/utils/renameDiscoverSeries';
9-
import {useProcessQueuesTimeSeriesQuery} from 'sentry/views/insights/queues/queries/useProcessQueuesTimeSeriesQuery';
10-
import {usePublishQueuesTimeSeriesQuery} from 'sentry/views/insights/queues/queries/usePublishQueuesTimeSeriesQuery';
1112
import type {Referrer} from 'sentry/views/insights/queues/referrers';
1213
import {FIELD_ALIASES} from 'sentry/views/insights/queues/settings';
14+
import type {SpanQueryFilters} from 'sentry/views/insights/types';
1315

1416
interface Props {
1517
id: string;
@@ -21,50 +23,65 @@ interface Props {
2123

2224
export function ThroughputChart({id, error, destination, pageFilters, referrer}: Props) {
2325
const theme = useTheme();
24-
const {
25-
data: publishData,
26-
error: publishError,
27-
isPending: isPublishDataLoading,
28-
} = usePublishQueuesTimeSeriesQuery({
29-
destination,
30-
referrer,
31-
pageFilters,
32-
});
26+
27+
const search = MutableSearch.fromQueryObject({
28+
'span.op': '[queue.publish, queue.process]',
29+
} satisfies SpanQueryFilters);
30+
31+
if (destination) {
32+
search.addFilterValue('messaging.destination.name', destination, false);
33+
}
3334

3435
const {
35-
data: processData,
36-
error: processError,
37-
isPending: isProcessDataLoading,
38-
} = useProcessQueuesTimeSeriesQuery({
39-
destination,
36+
data,
37+
error: topNError,
38+
isLoading,
39+
} = useTopNSpanMetricsSeries(
40+
{
41+
search,
42+
yAxis: ['epm()'],
43+
fields: ['epm()', 'span.op'],
44+
topN: 2,
45+
transformAliasToInputFormat: true,
46+
},
4047
referrer,
41-
pageFilters,
42-
});
48+
pageFilters
49+
);
50+
51+
const publishData: DiscoverSeries = data.find(
52+
(d): d is DiscoverSeries => d.seriesName === 'queue.publish'
53+
) ?? {data: [], seriesName: 'queue.publish', meta: {fields: {}, units: {}}};
54+
55+
const processData: DiscoverSeries = data.find(
56+
(d): d is DiscoverSeries => d.seriesName === 'queue.process'
57+
) ?? {data: [], seriesName: 'queue.process', meta: {fields: {}, units: {}}};
4358

4459
const colors = theme.chart.getColorPalette(2);
60+
4561
return (
4662
<InsightsLineChartWidget
4763
id={id}
64+
search={search}
4865
title={t('Published vs Processed')}
4966
series={[
5067
renameDiscoverSeries(
5168
{
52-
...publishData['epm()'],
69+
...publishData,
5370
color: colors[1],
5471
},
5572
'epm() span.op:queue.publish'
5673
),
5774
renameDiscoverSeries(
5875
{
59-
...processData['epm()'],
76+
...processData,
6077
color: colors[2],
6178
},
6279
'epm() span.op:queue.process'
6380
),
6481
]}
6582
aliases={FIELD_ALIASES}
66-
isLoading={isPublishDataLoading || isProcessDataLoading}
67-
error={error ?? processError ?? publishError}
83+
isLoading={isLoading}
84+
error={error ?? topNError}
6885
/>
6986
);
7087
}

static/app/views/insights/queues/queries/useProcessQueuesTimeSeriesQuery.tsx

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)