Skip to content

Commit 79e4bba

Browse files
authored
feat(tracemetrics): Add extrapolation warning iff we scan partial data (#101517)
Copy the logs confidence footer to render the confidence messaging. However, we _only_ want to show the message if we've hit partial data, otherwise there is no messaging.
1 parent e13449b commit 79e4bba

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import styled from '@emotion/styled';
2+
3+
import {Tooltip} from 'sentry/components/core/tooltip';
4+
import Count from 'sentry/components/count';
5+
import {t, tct} from 'sentry/locale';
6+
import type {Confidence} from 'sentry/types/organization';
7+
import {defined} from 'sentry/utils';
8+
import {
9+
Container,
10+
usePreviouslyLoaded,
11+
} from 'sentry/views/explore/components/chart/chartFooter';
12+
import type {ChartInfo} from 'sentry/views/explore/components/chart/types';
13+
14+
interface ConfidenceFooterProps {
15+
chartInfo: ChartInfo;
16+
isLoading: boolean;
17+
}
18+
19+
export function ConfidenceFooter({
20+
chartInfo: currentChartInfo,
21+
isLoading,
22+
}: ConfidenceFooterProps) {
23+
const chartInfo = usePreviouslyLoaded(currentChartInfo, isLoading);
24+
25+
return (
26+
<Container>
27+
<ConfidenceMessage
28+
isLoading={isLoading}
29+
confidence={chartInfo.confidence}
30+
dataScanned={chartInfo.dataScanned}
31+
isSampled={chartInfo.isSampled}
32+
sampleCount={chartInfo.sampleCount}
33+
topEvents={chartInfo.topEvents}
34+
/>
35+
</Container>
36+
);
37+
}
38+
39+
interface ConfidenceMessageProps {
40+
isLoading: boolean;
41+
confidence?: Confidence;
42+
dataScanned?: 'full' | 'partial';
43+
isSampled?: boolean | null;
44+
sampleCount?: number;
45+
topEvents?: number;
46+
}
47+
48+
function ConfidenceMessage({
49+
sampleCount,
50+
dataScanned,
51+
confidence,
52+
topEvents,
53+
isLoading,
54+
isSampled,
55+
}: ConfidenceMessageProps) {
56+
const isTopN = defined(topEvents) && topEvents > 1;
57+
58+
if (!defined(sampleCount) || isLoading) {
59+
return <Placeholder />;
60+
}
61+
62+
const noSampling = defined(isSampled) && !isSampled;
63+
const sampleCountComponent = <Count value={sampleCount} />;
64+
65+
if (dataScanned === 'full') {
66+
// If the full data was scanned, we do not want to expose any
67+
// sample count information because we deem it as unnecessary.
68+
return null;
69+
}
70+
71+
if (confidence === 'low') {
72+
const lowAccuracyFullSampleCount = <LowAccuracyFullTooltip noSampling={noSampling} />;
73+
74+
if (isTopN) {
75+
return tct(
76+
'Top [topEvents] groups extrapolated from [tooltip:[sampleCountComponent] metrics]',
77+
{
78+
topEvents,
79+
tooltip: lowAccuracyFullSampleCount,
80+
sampleCountComponent,
81+
}
82+
);
83+
}
84+
85+
return tct('Extrapolated from [tooltip:[sampleCountComponent] metrics]', {
86+
tooltip: lowAccuracyFullSampleCount,
87+
sampleCountComponent,
88+
});
89+
}
90+
91+
if (isTopN) {
92+
return tct(
93+
'Top [topEvents] groups extrapolated from [sampleCountComponent] metrics',
94+
{
95+
topEvents,
96+
sampleCountComponent,
97+
}
98+
);
99+
}
100+
101+
return tct('Extrapolated from [sampleCountComponent] metrics', {
102+
sampleCountComponent,
103+
});
104+
}
105+
106+
function LowAccuracyFullTooltip({
107+
noSampling,
108+
children,
109+
}: {
110+
noSampling: boolean;
111+
children?: React.ReactNode;
112+
}) {
113+
return (
114+
<Tooltip
115+
title={
116+
<div>
117+
{t('Some metrics are not shown due to the large volume of metrics.')}
118+
<br />
119+
<br />
120+
{t('Try reducing the date range or number of projects.')}
121+
</div>
122+
}
123+
disabled={noSampling}
124+
maxWidth={270}
125+
showUnderline
126+
>
127+
{children}
128+
</Tooltip>
129+
);
130+
}
131+
132+
const Placeholder = styled('div')`
133+
width: 180px;
134+
height: ${p => p.theme.fontSize.md};
135+
border-radius: ${p => p.theme.borderRadius};
136+
background-color: ${p => p.theme.backgroundTertiary};
137+
`;

static/app/views/explore/metrics/metricGraph.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {Widget} from 'sentry/views/dashboards/widgets/widget/widget';
1010
import {ChartVisualization} from 'sentry/views/explore/components/chart/chartVisualization';
1111
import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
1212
import {TOP_EVENTS_LIMIT} from 'sentry/views/explore/hooks/useTopEvents';
13+
import {ConfidenceFooter} from 'sentry/views/explore/metrics/confidenceFooter';
1314
import {
1415
useMetricVisualize,
1516
useSetMetricVisualize,
@@ -123,11 +124,23 @@ function Graph({onChartTypeChange, timeseriesResult, queryIndex, visualize}: Gra
123124
</Fragment>
124125
);
125126

127+
// We explicitly only want to show the confidence footer if we have
128+
// scanned partial data.
129+
const showConfidenceFooter =
130+
chartInfo.dataScanned !== 'full' && !timeseriesResult.isLoading;
126131
return (
127132
<Widget
128133
Title={Title}
129134
Actions={Actions}
130135
Visualization={visualize.visible && <ChartVisualization chartInfo={chartInfo} />}
136+
Footer={
137+
showConfidenceFooter && (
138+
<ConfidenceFooter
139+
chartInfo={chartInfo}
140+
isLoading={timeseriesResult.isLoading}
141+
/>
142+
)
143+
}
131144
revealActions="always"
132145
borderless
133146
/>

0 commit comments

Comments
 (0)