Skip to content

Commit 73d2983

Browse files
Zylphrexgetsantry[bot]
authored andcommitted
feat(logs): Swap logs to query params context for visualizes readonly (#97610)
This swaps out the read portions for visualizes to use the new query params context. --------- Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
1 parent 3c8b0bb commit 73d2983

16 files changed

+279
-174
lines changed

static/app/views/explore/contexts/logs/logsPageParams.tsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -357,22 +357,6 @@ export function useLogsCursor() {
357357
return cursor;
358358
}
359359

360-
export function useLogsAggregateFunction() {
361-
const {aggregateFn} = useLogsPageParams();
362-
return aggregateFn;
363-
}
364-
365-
export function useLogsAggregateParam() {
366-
const {aggregateParam} = useLogsPageParams();
367-
return aggregateParam;
368-
}
369-
370-
export function useLogsAggregate() {
371-
const aggregateFn = useLogsAggregateFunction();
372-
const aggregateParam = useLogsAggregateParam();
373-
return `${aggregateFn}(${aggregateParam})`;
374-
}
375-
376360
export function useLogsLimitToTraceId() {
377361
const {limitToTraceId} = useLogsPageParams();
378362
return limitToTraceId;

static/app/views/explore/logs/logsGraph.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ import {defined} from 'sentry/utils';
88
import {determineSeriesSampleCountAndIsSampled} from 'sentry/views/alerts/rules/metric/utils/determineSeriesSampleCount';
99
import {Widget} from 'sentry/views/dashboards/widgets/widget/widget';
1010
import {ChartVisualization} from 'sentry/views/explore/components/chart/chartVisualization';
11-
import {useLogsAggregate} from 'sentry/views/explore/contexts/logs/logsPageParams';
1211
import {
1312
ChartIntervalUnspecifiedStrategy,
1413
useChartInterval,
1514
} from 'sentry/views/explore/hooks/useChartInterval';
1615
import {TOP_EVENTS_LIMIT} from 'sentry/views/explore/hooks/useTopEvents';
1716
import {ConfidenceFooter} from 'sentry/views/explore/logs/confidenceFooter';
18-
import {useQueryParamsTopEventsLimit} from 'sentry/views/explore/queryParams/context';
17+
import {
18+
useQueryParamsTopEventsLimit,
19+
useQueryParamsVisualizes,
20+
} from 'sentry/views/explore/queryParams/context';
21+
import type {Visualize} from 'sentry/views/explore/queryParams/visualize';
1922
import {EXPLORE_CHART_TYPE_OPTIONS} from 'sentry/views/explore/spans/charts';
2023
import {
2124
combineConfidenceForSeries,
@@ -29,7 +32,25 @@ interface LogsGraphProps {
2932
}
3033

3134
export function LogsGraph({timeseriesResult}: LogsGraphProps) {
32-
const aggregate = useLogsAggregate();
35+
const visualizes = useQueryParamsVisualizes();
36+
37+
return (
38+
<Fragment>
39+
{visualizes.map((visualize, index) => {
40+
return (
41+
<Graph key={index} visualize={visualize} timeseriesResult={timeseriesResult} />
42+
);
43+
})}
44+
</Fragment>
45+
);
46+
}
47+
48+
interface GraphProps extends LogsGraphProps {
49+
visualize: Visualize;
50+
}
51+
52+
function Graph({timeseriesResult, visualize}: GraphProps) {
53+
const aggregate = visualize.yAxis;
3354
const topEventsLimit = useQueryParamsTopEventsLimit();
3455

3556
const [chartType, setChartType] = useState<ChartType>(ChartType.BAR);

static/app/views/explore/logs/logsQueryParams.spec.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {getReadableQueryParamsFromLocation} from 'sentry/views/explore/logs/logs
55
import {Mode} from 'sentry/views/explore/queryParams/mode';
66
import type {ReadableQueryParamsOptions} from 'sentry/views/explore/queryParams/readableQueryParams';
77
import {ReadableQueryParams} from 'sentry/views/explore/queryParams/readableQueryParams';
8-
import {Visualize} from 'sentry/views/explore/queryParams/visualize';
8+
import {VisualizeFunction} from 'sentry/views/explore/queryParams/visualize';
99

1010
function locationFixture(query: Location['query']): Location {
1111
return LocationFixture({query});
@@ -21,7 +21,7 @@ function readableQueryParamOptions(
2121
fields: ['timestamp', 'message'],
2222
sortBys: [{field: 'timestamp', kind: 'desc'}],
2323
aggregateCursor: '',
24-
aggregateFields: [{groupBy: ''}, new Visualize('count(message)')],
24+
aggregateFields: [{groupBy: ''}, new VisualizeFunction('count(message)')],
2525
aggregateSortBys: [
2626
{
2727
field: 'count(message)',
@@ -179,7 +179,10 @@ describe('getReadableQueryParamsFromLocation', function () {
179179
expect(queryParams).toEqual(
180180
new ReadableQueryParams(
181181
readableQueryParamOptions({
182-
aggregateFields: [{groupBy: 'severity'}, new Visualize('count(message)')],
182+
aggregateFields: [
183+
{groupBy: 'severity'},
184+
new VisualizeFunction('count(message)'),
185+
],
183186
})
184187
)
185188
);
@@ -191,7 +194,7 @@ describe('getReadableQueryParamsFromLocation', function () {
191194
expect(queryParams).toEqual(
192195
new ReadableQueryParams(
193196
readableQueryParamOptions({
194-
aggregateFields: [{groupBy: ''}, new Visualize('avg(foo)')],
197+
aggregateFields: [{groupBy: ''}, new VisualizeFunction('avg(foo)')],
195198
aggregateSortBys: [{field: 'avg(foo)', kind: 'desc'}],
196199
})
197200
)
@@ -209,7 +212,7 @@ describe('getReadableQueryParamsFromLocation', function () {
209212
expect(queryParams).toEqual(
210213
new ReadableQueryParams(
211214
readableQueryParamOptions({
212-
aggregateFields: [{groupBy: 'severity'}, new Visualize('avg(foo)')],
215+
aggregateFields: [{groupBy: 'severity'}, new VisualizeFunction('avg(foo)')],
213216
aggregateSortBys: [{field: 'severity', kind: 'desc'}],
214217
})
215218
)

static/app/views/explore/logs/logsQueryParams.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {Location} from 'history';
22

33
import type {Sort} from 'sentry/utils/discover/fields';
4+
import {AggregationKey} from 'sentry/utils/fields';
45
import {decodeScalar} from 'sentry/utils/queryString';
56
import {defaultLogFields} from 'sentry/views/explore/contexts/logs/fields';
67
import {
@@ -31,7 +32,8 @@ import {getModeFromLocation} from 'sentry/views/explore/queryParams/mode';
3132
import {getQueryFromLocation} from 'sentry/views/explore/queryParams/query';
3233
import {ReadableQueryParams} from 'sentry/views/explore/queryParams/readableQueryParams';
3334
import {getSortBysFromLocation} from 'sentry/views/explore/queryParams/sortBy';
34-
import {isVisualize, Visualize} from 'sentry/views/explore/queryParams/visualize';
35+
import type {Visualize} from 'sentry/views/explore/queryParams/visualize';
36+
import {isVisualize, VisualizeFunction} from 'sentry/views/explore/queryParams/visualize';
3537
import type {WritableQueryParams} from 'sentry/views/explore/queryParams/writableQueryParams';
3638

3739
const LOGS_MODE_KEY = 'mode';
@@ -102,17 +104,20 @@ function defaultSortBys(fields: string[]) {
102104
}
103105

104106
export function defaultVisualizes() {
105-
return [new Visualize('count(message)')];
107+
return [new VisualizeFunction('count(message)')];
106108
}
107109

108110
function getVisualizesFromLocation(location: Location): [Visualize] {
109-
const aggregateFn = decodeScalar(location.query?.[LOGS_AGGREGATE_FN_KEY], 'count');
111+
const aggregateFn = decodeScalar(
112+
location.query?.[LOGS_AGGREGATE_FN_KEY],
113+
AggregationKey.COUNT
114+
);
110115
const aggregateParam = decodeScalar(
111116
location.query?.[LOGS_AGGREGATE_PARAM_KEY],
112-
'message'
117+
aggregateFn === AggregationKey.COUNT ? OurLogKnownFieldKey.MESSAGE : ''
113118
);
114119

115-
return [new Visualize(`${aggregateFn}(${aggregateParam})`)];
120+
return [new VisualizeFunction(`${aggregateFn}(${aggregateParam})`)];
116121
}
117122

118123
function getLogsAggregateFieldsFromLocation(location: Location): AggregateField[] {

static/app/views/explore/logs/logsTab.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {t} from 'sentry/locale';
1616
import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent';
1717
import {DiscoverDatasets} from 'sentry/utils/discover/types';
1818
import {parsePeriodToHours} from 'sentry/utils/duration/parsePeriodToHours';
19+
import {AggregationKey} from 'sentry/utils/fields';
1920
import {HOUR} from 'sentry/utils/formatters';
2021
import {useQueryClient, type InfiniteData} from 'sentry/utils/queryClient';
2122
import useOrganization from 'sentry/utils/useOrganization';
@@ -29,8 +30,6 @@ import {defaultLogFields} from 'sentry/views/explore/contexts/logs/fields';
2930
import {useLogsAutoRefreshEnabled} from 'sentry/views/explore/contexts/logs/logsAutoRefreshContext';
3031
import {useLogsPageDataQueryResult} from 'sentry/views/explore/contexts/logs/logsPageData';
3132
import {
32-
useLogsAggregate,
33-
useLogsAggregateFunction,
3433
useLogsAggregateSortBys,
3534
useLogsFields,
3635
useLogsSearch,
@@ -83,8 +82,10 @@ import {
8382
useQueryParamsGroupBys,
8483
useQueryParamsMode,
8584
useQueryParamsTopEventsLimit,
85+
useQueryParamsVisualizes,
8686
useSetQueryParamsMode,
8787
} from 'sentry/views/explore/queryParams/context';
88+
import {isVisualizeFunction} from 'sentry/views/explore/queryParams/visualize';
8889
import {ColumnEditorModal} from 'sentry/views/explore/tables/columnEditorModal';
8990
import type {PickableDays} from 'sentry/views/explore/utils';
9091
import {useSortedTimeSeries} from 'sentry/views/insights/common/queries/useSortedTimeSeries';
@@ -119,8 +120,7 @@ export function LogsTabContent({
119120
const [interval] = useChartInterval({
120121
unspecifiedStrategy: ChartIntervalUnspecifiedStrategy.USE_SMALLEST,
121122
});
122-
const aggregateFunction = useLogsAggregateFunction();
123-
const aggregate = useLogsAggregate();
123+
const visualizes = useQueryParamsVisualizes();
124124

125125
const orderby: string | string[] | undefined = useMemo(() => {
126126
if (!sortBys.length) {
@@ -132,8 +132,12 @@ export function LogsTabContent({
132132

133133
const [sidebarOpen, setSidebarOpen] = useState(
134134
!!(
135-
(aggregateFunction && aggregateFunction !== 'count') ||
136-
groupBys.filter(Boolean).length
135+
groupBys.some(Boolean) ||
136+
visualizes.some(
137+
visualize =>
138+
isVisualizeFunction(visualize) &&
139+
visualize.parsedFunction?.name !== AggregationKey.COUNT
140+
)
137141
)
138142
);
139143

@@ -156,9 +160,12 @@ export function LogsTabContent({
156160
const _timeseriesResult = useSortedTimeSeries(
157161
{
158162
search,
159-
yAxis: [aggregate],
163+
yAxis: visualizes.map(visualize => visualize.yAxis),
160164
interval,
161-
fields: [...groupBys.filter(Boolean), aggregate],
165+
fields: [
166+
...groupBys.filter(Boolean),
167+
...visualizes.map(visualize => visualize.yAxis),
168+
],
162169
topEvents: topEventsLimit,
163170
orderby,
164171
},
@@ -252,7 +259,7 @@ export function LogsTabContent({
252259
);
253260

254261
const saveAsItems = useSaveAsItems({
255-
aggregate,
262+
visualizes,
256263
groupBys,
257264
interval,
258265
mode,

static/app/views/explore/logs/logsToolbar.tsx

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ import {t} from 'sentry/locale';
66
import {space} from 'sentry/styles/space';
77
import type {TagCollection} from 'sentry/types/group';
88
import {AggregationKey, prettifyTagKey} from 'sentry/utils/fields';
9+
import {useSetLogsPageParams} from 'sentry/views/explore/contexts/logs/logsPageParams';
910
import {
10-
useLogsAggregateFunction,
11-
useLogsAggregateParam,
12-
useSetLogsPageParams,
13-
} from 'sentry/views/explore/contexts/logs/logsPageParams';
14-
import type {OurLogsAggregate} from 'sentry/views/explore/logs/types';
15-
import {useQueryParamsGroupBys} from 'sentry/views/explore/queryParams/context';
11+
OurLogKnownFieldKey,
12+
type OurLogsAggregate,
13+
} from 'sentry/views/explore/logs/types';
14+
import {
15+
useQueryParamsGroupBys,
16+
useQueryParamsVisualizes,
17+
} from 'sentry/views/explore/queryParams/context';
18+
import type {VisualizeFunction} from 'sentry/views/explore/queryParams/visualize';
19+
import {isVisualizeFunction} from 'sentry/views/explore/queryParams/visualize';
1620

1721
export const LOG_AGGREGATES = [
1822
{
@@ -67,63 +71,74 @@ interface LogsToolbarProps {
6771
}
6872

6973
export function LogsToolbar({stringTags, numberTags}: LogsToolbarProps) {
70-
const aggregateFunction = useLogsAggregateFunction();
71-
let aggregateParam = useLogsAggregateParam();
74+
const visualizes = useQueryParamsVisualizes();
7275
const groupBys = useQueryParamsGroupBys();
7376
const setLogsPageParams = useSetLogsPageParams();
7477
const functionArgRef = useRef<HTMLDivElement>(null);
7578

76-
let aggregatableKeys = Object.keys(numberTags ?? {}).map(key => ({
77-
label: prettifyTagKey(key),
78-
value: key,
79-
}));
80-
81-
if (aggregateFunction === AggregationKey.COUNT) {
82-
aggregatableKeys = [{label: t('logs'), value: 'logs'}];
83-
aggregateParam = 'logs';
84-
}
85-
if (aggregateFunction === AggregationKey.COUNT_UNIQUE) {
86-
aggregatableKeys = Object.keys(stringTags ?? {}).map(key => ({
87-
label: prettifyTagKey(key),
88-
value: key,
89-
}));
90-
}
91-
9279
return (
9380
<Container data-test-id="logs-toolbar">
9481
<ToolbarItem>
9582
<SectionHeader>
9683
<Label>{t('Visualize')}</Label>
9784
</SectionHeader>
98-
<ToolbarSelectRow>
99-
<Select
100-
options={LOG_AGGREGATES}
101-
onChange={val => {
102-
if (val.value === 'count') {
103-
setLogsPageParams({
104-
aggregateFn: val.value as string | undefined,
105-
aggregateParam: null,
106-
});
107-
} else {
108-
setLogsPageParams({aggregateFn: val.value as string | undefined});
109-
functionArgRef.current?.querySelector('button')?.click();
110-
}
111-
}}
112-
value={aggregateFunction}
113-
/>
114-
<SelectRefWrapper ref={functionArgRef}>
115-
<Select
116-
options={aggregatableKeys}
117-
onChange={val => {
118-
if (aggregateFunction !== 'count') {
119-
setLogsPageParams({aggregateParam: val.value as string | undefined});
120-
}
121-
}}
122-
searchable
123-
value={aggregateParam}
124-
/>
125-
</SelectRefWrapper>
126-
</ToolbarSelectRow>
85+
{visualizes
86+
.filter<VisualizeFunction>(isVisualizeFunction)
87+
.map((visualize, index) => {
88+
const aggregateFunction = visualize.parsedFunction?.name ?? 'count';
89+
90+
const aggregatableKeys =
91+
aggregateFunction === AggregationKey.COUNT
92+
? [{label: t('logs'), value: OurLogKnownFieldKey.MESSAGE}]
93+
: aggregateFunction === AggregationKey.COUNT_UNIQUE
94+
? Object.keys(stringTags ?? {}).map(key => ({
95+
label: prettifyTagKey(key),
96+
value: key,
97+
}))
98+
: Object.keys(numberTags ?? {}).map(key => ({
99+
label: prettifyTagKey(key),
100+
value: key,
101+
}));
102+
103+
const aggregateParam =
104+
aggregateFunction === AggregationKey.COUNT
105+
? OurLogKnownFieldKey.MESSAGE
106+
: (visualize.parsedFunction?.arguments?.[0] ?? '');
107+
108+
return (
109+
<ToolbarSelectRow key={index}>
110+
<Select
111+
options={LOG_AGGREGATES}
112+
onChange={val => {
113+
if (val.value === 'count') {
114+
setLogsPageParams({
115+
aggregateFn: val.value as string | undefined,
116+
aggregateParam: null,
117+
});
118+
} else {
119+
setLogsPageParams({aggregateFn: val.value as string | undefined});
120+
functionArgRef.current?.querySelector('button')?.click();
121+
}
122+
}}
123+
value={visualize.parsedFunction?.name ?? ''}
124+
/>
125+
<SelectRefWrapper ref={functionArgRef}>
126+
<Select
127+
options={aggregatableKeys}
128+
onChange={val => {
129+
if (aggregateFunction !== 'count') {
130+
setLogsPageParams({
131+
aggregateParam: val.value as string | undefined,
132+
});
133+
}
134+
}}
135+
searchable
136+
value={aggregateParam}
137+
/>
138+
</SelectRefWrapper>
139+
</ToolbarSelectRow>
140+
);
141+
})}
127142
</ToolbarItem>
128143
<ToolbarItem>
129144
<SectionHeader>

0 commit comments

Comments
 (0)