Skip to content

Commit 9f84049

Browse files
authored
ref(trace-items): Pull useGetTraceItemAttributeKeys into hook (#93739)
We'll need the `useGetTraceItemAttributeKeys` hook in other places so refactoring it so that it can exported.
1 parent c05a0c6 commit 9f84049

File tree

7 files changed

+202
-110
lines changed

7 files changed

+202
-110
lines changed

static/app/views/explore/components/traceItemSearchQueryBuilder.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {SavedSearchType, type TagCollection} from 'sentry/types/group';
88
import type {AggregationKey} from 'sentry/utils/fields';
99
import {FieldKind, getFieldDefinition} from 'sentry/utils/fields';
1010
import useOrganization from 'sentry/utils/useOrganization';
11-
import {useTraceItemAttributeValues} from 'sentry/views/explore/hooks/useTraceItemAttributeValues';
11+
import {useGetTraceItemAttributeValues} from 'sentry/views/explore/hooks/useGetTraceItemAttributeValues';
1212
import {LOGS_FILTER_KEY_SECTIONS} from 'sentry/views/explore/logs/constants';
1313
import {TraceItemDataset} from 'sentry/views/explore/types';
1414
import {SPANS_FILTER_KEY_SECTIONS} from 'sentry/views/insights/constants';
@@ -68,10 +68,8 @@ export function useSearchQueryBuilderProps({
6868
const filterKeySections = useFilterKeySections(itemType, stringAttributes);
6969
const filterTags = useFilterTags(numberAttributes, stringAttributes, functionTags);
7070

71-
const getTraceItemAttributeValues = useTraceItemAttributeValues({
71+
const getTraceItemAttributeValues = useGetTraceItemAttributeValues({
7272
traceItemType: itemType,
73-
attributeKey: '',
74-
enabled: true,
7573
type: 'string',
7674
projectIds: projects,
7775
});
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import {useCallback} from 'react';
2+
3+
import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
4+
import type {PageFilters} from 'sentry/types/core';
5+
import type {Tag, TagCollection} from 'sentry/types/group';
6+
import {FieldKind} from 'sentry/utils/fields';
7+
import useApi from 'sentry/utils/useApi';
8+
import useOrganization from 'sentry/utils/useOrganization';
9+
import usePageFilters from 'sentry/utils/usePageFilters';
10+
import type {
11+
TraceItemDataset,
12+
UseTraceItemAttributeBaseProps,
13+
} from 'sentry/views/explore/types';
14+
15+
interface UseGetTraceItemAttributeKeysProps extends UseTraceItemAttributeBaseProps {
16+
projectIds?: Array<string | number>;
17+
}
18+
19+
type TraceItemAttributeKeyOptions = Pick<
20+
ReturnType<typeof normalizeDateTimeParams>,
21+
'end' | 'start' | 'statsPeriod' | 'utc'
22+
> & {
23+
attributeType: 'string' | 'number';
24+
itemType: TraceItemDataset;
25+
project?: string[];
26+
substringMatch?: string;
27+
};
28+
29+
export function makeTraceItemAttributeKeysQueryOptions({
30+
traceItemType,
31+
type,
32+
datetime,
33+
projectIds,
34+
search,
35+
}: {
36+
datetime: PageFilters['datetime'];
37+
traceItemType: TraceItemDataset;
38+
type: 'string' | 'number';
39+
projectIds?: Array<string | number>;
40+
search?: string;
41+
}): TraceItemAttributeKeyOptions {
42+
const options: TraceItemAttributeKeyOptions = {
43+
itemType: traceItemType,
44+
attributeType: type,
45+
project: projectIds?.map(String),
46+
substringMatch: search,
47+
...normalizeDateTimeParams(datetime),
48+
};
49+
50+
// environment left out intentionally as it's not supported
51+
52+
return options;
53+
}
54+
55+
export function useGetTraceItemAttributeKeys({
56+
traceItemType,
57+
projectIds,
58+
type,
59+
}: UseGetTraceItemAttributeKeysProps) {
60+
const api = useApi();
61+
const organization = useOrganization();
62+
const {selection} = usePageFilters();
63+
64+
const getTraceItemAttributeKeys = useCallback(
65+
async (queryString?: string): Promise<TagCollection> => {
66+
const options = makeTraceItemAttributeKeysQueryOptions({
67+
traceItemType,
68+
type,
69+
datetime: selection.datetime,
70+
projectIds: projectIds ?? selection.projects,
71+
search: queryString,
72+
});
73+
74+
let result: Tag[];
75+
76+
try {
77+
result = await api.requestPromise(
78+
`/organizations/${organization.slug}/trace-items/attributes/`,
79+
{
80+
method: 'GET',
81+
query: options,
82+
}
83+
);
84+
} catch (e) {
85+
throw new Error(`Unable to fetch trace item attribute keys: ${e}`);
86+
}
87+
88+
const attributes: TagCollection = {};
89+
90+
for (const attribute of result ?? []) {
91+
if (isKnownAttribute(attribute)) {
92+
continue;
93+
}
94+
95+
// EAP spans contain tags with illegal characters
96+
// SnQL forbids `-` but is allowed in RPC. So add it back later
97+
if (
98+
!/^[a-zA-Z0-9_.:-]+$/.test(attribute.key) &&
99+
!/^tags\[[a-zA-Z0-9_.:-]+,number\]$/.test(attribute.key)
100+
) {
101+
continue;
102+
}
103+
104+
attributes[attribute.key] = {
105+
key: attribute.key,
106+
name: attribute.name,
107+
kind: type === 'number' ? FieldKind.MEASUREMENT : FieldKind.TAG,
108+
};
109+
}
110+
111+
return attributes;
112+
},
113+
[api, organization, selection, traceItemType, projectIds, type]
114+
);
115+
116+
return getTraceItemAttributeKeys;
117+
}
118+
119+
function isKnownAttribute(attribute: Tag) {
120+
// For now, skip all the sentry. prefixed attributes as they
121+
// should be covered by the static attributes that will be
122+
// merged with these results.
123+
124+
// For logs we include sentry.message.* since it contains params etc.
125+
if (
126+
attribute.key.startsWith('sentry.message.') ||
127+
attribute.key.startsWith('tags[sentry.message.')
128+
) {
129+
return false;
130+
}
131+
132+
return attribute.key.startsWith('sentry.') || attribute.key.startsWith('tags[sentry.');
133+
}

static/app/views/explore/hooks/useTraceItemAttributeValues.spec.tsx renamed to static/app/views/explore/hooks/useGetTraceItemAttributeValues.spec.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type {Organization} from 'sentry/types/organization';
1010
import {FieldKind} from 'sentry/utils/fields';
1111
import {QueryClientProvider} from 'sentry/utils/queryClient';
1212
import {useLocation} from 'sentry/utils/useLocation';
13-
import {useTraceItemAttributeValues} from 'sentry/views/explore/hooks/useTraceItemAttributeValues';
13+
import {useGetTraceItemAttributeValues} from 'sentry/views/explore/hooks/useGetTraceItemAttributeValues';
1414
import {TraceItemDataset} from 'sentry/views/explore/types';
1515
import {OrganizationContext} from 'sentry/views/organizationContext';
1616

@@ -27,7 +27,7 @@ function createWrapper(organization: Organization) {
2727
};
2828
}
2929

30-
describe('useTraceItemAttributeValues', () => {
30+
describe('useGetTraceItemAttributeValues', () => {
3131
const organization = OrganizationFixture({slug: 'org-slug'});
3232
const attributeKey = 'test.attribute';
3333

@@ -77,9 +77,8 @@ describe('useTraceItemAttributeValues', () => {
7777

7878
const {result} = renderHook(
7979
() =>
80-
useTraceItemAttributeValues({
80+
useGetTraceItemAttributeValues({
8181
traceItemType: TraceItemDataset.LOGS,
82-
attributeKey,
8382
type: 'string',
8483
}),
8584
{
@@ -125,9 +124,8 @@ describe('useTraceItemAttributeValues', () => {
125124

126125
const {result} = renderHook(
127126
() =>
128-
useTraceItemAttributeValues({
127+
useGetTraceItemAttributeValues({
129128
traceItemType: TraceItemDataset.LOGS,
130-
attributeKey,
131129
type: 'number',
132130
}),
133131
{

static/app/views/explore/hooks/useTraceItemAttributeValues.tsx renamed to static/app/views/explore/hooks/useGetTraceItemAttributeValues.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import type {ApiQueryKey} from 'sentry/utils/queryClient';
99
import useApi from 'sentry/utils/useApi';
1010
import useOrganization from 'sentry/utils/useOrganization';
1111
import usePageFilters from 'sentry/utils/usePageFilters';
12-
import type {UseTraceItemAttributeBaseProps} from 'sentry/views/explore/hooks/useTraceItemAttributeKeys';
13-
import type {TraceItemDataset} from 'sentry/views/explore/types';
12+
import type {
13+
TraceItemDataset,
14+
UseTraceItemAttributeBaseProps,
15+
} from 'sentry/views/explore/types';
1416

1517
interface TraceItemAttributeValue {
1618
first_seen: null;
@@ -20,15 +22,9 @@ interface TraceItemAttributeValue {
2022
value: string;
2123
}
2224

23-
interface UseTraceItemAttributeValuesProps extends UseTraceItemAttributeBaseProps {
24-
/**
25-
* The attribute key for which to fetch values
26-
*/
27-
attributeKey: string;
25+
interface UseGetTraceItemAttributeValuesProps extends UseTraceItemAttributeBaseProps {
2826
datetime?: PageFilters['datetime'];
29-
enabled?: boolean;
3027
projectIds?: PageFilters['projects'];
31-
search?: string;
3228
}
3329

3430
function traceItemAttributeValuesQueryKey({
@@ -79,12 +75,12 @@ function traceItemAttributeValuesQueryKey({
7975
* Hook to fetch trace item attribute values for the Explore interface.
8076
* This is designed to be used with the organization_trace_item_attributes endpoint.
8177
*/
82-
export function useTraceItemAttributeValues({
78+
export function useGetTraceItemAttributeValues({
8379
traceItemType,
8480
projectIds,
8581
datetime,
8682
type = 'string',
87-
}: UseTraceItemAttributeValuesProps) {
83+
}: UseGetTraceItemAttributeValuesProps) {
8884
const api = useApi();
8985
const organization = useOrganization();
9086
const {selection} = usePageFilters();
Lines changed: 37 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
11
import {useMemo} from 'react';
22

3-
import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
4-
import type {Tag, TagCollection} from 'sentry/types/group';
5-
import type {Project} from 'sentry/types/project';
3+
import type {TagCollection} from 'sentry/types/group';
64
import {defined} from 'sentry/utils';
7-
import {FieldKind} from 'sentry/utils/fields';
8-
import {useApiQuery} from 'sentry/utils/queryClient';
9-
import useOrganization from 'sentry/utils/useOrganization';
5+
import {useQuery} from 'sentry/utils/queryClient';
106
import usePageFilters from 'sentry/utils/usePageFilters';
117
import usePrevious from 'sentry/utils/usePrevious';
12-
import type {TraceItemDataset} from 'sentry/views/explore/types';
13-
14-
export interface UseTraceItemAttributeBaseProps {
15-
/**
16-
* The trace item type supported by the endpoint, currently only supports LOGS.
17-
*/
18-
traceItemType: TraceItemDataset;
19-
/**
20-
* The attribute type supported by the endpoint, currently only supports string and number.
21-
*/
22-
type: 'number' | 'string';
23-
/**
24-
* Optional list of projects to search. If not provided, it'll use the page filters.
25-
*/
26-
projects?: Project[];
27-
}
8+
import {
9+
makeTraceItemAttributeKeysQueryOptions,
10+
useGetTraceItemAttributeKeys,
11+
} from 'sentry/views/explore/hooks/useGetTraceItemAttributeKeys';
12+
import type {UseTraceItemAttributeBaseProps} from 'sentry/views/explore/types';
2813

2914
interface UseTraceItemAttributeKeysProps extends UseTraceItemAttributeBaseProps {
3015
enabled?: boolean;
@@ -36,76 +21,43 @@ export function useTraceItemAttributeKeys({
3621
traceItemType,
3722
projects,
3823
}: UseTraceItemAttributeKeysProps) {
39-
const organization = useOrganization();
4024
const {selection} = usePageFilters();
4125

42-
const path = `/organizations/${organization.slug}/trace-items/attributes/`;
43-
const endpointOptions = {
44-
query: {
45-
project: defined(projects)
46-
? projects.map(project => project.id)
47-
: selection.projects,
48-
environment: selection.environments,
49-
...normalizeDateTimeParams(selection.datetime),
50-
itemType: traceItemType,
51-
attributeType: type,
52-
},
53-
};
26+
const projectIds = defined(projects)
27+
? projects.map(project => project.id)
28+
: selection.projects;
29+
30+
const queryOptions = useMemo(() => {
31+
return makeTraceItemAttributeKeysQueryOptions({
32+
traceItemType,
33+
type,
34+
datetime: selection.datetime,
35+
projectIds,
36+
});
37+
}, [selection, traceItemType, type, projectIds]);
38+
39+
const queryKey = useMemo(
40+
() => ['use-trace-item-attribute-keys', queryOptions],
41+
[queryOptions]
42+
);
43+
44+
const getTraceItemAttributeKeys = useGetTraceItemAttributeKeys({
45+
traceItemType,
46+
type,
47+
projectIds,
48+
});
5449

55-
const result = useApiQuery<Tag[]>([path, endpointOptions], {
50+
const {data, isFetching, error} = useQuery<TagCollection>({
5651
enabled,
57-
staleTime: 0,
58-
refetchOnWindowFocus: false,
59-
retry: false,
52+
queryKey,
53+
queryFn: () => getTraceItemAttributeKeys(),
6054
});
6155

62-
const attributes: TagCollection = useMemo(() => {
63-
const allAttributes: TagCollection = {};
64-
65-
for (const attribute of result.data ?? []) {
66-
if (isKnownAttribute(attribute)) {
67-
continue;
68-
}
69-
70-
// EAP spans contain tags with illegal characters
71-
// SnQL forbids `-` but is allowed in RPC. So add it back later
72-
if (
73-
!/^[a-zA-Z0-9_.:-]+$/.test(attribute.key) &&
74-
!/^tags\[[a-zA-Z0-9_.:-]+,number\]$/.test(attribute.key)
75-
) {
76-
continue;
77-
}
78-
79-
allAttributes[attribute.key] = {
80-
key: attribute.key,
81-
name: attribute.name,
82-
kind: type === 'number' ? FieldKind.MEASUREMENT : FieldKind.TAG,
83-
};
84-
}
85-
86-
return allAttributes;
87-
}, [result.data, type]);
88-
89-
const previousAttributes = usePrevious(attributes, result.isLoading);
56+
const previous = usePrevious(data, isFetching);
9057

9158
return {
92-
attributes: result.isLoading ? previousAttributes : attributes,
93-
isLoading: result.isLoading,
59+
attributes: isFetching ? previous : data,
60+
error,
61+
isLoading: isFetching,
9462
};
9563
}
96-
97-
function isKnownAttribute(attribute: Tag) {
98-
// For now, skip all the sentry. prefixed attributes as they
99-
// should be covered by the static attributes that will be
100-
// merged with these results.
101-
102-
// For logs we include sentry.message.* since it contains params etc.
103-
if (
104-
attribute.key.startsWith('sentry.message.') ||
105-
attribute.key.startsWith('tags[sentry.message.')
106-
) {
107-
return false;
108-
}
109-
110-
return attribute.key.startsWith('sentry.') || attribute.key.startsWith('tags[sentry.');
111-
}

0 commit comments

Comments
 (0)