Skip to content

Commit c368cfd

Browse files
authored
feat(explore): Update spans confidence footer like logs (#102924)
This updates the confidence footer for spans to be more like logs using matching/scanned/total counts for better context.
1 parent 10be382 commit c368cfd

File tree

11 files changed

+288
-156
lines changed

11 files changed

+288
-156
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import styled from '@emotion/styled';
2+
3+
const _OffsetContainer = styled('span')`
4+
position: relative;
5+
top: 2px;
6+
`;
7+
8+
const _Placeholder = styled('div')<{width: number}>`
9+
display: inline-block;
10+
width: ${p => p.width}px;
11+
height: ${p => p.theme.fontSize.md};
12+
border-radius: ${p => p.theme.borderRadius};
13+
background-color: ${p => p.theme.backgroundTertiary};
14+
`;
15+
16+
interface PlaceholderProps {
17+
width: number;
18+
}
19+
20+
export function Placeholder({width}: PlaceholderProps) {
21+
return (
22+
<_OffsetContainer data-test-id="loading-placeholder">
23+
<_Placeholder width={width} />
24+
</_OffsetContainer>
25+
);
26+
}

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

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import styled from '@emotion/styled';
2-
31
import {Tooltip} from 'sentry/components/core/tooltip';
42
import Count from 'sentry/components/count';
53
import {IconWarning} from 'sentry/icons';
@@ -10,14 +8,15 @@ import {
108
Container,
119
usePreviouslyLoaded,
1210
} from 'sentry/views/explore/components/chart/chartFooter';
11+
import {Placeholder} from 'sentry/views/explore/components/chart/placeholder';
1312
import type {ChartInfo} from 'sentry/views/explore/components/chart/types';
14-
import type {RawLogCounts} from 'sentry/views/explore/logs/useLogsQuery';
13+
import type {RawCounts} from 'sentry/views/explore/useRawCounts';
1514

1615
interface ConfidenceFooterProps {
1716
chartInfo: ChartInfo;
1817
hasUserQuery: boolean;
1918
isLoading: boolean;
20-
rawLogCounts: RawLogCounts;
19+
rawLogCounts: RawCounts;
2120
}
2221

2322
export function ConfidenceFooter({
@@ -46,7 +45,7 @@ export function ConfidenceFooter({
4645
interface ConfidenceMessageProps {
4746
hasUserQuery: boolean;
4847
isLoading: boolean;
49-
rawLogCounts: RawLogCounts;
48+
rawLogCounts: RawCounts;
5049
confidence?: Confidence;
5150
dataScanned?: 'full' | 'partial';
5251
isSampled?: boolean | null;
@@ -67,11 +66,7 @@ function ConfidenceMessage({
6766
const isTopN = defined(topEvents) && topEvents > 1;
6867

6968
if (!defined(sampleCount) || isLoading) {
70-
return (
71-
<OffsetContainer>
72-
<Placeholder width={180} />
73-
</OffsetContainer>
74-
);
69+
return <Placeholder width={180} />;
7570
}
7671

7772
const noSampling = defined(isSampled) && !isSampled;
@@ -86,9 +81,7 @@ function ConfidenceMessage({
8681
t('%s sample', <Count value={rawLogCounts.normal.count} />)
8782
)
8883
) : (
89-
<OffsetContainer>
90-
<Placeholder width={40} />
91-
</OffsetContainer>
84+
<Placeholder width={40} />
9285
);
9386
const allLogsCount = rawLogCounts.highAccuracy.count ? (
9487
rawLogCounts.highAccuracy.count > 1 ? (
@@ -97,9 +90,7 @@ function ConfidenceMessage({
9790
t('%s log', <Count value={rawLogCounts.highAccuracy.count} />)
9891
)
9992
) : (
100-
<OffsetContainer>
101-
<Placeholder width={40} />
102-
</OffsetContainer>
93+
<Placeholder width={40} />
10394
);
10495

10596
if (dataScanned === 'full') {
@@ -134,11 +125,7 @@ function ConfidenceMessage({
134125

135126
const downsampledTooltip = <DownsampledTooltip noSampling={noSampling} />;
136127

137-
const warning = (
138-
<OffsetContainer>
139-
<IconWarning size="sm" />
140-
</OffsetContainer>
141-
);
128+
const warning = <IconWarning size="sm" />;
142129

143130
if (isTopN) {
144131
return tct(
@@ -194,16 +181,3 @@ function DownsampledTooltip({
194181
</Tooltip>
195182
);
196183
}
197-
198-
const Placeholder = styled('div')<{width: number}>`
199-
display: inline-block;
200-
width: ${p => p.width}px;
201-
height: ${p => p.theme.fontSize.md};
202-
border-radius: ${p => p.theme.borderRadius};
203-
background-color: ${p => p.theme.backgroundTertiary};
204-
`;
205-
206-
const OffsetContainer = styled('span')`
207-
position: relative;
208-
top: 2px;
209-
`;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
} from 'sentry/views/explore/hooks/useChartInterval';
3535
import {TOP_EVENTS_LIMIT} from 'sentry/views/explore/hooks/useTopEvents';
3636
import {ConfidenceFooter} from 'sentry/views/explore/logs/confidenceFooter';
37-
import type {RawLogCounts} from 'sentry/views/explore/logs/useLogsQuery';
3837
import {
3938
useQueryParamsAggregateFields,
4039
useQueryParamsAggregateSortBys,
@@ -49,6 +48,7 @@ import {isGroupBy} from 'sentry/views/explore/queryParams/groupBy';
4948
import {Mode} from 'sentry/views/explore/queryParams/mode';
5049
import {isVisualize, type Visualize} from 'sentry/views/explore/queryParams/visualize';
5150
import {EXPLORE_CHART_TYPE_OPTIONS} from 'sentry/views/explore/spans/charts';
51+
import type {RawCounts} from 'sentry/views/explore/useRawCounts';
5252
import {
5353
combineConfidenceForSeries,
5454
prettifyAggregation,
@@ -58,7 +58,7 @@ import type {useSortedTimeSeries} from 'sentry/views/insights/common/queries/use
5858
import {getAlertsUrl} from 'sentry/views/insights/common/utils/getAlertsUrl';
5959

6060
interface LogsGraphProps {
61-
rawLogCounts: RawLogCounts;
61+
rawLogCounts: RawCounts;
6262
timeseriesResult: ReturnType<typeof useSortedTimeSeries>;
6363
}
6464

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/c
1212
import {IconChevron, IconEdit, IconRefresh} from 'sentry/icons';
1313
import {t} from 'sentry/locale';
1414
import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent';
15+
import {DiscoverDatasets} from 'sentry/utils/discover/types';
1516
import {parsePeriodToHours} from 'sentry/utils/duration/parsePeriodToHours';
1617
import {HOUR} from 'sentry/utils/formatters';
1718
import {useQueryClient, type InfiniteData} from 'sentry/utils/queryClient';
@@ -64,10 +65,7 @@ import {LogsAggregateTable} from 'sentry/views/explore/logs/tables/logsAggregate
6465
import {LogsInfiniteTable} from 'sentry/views/explore/logs/tables/logsInfiniteTable';
6566
import {type OurLogsResponseItem} from 'sentry/views/explore/logs/types';
6667
import {useLogsAggregatesTable} from 'sentry/views/explore/logs/useLogsAggregatesTable';
67-
import {
68-
getMaxIngestDelayTimestamp,
69-
useLogsRawCounts,
70-
} from 'sentry/views/explore/logs/useLogsQuery';
68+
import {getMaxIngestDelayTimestamp} from 'sentry/views/explore/logs/useLogsQuery';
7169
import {useLogsSearchQueryBuilderProps} from 'sentry/views/explore/logs/useLogsSearchQueryBuilderProps';
7270
import {useLogsTimeseries} from 'sentry/views/explore/logs/useLogsTimeseries';
7371
import {usePersistentLogsPageParameters} from 'sentry/views/explore/logs/usePersistentLogsPageParameters';
@@ -86,6 +84,7 @@ import {
8684
useSetQueryParamsMode,
8785
} from 'sentry/views/explore/queryParams/context';
8886
import {ColumnEditorModal} from 'sentry/views/explore/tables/columnEditorModal';
87+
import {useRawCounts} from 'sentry/views/explore/useRawCounts';
8988
import type {PickableDays} from 'sentry/views/explore/utils';
9089

9190
// eslint-disable-next-line no-restricted-imports,boundaries/element-types
@@ -132,7 +131,7 @@ export function LogsTabContent({
132131
}
133132
}, [autorefreshEnabled]);
134133

135-
const rawLogCounts = useLogsRawCounts();
134+
const rawLogCounts = useRawCounts({dataset: DiscoverDatasets.OURLOGS});
136135

137136
const yAxes = useMemo(() => {
138137
const uniqueYAxes = new Set(visualizes.map(visualize => visualize.yAxis));

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

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {useCallback, useEffect, useMemo, useState} from 'react';
22
import {logger} from '@sentry/react';
33

44
import {type ApiResult} from 'sentry/api';
5-
import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
65
import {useCaseInsensitivity} from 'sentry/components/searchQueryBuilder/hooks';
76
import {defined} from 'sentry/utils';
87
import {encodeSort, type EventsMetaType} from 'sentry/utils/discover/eventView';
@@ -11,7 +10,6 @@ import {DiscoverDatasets} from 'sentry/utils/discover/types';
1110
import parseLinkHeader from 'sentry/utils/parseLinkHeader';
1211
import {
1312
fetchDataQuery,
14-
useApiQuery,
1513
useInfiniteQuery,
1614
useQueryClient,
1715
type ApiQueryKey,
@@ -40,7 +38,6 @@ import {
4038
import {
4139
OurLogKnownFieldKey,
4240
type EventsLogsResult,
43-
type LogsAggregatesResult,
4441
} from 'sentry/views/explore/logs/types';
4542
import {
4643
isRowVisibleInVirtualStream,
@@ -747,79 +744,3 @@ export function useLogsQueryHighFidelity() {
747744
sortBys[0]?.kind === 'desc'
748745
);
749746
}
750-
751-
interface RawCount {
752-
count: number | null;
753-
isLoading: boolean;
754-
}
755-
756-
export interface RawLogCounts {
757-
highAccuracy: RawCount;
758-
normal: RawCount;
759-
}
760-
761-
export function useLogsRawCounts(): RawLogCounts {
762-
const organization = useOrganization();
763-
const {selection} = usePageFilters();
764-
765-
const baseQueryParams = {
766-
dataset: DiscoverDatasets.OURLOGS,
767-
project: selection.projects,
768-
environment: selection.environments,
769-
...normalizeDateTimeParams(selection.datetime),
770-
field: ['count(message)'],
771-
disableAggregateExtrapolation: '1',
772-
};
773-
774-
const normalScanQueryKey: ApiQueryKey = [
775-
`/organizations/${organization.slug}/events/`,
776-
{
777-
query: {
778-
...baseQueryParams,
779-
referrer: 'api.explore.logs.raw-count.normal',
780-
sampling: SAMPLING_MODE.NORMAL,
781-
},
782-
},
783-
];
784-
785-
const normalScanResult = useApiQuery<LogsAggregatesResult>(normalScanQueryKey, {
786-
enabled: true,
787-
staleTime: 0,
788-
});
789-
790-
const highestAccuracyScanQueryKey: ApiQueryKey = [
791-
`/organizations/${organization.slug}/events/`,
792-
{
793-
query: {
794-
...baseQueryParams,
795-
referrer: 'api.explore.logs.raw-count.high-accuracy',
796-
sampling: SAMPLING_MODE.HIGH_ACCURACY,
797-
},
798-
},
799-
];
800-
801-
const highestAccuracyScanResult = useApiQuery<LogsAggregatesResult>(
802-
highestAccuracyScanQueryKey,
803-
{
804-
enabled: true,
805-
staleTime: 0,
806-
}
807-
);
808-
809-
const normalScanCount = (normalScanResult.data?.data?.[0]?.['count(message)'] ||
810-
null) as number | null;
811-
const highestAccuracyScanCount = (highestAccuracyScanResult.data?.data?.[0]?.[
812-
'count(message)'
813-
] || null) as number | null;
814-
815-
return {
816-
normal: {
817-
isLoading: normalScanResult.isFetching,
818-
count: normalScanCount,
819-
},
820-
highAccuracy: {
821-
isLoading: highestAccuracyScanResult.isFetching,
822-
count: highestAccuracyScanCount,
823-
},
824-
};
825-
}

static/app/views/explore/spans/charts/confidenceFooter.spec.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('ConfidenceFooter', () => {
2020
);
2121

2222
expect(screen.getByTestId('wrapper')).toHaveTextContent(
23-
'Extrapolated from 100 span samples'
23+
'Extrapolated from 100 spans'
2424
);
2525
await userEvent.hover(screen.getByText('100'));
2626
expect(
@@ -41,7 +41,7 @@ describe('ConfidenceFooter', () => {
4141
);
4242

4343
expect(screen.getByTestId('wrapper')).toHaveTextContent(
44-
'Top 5 groups extrapolated from 100 span samples'
44+
'Extrapolated from 100 spans for top 5 groups'
4545
);
4646
await userEvent.hover(screen.getByText('100'));
4747
expect(
@@ -64,9 +64,7 @@ describe('ConfidenceFooter', () => {
6464
{wrapper: Wrapper}
6565
);
6666

67-
expect(screen.getByTestId('wrapper')).toHaveTextContent(
68-
'Extrapolated from 100 span samples'
69-
);
67+
expect(screen.getByTestId('wrapper')).toHaveTextContent('Span count: 100');
7068
});
7169
it('renders for full scan with grouping', () => {
7270
render(
@@ -80,7 +78,7 @@ describe('ConfidenceFooter', () => {
8078
);
8179

8280
expect(screen.getByTestId('wrapper')).toHaveTextContent(
83-
'Top 5 groups extrapolated from 100 span samples'
81+
'Span count for top 5 groups: 100'
8482
);
8583
});
8684
});
@@ -89,7 +87,7 @@ describe('ConfidenceFooter', () => {
8987
it('unextrapolated loading', () => {
9088
render(<ConfidenceFooter extrapolate={false} />, {wrapper: Wrapper});
9189

92-
expect(screen.getByTestId('wrapper')).toHaveTextContent('Span count: \u2026');
90+
expect(screen.getByTestId('loading-placeholder')).toBeInTheDocument();
9391
});
9492

9593
it('unextrapolated loaded', () => {
@@ -106,7 +104,7 @@ describe('ConfidenceFooter', () => {
106104
});
107105

108106
expect(screen.getByTestId('wrapper')).toHaveTextContent(
109-
'Top 5 groups span count: 100'
107+
'Span count for top 5 groups: 100'
110108
);
111109
});
112110
});

0 commit comments

Comments
 (0)