Skip to content

Commit 1fc6995

Browse files
feat(webvitals): Escape webvital query filters using MutableSearch (#68220)
Transaction names with asterisks break queries in the page overview. This fix escapes asterisks in transaction names before querying.
1 parent 01a022a commit 1fc6995

10 files changed

+137
-34
lines changed

static/app/views/performance/browser/webVitals/pageOverview.spec.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,57 @@ describe('PageOverview', function () {
131131
)
132132
);
133133
});
134+
135+
it('escapes transaction name before querying discover', async () => {
136+
const organizationWithInp = OrganizationFixture({
137+
features: [
138+
'starfish-browser-webvitals',
139+
'performance-database-view',
140+
'starfish-browser-webvitals-replace-fid-with-inp',
141+
],
142+
});
143+
jest.mocked(useOrganization).mockReturnValue(organizationWithInp);
144+
jest.mocked(useLocation).mockReturnValue({
145+
pathname: '',
146+
search: '',
147+
query: {
148+
useStoredScores: 'true',
149+
transaction: '/page-with-a-*/',
150+
type: 'interactions',
151+
},
152+
hash: '',
153+
state: undefined,
154+
action: 'PUSH',
155+
key: '',
156+
});
157+
render(<PageOverview />);
158+
await waitFor(() =>
159+
expect(eventsMock).toHaveBeenCalledWith(
160+
'/organizations/org-slug/events/',
161+
expect.objectContaining({
162+
query: expect.objectContaining({
163+
dataset: 'spansIndexed',
164+
field: [
165+
'measurements.inp',
166+
'measurements.score.inp',
167+
'measurements.score.weight.inp',
168+
'measurements.score.total',
169+
'span_id',
170+
'timestamp',
171+
'profile_id',
172+
'replay.id',
173+
'user',
174+
'origin.transaction',
175+
'project',
176+
'browser.name',
177+
'span.self_time',
178+
'span.description',
179+
],
180+
query:
181+
'span.op:ui.interaction.click measurements.score.weight.inp:>0 origin.transaction:"/page-with-a-\\*/"',
182+
}),
183+
})
184+
)
185+
);
186+
});
134187
});

static/app/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useProjectRawWebVitalsQuery.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {Tag} from 'sentry/types';
22
import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
33
import EventView from 'sentry/utils/discover/eventView';
44
import {DiscoverDatasets} from 'sentry/utils/discover/types';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -16,6 +17,13 @@ export const useProjectRawWebVitalsQuery = ({transaction, tag, dataset}: Props =
1617
const organization = useOrganization();
1718
const pageFilters = usePageFilters();
1819
const location = useLocation();
20+
const search = new MutableSearch([]);
21+
if (transaction) {
22+
search.addFilterValue('transaction', transaction);
23+
}
24+
if (tag) {
25+
search.addFilterValue(tag.key, tag.name);
26+
}
1927

2028
const projectEventView = EventView.fromNewQueryWithPageFilters(
2129
{
@@ -38,9 +46,10 @@ export const useProjectRawWebVitalsQuery = ({transaction, tag, dataset}: Props =
3846
query: [
3947
'transaction.op:[pageload,""]',
4048
'span.op:[ui.interaction.click,""]',
41-
...(transaction ? [`transaction:"${transaction}"`] : []),
42-
...(tag ? [`{tag.key}:"${tag.name}"`] : []),
43-
].join(' '),
49+
search.formatString(),
50+
]
51+
.join(' ')
52+
.trim(),
4453
version: 2,
4554
dataset: dataset ?? DiscoverDatasets.METRICS,
4655
},

static/app/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useProjectRawWebVitalsTimeseriesQuery.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import EventView from 'sentry/utils/discover/eventView';
66
import type {DiscoverQueryProps} from 'sentry/utils/discover/genericDiscoverQuery';
77
import {useGenericDiscoverQuery} from 'sentry/utils/discover/genericDiscoverQuery';
88
import {DiscoverDatasets} from 'sentry/utils/discover/types';
9+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
910
import {useLocation} from 'sentry/utils/useLocation';
1011
import useOrganization from 'sentry/utils/useOrganization';
1112
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -35,6 +36,13 @@ export const useProjectRawWebVitalsTimeseriesQuery = ({
3536
const pageFilters = usePageFilters();
3637
const location = useLocation();
3738
const organization = useOrganization();
39+
const search = new MutableSearch(['transaction.op:pageload']);
40+
if (transaction) {
41+
search.addFilterValue('transaction', transaction);
42+
}
43+
if (tag) {
44+
search.addFilterValue(tag.key, tag.name);
45+
}
3846
const projectTimeSeriesEventView = EventView.fromNewQueryWithPageFilters(
3947
{
4048
yAxis: [
@@ -46,11 +54,7 @@ export const useProjectRawWebVitalsTimeseriesQuery = ({
4654
'count()',
4755
],
4856
name: 'Web Vitals',
49-
query: [
50-
'transaction.op:pageload',
51-
transaction ? `transaction:"${transaction}"` : '',
52-
tag ? `${tag.key}:"${tag.name}"` : '',
53-
].join(' '),
57+
query: search.formatString(),
5458
version: 2,
5559
fields: [],
5660
interval: getInterval(pageFilters.selection.datetime, 'low'),

static/app/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useProjectRawWebVitalsValuesTimeseriesQuery.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import EventView from 'sentry/utils/discover/eventView';
66
import type {DiscoverQueryProps} from 'sentry/utils/discover/genericDiscoverQuery';
77
import {useGenericDiscoverQuery} from 'sentry/utils/discover/genericDiscoverQuery';
88
import {DiscoverDatasets} from 'sentry/utils/discover/types';
9+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
910
import {useLocation} from 'sentry/utils/useLocation';
1011
import useOrganization from 'sentry/utils/useOrganization';
1112
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -22,6 +23,10 @@ export const useProjectRawWebVitalsValuesTimeseriesQuery = ({
2223
const pageFilters = usePageFilters();
2324
const location = useLocation();
2425
const organization = useOrganization();
26+
const search = new MutableSearch([]);
27+
if (transaction) {
28+
search.addFilterValue('transaction', transaction);
29+
}
2530
const projectTimeSeriesEventView = EventView.fromNewQueryWithPageFilters(
2631
{
2732
yAxis: [
@@ -38,8 +43,10 @@ export const useProjectRawWebVitalsValuesTimeseriesQuery = ({
3843
query: [
3944
'transaction.op:[pageload,""]',
4045
'span.op:[ui.interaction.click,""]',
41-
...(transaction ? [`transaction:"${transaction}"`] : []),
42-
].join(' '),
46+
search.formatString(),
47+
]
48+
.join(' ')
49+
.trim(),
4350
version: 2,
4451
fields: [],
4552
interval: getInterval(pageFilters.selection.datetime, 'low'),

static/app/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useTransactionRawSamplesWebVitalsQuery.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {ReactText} from 'react';
22

33
import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
44
import EventView from 'sentry/utils/discover/eventView';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -73,11 +74,9 @@ export const useTransactionRawSamplesWebVitalsQuery = ({
7374
'project',
7475
],
7576
name: 'Web Vitals',
76-
query: [
77-
'transaction.op:pageload',
78-
`transaction:"${transaction}"`,
79-
...(query ? [query] : []),
80-
].join(' '),
77+
query: new MutableSearch(['transaction.op:pageload', ...(query ? [query] : [])])
78+
.addStringFilter(`transaction:"${transaction}"`)
79+
.formatString(),
8180
orderby: mapWebVitalToOrderBy(orderBy) ?? withProfiles ? '-profile.id' : undefined,
8281
version: 2,
8382
},

static/app/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useTransactionRawWebVitalsQuery.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
22
import EventView from 'sentry/utils/discover/eventView';
33
import type {Sort} from 'sentry/utils/discover/fields';
44
import {DiscoverDatasets} from 'sentry/utils/discover/types';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -32,6 +33,13 @@ export const useTransactionRawWebVitalsQuery = ({
3233

3334
const sort = useWebVitalsSort({sortName, defaultSort});
3435

36+
const search = new MutableSearch([
37+
'transaction.op:pageload',
38+
...(query ? [query] : []),
39+
]);
40+
if (transaction) {
41+
search.addFilterValue('transaction', transaction);
42+
}
3543
const eventView = EventView.fromNewQueryWithPageFilters(
3644
{
3745
fields: [
@@ -50,11 +58,7 @@ export const useTransactionRawWebVitalsQuery = ({
5058
'count()',
5159
],
5260
name: 'Web Vitals',
53-
query: [
54-
'transaction.op:pageload',
55-
...(transaction ? [`transaction:"${transaction}"`] : []),
56-
...(query ? [query] : []),
57-
].join(' '),
61+
query: search.formatString(),
5862
version: 2,
5963
dataset: DiscoverDatasets.METRICS,
6064
},

static/app/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useProjectWebVitalsScoresQuery.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {Tag} from 'sentry/types';
22
import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
33
import EventView from 'sentry/utils/discover/eventView';
44
import {DiscoverDatasets} from 'sentry/utils/discover/types';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -29,6 +30,13 @@ export const useProjectWebVitalsScoresQuery = ({
2930
const shouldReplaceFidWithInp = useReplaceFidWithInpSetting();
3031
const inpOrFid = shouldReplaceFidWithInp ? 'inp' : 'fid';
3132

33+
const search = new MutableSearch([]);
34+
if (transaction) {
35+
search.addFilterValue('transaction', transaction);
36+
}
37+
if (tag) {
38+
search.addFilterValue(tag.key, tag.name);
39+
}
3240
const projectEventView = EventView.fromNewQueryWithPageFilters(
3341
{
3442
fields: [
@@ -58,9 +66,10 @@ export const useProjectWebVitalsScoresQuery = ({
5866
query: [
5967
'transaction.op:[pageload,""]',
6068
'span.op:[ui.interaction.click,""]',
61-
...(transaction ? [`transaction:"${transaction}"`] : []),
62-
...(tag ? [`${tag.key}:"${tag.name}"`] : []),
63-
].join(' '),
69+
search.formatString(),
70+
]
71+
.join(' ')
72+
.trim(),
6473
version: 2,
6574
dataset: dataset ?? DiscoverDatasets.METRICS,
6675
},

static/app/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useProjectWebVitalsScoresTimeseriesQuery.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import EventView from 'sentry/utils/discover/eventView';
66
import type {DiscoverQueryProps} from 'sentry/utils/discover/genericDiscoverQuery';
77
import {useGenericDiscoverQuery} from 'sentry/utils/discover/genericDiscoverQuery';
88
import {DiscoverDatasets} from 'sentry/utils/discover/types';
9+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
910
import {useLocation} from 'sentry/utils/useLocation';
1011
import useOrganization from 'sentry/utils/useOrganization';
1112
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -35,6 +36,13 @@ export const useProjectWebVitalsScoresTimeseriesQuery = ({
3536
const pageFilters = usePageFilters();
3637
const location = useLocation();
3738
const organization = useOrganization();
39+
const search = new MutableSearch([
40+
'has:measurements.score.total',
41+
...(tag ? [`${tag.key}:"${tag.name}"`] : []),
42+
]);
43+
if (transaction) {
44+
search.addFilterValue('transaction', transaction);
45+
}
3846
const projectTimeSeriesEventView = EventView.fromNewQueryWithPageFilters(
3947
{
4048
yAxis: [
@@ -56,10 +64,10 @@ export const useProjectWebVitalsScoresTimeseriesQuery = ({
5664
query: [
5765
'transaction.op:[pageload,""]',
5866
'span.op:[ui.interaction.click,""]',
59-
'has:measurements.score.total',
60-
...(transaction ? [`transaction:"${transaction}"`] : []),
61-
...(tag ? [`${tag.key}:"${tag.name}"`] : []),
62-
].join(' '),
67+
search.formatString(),
68+
]
69+
.join(' ')
70+
.trim(),
6371
version: 2,
6472
fields: [],
6573
interval: getInterval(pageFilters.selection.datetime, 'low'),

static/app/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useTransactionSamplesWebVitalsScoresQuery.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {ReactText} from 'react';
22

33
import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
44
import EventView from 'sentry/utils/discover/eventView';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -78,12 +79,13 @@ export const useTransactionSamplesWebVitalsScoresQuery = ({
7879
: []),
7980
],
8081
name: 'Web Vitals',
81-
query: [
82+
query: new MutableSearch([
8283
'transaction.op:pageload',
83-
`transaction:"${transaction}"`,
8484
'has:measurements.score.total',
8585
...(query ? [query] : []),
86-
].join(' '),
86+
])
87+
.addStringFilter(`transaction:"${transaction}"`)
88+
.formatString(),
8789
orderby: mapWebVitalToOrderBy(orderBy) ?? withProfiles ? '-profile.id' : undefined,
8890
version: 2,
8991
},

static/app/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useTransactionWebVitalsScoresQuery.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
22
import EventView from 'sentry/utils/discover/eventView';
33
import type {Sort} from 'sentry/utils/discover/fields';
44
import {DiscoverDatasets} from 'sentry/utils/discover/types';
5+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
56
import {useLocation} from 'sentry/utils/useLocation';
67
import useOrganization from 'sentry/utils/useOrganization';
78
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -37,6 +38,13 @@ export const useTransactionWebVitalsScoresQuery = ({
3738

3839
const sort = useWebVitalsSort({sortName, defaultSort});
3940

41+
const search = new MutableSearch([
42+
'avg(measurements.score.total):>=0',
43+
...(query ? [query] : []),
44+
]);
45+
if (transaction) {
46+
search.addFilterValue('transaction', transaction);
47+
}
4048
const eventView = EventView.fromNewQueryWithPageFilters(
4149
{
4250
fields: [
@@ -64,10 +72,10 @@ export const useTransactionWebVitalsScoresQuery = ({
6472
query: [
6573
'transaction.op:[pageload,""]',
6674
'span.op:[ui.interaction.click,""]',
67-
'avg(measurements.score.total):>=0',
68-
...(transaction ? [`transaction:"${transaction}"`] : []),
69-
...(query ? [query] : []),
70-
].join(' '),
75+
search.formatString(),
76+
]
77+
.join(' ')
78+
.trim(),
7179
version: 2,
7280
dataset: DiscoverDatasets.METRICS,
7381
},

0 commit comments

Comments
 (0)