Skip to content

Commit 9599396

Browse files
authored
feat: Choose the least granular defaults (#87218)
Choose less granular defaults and track percentage of empty buckets in timeseries
1 parent 09f90ec commit 9599396

File tree

7 files changed

+59
-9
lines changed

7 files changed

+59
-9
lines changed

static/app/utils/analytics/tracingEventMap.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export type TracingEventParameters = {
1616
confidences: string[];
1717
dataset: string;
1818
has_exceeded_performance_usage_limit: boolean | null;
19+
interval: string;
1920
page_source: 'explore' | 'compare';
2021
query_status: 'success' | 'error' | 'pending';
2122
result_length: number;
@@ -26,6 +27,7 @@ export type TracingEventParameters = {
2627
user_queries_count: number;
2728
visualizes: BaseVisualize[];
2829
visualizes_count: number;
30+
empty_buckets_percentage?: number[];
2931
};
3032
'trace.load.empty_state': {
3133
source: TraceWaterFallSource;

static/app/views/explore/hooks/useAnalytics.tsx

+41
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {dedupeArray} from 'sentry/utils/dedupeArray';
77
import {DiscoverDatasets} from 'sentry/utils/discover/types';
88
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
99
import useOrganization from 'sentry/utils/useOrganization';
10+
import type {TimeSeries} from 'sentry/views/dashboards/widgets/common/types';
1011
import {
1112
useExploreDataset,
1213
useExploreFields,
@@ -37,10 +38,12 @@ export function useTrackAnalytics({
3738
fields,
3839
visualizes,
3940
page_source,
41+
interval,
4042
}: {
4143
aggregatesTableResult: AggregatesTableResult;
4244
dataset: DiscoverDatasets;
4345
fields: string[];
46+
interval: string;
4447
page_source: 'explore' | 'compare';
4548
query: string;
4649
queryType: 'aggregate' | 'samples' | 'traces';
@@ -95,9 +98,11 @@ export function useTrackAnalytics({
9598
})),
9699
visualizes_count: visualizes.length,
97100
title: title || '',
101+
empty_buckets_percentage: computeEmptyBuckets(visualizes, timeseriesResult.data),
98102
confidences: computeConfidence(visualizes, timeseriesResult.data),
99103
has_exceeded_performance_usage_limit: hasExceededPerformanceUsageLimit,
100104
page_source,
105+
interval,
101106
});
102107

103108
info(
@@ -135,6 +140,7 @@ export function useTrackAnalytics({
135140
isLoadingSubscriptionDetails,
136141
query_status,
137142
page_source,
143+
interval,
138144
]);
139145

140146
useEffect(() => {
@@ -162,9 +168,11 @@ export function useTrackAnalytics({
162168
visualizes,
163169
visualizes_count: visualizes.length,
164170
title: title || '',
171+
empty_buckets_percentage: computeEmptyBuckets(visualizes, timeseriesResult.data),
165172
confidences: computeConfidence(visualizes, timeseriesResult.data),
166173
has_exceeded_performance_usage_limit: hasExceededPerformanceUsageLimit,
167174
page_source,
175+
interval,
168176
});
169177

170178
info(fmt`trace.explorer.metadata:
@@ -198,6 +206,7 @@ export function useTrackAnalytics({
198206
isLoadingSubscriptionDetails,
199207
query_status,
200208
page_source,
209+
interval,
201210
]);
202211

203212
const tracesTableResultDefined = defined(tracesTableResult);
@@ -240,9 +249,11 @@ export function useTrackAnalytics({
240249
visualizes,
241250
visualizes_count: visualizes.length,
242251
title: title || '',
252+
empty_buckets_percentage: computeEmptyBuckets(visualizes, timeseriesResult.data),
243253
confidences: computeConfidence(visualizes, timeseriesResult.data),
244254
has_exceeded_performance_usage_limit: hasExceededPerformanceUsageLimit,
245255
page_source,
256+
interval,
246257
});
247258
}, [
248259
organization,
@@ -262,6 +273,7 @@ export function useTrackAnalytics({
262273
query_status,
263274
page_source,
264275
tracesTableResultDefined,
276+
interval,
265277
]);
266278
}
267279

@@ -271,8 +283,10 @@ export function useAnalytics({
271283
spansTableResult,
272284
tracesTableResult,
273285
timeseriesResult,
286+
interval,
274287
}: {
275288
aggregatesTableResult: AggregatesTableResult;
289+
interval: string;
276290
queryType: 'aggregate' | 'samples' | 'traces';
277291
spansTableResult: SpansTableResult;
278292
timeseriesResult: ReturnType<typeof useSortedTimeSeries>;
@@ -295,6 +309,7 @@ export function useAnalytics({
295309
query,
296310
fields,
297311
visualizes,
312+
interval,
298313
page_source: 'explore',
299314
});
300315
}
@@ -306,9 +321,11 @@ export function useCompareAnalytics({
306321
aggregatesTableResult,
307322
spansTableResult,
308323
timeseriesResult,
324+
interval,
309325
}: {
310326
aggregatesTableResult: AggregatesTableResult;
311327
index: number;
328+
interval: string;
312329
query: ReadableExploreQueryParts;
313330
queryType: 'aggregate' | 'samples' | 'traces';
314331
spansTableResult: SpansTableResult;
@@ -334,6 +351,7 @@ export function useCompareAnalytics({
334351
query,
335352
fields,
336353
visualizes,
354+
interval,
337355
page_source: 'compare',
338356
});
339357
}
@@ -348,3 +366,26 @@ function computeConfidence(
348366
return String(combineConfidenceForSeries(series));
349367
});
350368
}
369+
370+
export function computeEmptyBucketsForSeries(series: Pick<TimeSeries, 'data'>): number {
371+
let emptyBucketsForSeries = 0;
372+
for (const item of series.data) {
373+
if (item.value === 0 || item.value === null) {
374+
emptyBucketsForSeries += 1;
375+
}
376+
}
377+
return Math.floor((emptyBucketsForSeries / series.data.length) * 100);
378+
}
379+
380+
function computeEmptyBuckets(
381+
visualizes: Visualize[],
382+
data: ReturnType<typeof useSortedTimeSeries>['data']
383+
) {
384+
return visualizes.flatMap(visualize => {
385+
const dedupedYAxes = dedupeArray(visualize.yAxes);
386+
return dedupedYAxes
387+
.flatMap(yAxis => data[yAxis])
388+
.filter(defined)
389+
.map(computeEmptyBucketsForSeries);
390+
});
391+
}

static/app/views/explore/hooks/useChartInterval.spec.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ describe('useChartInterval', function () {
2929
{value: '12h', label: '12 hours'},
3030
{value: '1d', label: '1 day'},
3131
]);
32-
expect(chartInterval).toBe('3h'); // default
32+
expect(chartInterval).toBe('1d'); // default
3333

34-
await act(() => setChartInterval('1d'));
35-
expect(chartInterval).toBe('1d');
34+
await act(() => setChartInterval('3h'));
35+
expect(chartInterval).toBe('3h');
3636

3737
// Update page filters to change interval options
3838
await act(() =>

static/app/views/explore/hooks/useChartInterval.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ function useChartIntervalImpl({
5858
return decodedInterval &&
5959
intervalOptions.some(option => option.value === decodedInterval)
6060
? decodedInterval
61-
: // Default to the second option so we're not defaulting to the smallest option
62-
intervalOptions[1]!.value;
61+
: // Default to the largest option
62+
intervalOptions[intervalOptions.length - 1]!.value;
6363
}, [location.query.interval, intervalOptions]);
6464

6565
const setInterval = useCallback(

static/app/views/explore/multiQueryMode/content.spec.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ describe('MultiQueryModeContent', function () {
376376
query: expect.objectContaining({
377377
dataset: 'spans',
378378
field: [],
379-
interval: '1h',
379+
interval: '1d',
380380
orderby: undefined,
381381
project: ['2'],
382382
query: '!transaction.span_id:00',
@@ -427,7 +427,7 @@ describe('MultiQueryModeContent', function () {
427427
dataset: 'spans',
428428
excludeOther: 0,
429429
field: ['span.op', 'avg(span.duration)'],
430-
interval: '1h',
430+
interval: '1d',
431431
orderby: '-avg_span_duration',
432432
project: ['2'],
433433
query: '!transaction.span_id:00',
@@ -566,9 +566,9 @@ describe('MultiQueryModeContent', function () {
566566

567567
const section = screen.getByTestId('section-visualization-0');
568568
expect(
569-
await within(section).findByRole('button', {name: '1 hour'})
569+
await within(section).findByRole('button', {name: '1 day'})
570570
).toBeInTheDocument();
571-
await userEvent.click(within(section).getByRole('button', {name: '1 hour'}));
571+
await userEvent.click(within(section).getByRole('button', {name: '1 day'}));
572572
await userEvent.click(within(section).getByRole('option', {name: '30 minutes'}));
573573
expect(router.push).toHaveBeenCalledWith({
574574
pathname: '/traces/compare',

static/app/views/explore/multiQueryMode/queryRow.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {t} from 'sentry/locale';
88
import {space} from 'sentry/styles/space';
99
import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
1010
import {useCompareAnalytics} from 'sentry/views/explore/hooks/useAnalytics';
11+
import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
1112
import {
1213
useMultiQueryTableAggregateMode,
1314
useMultiQueryTableSampleMode,
@@ -58,13 +59,16 @@ export function QueryRow({query: queryParts, index, totalQueryRows}: Props) {
5859
enabled: true,
5960
});
6061

62+
const [interval] = useChartInterval();
63+
6164
useCompareAnalytics({
6265
aggregatesTableResult,
6366
index,
6467
query: queryParts,
6568
spansTableResult,
6669
timeseriesResult,
6770
queryType: mode === Mode.AGGREGATE ? 'aggregate' : 'samples',
71+
interval,
6872
});
6973

7074
return (

static/app/views/explore/spans/spansTab.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
useSpanTags,
4545
} from 'sentry/views/explore/contexts/spanTagsContext';
4646
import {useAnalytics} from 'sentry/views/explore/hooks/useAnalytics';
47+
import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
4748
import {useExploreAggregatesTable} from 'sentry/views/explore/hooks/useExploreAggregatesTable';
4849
import {useExploreSpansTable} from 'sentry/views/explore/hooks/useExploreSpansTable';
4950
import {useExploreTimeseries} from 'sentry/views/explore/hooks/useExploreTimeseries';
@@ -140,13 +141,15 @@ export function SpansTabContentImpl({
140141
);
141142

142143
const [expanded, setExpanded] = useState(true);
144+
const [interval] = useChartInterval();
143145

144146
useAnalytics({
145147
queryType,
146148
aggregatesTableResult,
147149
spansTableResult,
148150
tracesTableResult,
149151
timeseriesResult,
152+
interval,
150153
});
151154

152155
const resultsLength =

0 commit comments

Comments
 (0)