Skip to content

Commit d0e8353

Browse files
authored
Merge pull request #232 from adwait-godbole/graph-resolution-input
prometheus: Add resolution input for metrics
2 parents 6d20135 + 449aecb commit d0e8353

File tree

12 files changed

+248
-69
lines changed

12 files changed

+248
-69
lines changed

prometheus/src/components/Chart/CPUChart/CPUChart.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface CPUChartProps {
1717
query: string;
1818
prometheusPrefix: string;
1919
interval: string;
20+
resolution: string;
2021
autoRefresh: boolean;
2122
subPath: string;
2223
}

prometheus/src/components/Chart/Chart/Chart.tsx

+18-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { EmptyContent, Loader } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
22
import { Box, useTheme } from '@mui/material';
3-
import { useEffect, useState } from 'react';
3+
import { useEffect, useMemo, useState } from 'react';
44
import {
55
Area,
66
AreaChart,
@@ -11,7 +11,7 @@ import {
1111
XAxis,
1212
YAxis,
1313
} from 'recharts';
14-
import { getTimeRange } from '../../../util';
14+
import { getTimeRangeAndStepSize } from '../../../util';
1515

1616
/**
1717
* Props for the Chart component.
@@ -40,6 +40,7 @@ export interface ChartProps {
4040
}>;
4141
fetchMetrics: (query: object) => Promise<any>;
4242
interval: string;
43+
resolution: string;
4344
prometheusPrefix: string;
4445
autoRefresh: boolean;
4546
xAxisProps: {
@@ -64,14 +65,19 @@ export default function Chart(props: ChartProps) {
6465
const [state, setState] = useState<ChartState | null>(null);
6566
const [error, setError] = useState<string | null>(null);
6667
const theme = useTheme();
67-
const timeRange = getTimeRange(props.interval);
68+
const {
69+
from: fromTimestamp,
70+
to: toTimestamp,
71+
step: stepSize,
72+
} = useMemo(
73+
() => getTimeRangeAndStepSize(props.interval, props.resolution),
74+
[props.interval, props.resolution]
75+
);
6876

6977
const fetchMetricsData = async (
7078
plots: Array<{ query: string; name: string; dataProcessor: (data: any) => any }>,
7179
firstLoad: boolean = false
7280
) => {
73-
const { from, to, step } = getTimeRange(props.interval);
74-
7581
const fetchedMetrics: {
7682
[key: string]: {
7783
data: { timestamp: number; y: number }[];
@@ -88,9 +94,9 @@ export default function Chart(props: ChartProps) {
8894
response = await fetchMetrics({
8995
prefix: props.prometheusPrefix,
9096
query: plot.query,
91-
from: from,
92-
to: to,
93-
step: step,
97+
from: fromTimestamp,
98+
to: toTimestamp,
99+
step: stepSize,
94100
subPath: props.subPath,
95101
});
96102
} catch (e) {
@@ -140,7 +146,7 @@ export default function Chart(props: ChartProps) {
140146
// Fetch data on initial load
141147
useEffect(() => {
142148
fetchMetricsData(props.plots, true);
143-
}, []);
149+
}, [props.interval, props.resolution]);
144150

145151
// if reload is true, set up a timer to refresh data every 10 seconds
146152
// Set up a timer to refresh data every 10 seconds
@@ -154,7 +160,7 @@ export default function Chart(props: ChartProps) {
154160
clearInterval(refreshInterval);
155161
};
156162
}
157-
}, [props.autoRefresh, props.plots, props.interval]);
163+
}, [props.autoRefresh, props.plots, props.interval, props.resolution]);
158164

159165
let chartContent;
160166

@@ -166,7 +172,7 @@ export default function Chart(props: ChartProps) {
166172
fontSize={12}
167173
{...xAxisProps}
168174
type="number"
169-
domain={[timeRange.from, timeRange.to]}
175+
domain={[fromTimestamp, toTimestamp]}
170176
allowDataOverflow
171177
/>
172178
<YAxis fontSize={14} stroke={theme.palette.chartStyles.labelColor} {...yAxisProps} />
@@ -179,6 +185,7 @@ export default function Chart(props: ChartProps) {
179185
<CartesianGrid strokeDasharray="2 4" stroke={theme.palette.divider} vertical={false} />
180186
{props.plots.map(plot => (
181187
<Area
188+
key={plot.name}
182189
stackId="1"
183190
type="step"
184191
dataKey={plot.name}

prometheus/src/components/Chart/Chart/chart.stories.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ const Template: StoryFn<ChartProps> = () => {
336336
},
337337
]}
338338
interval="10m"
339+
resolution="medium"
339340
autoRefresh={false}
340341
xAxisProps={XTickProps}
341342
yAxisProps={YTickProps}

prometheus/src/components/Chart/DiskChart/DiskChart.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface DiskChartProps {
1818
usageQuery: string;
1919
capacityQuery: string;
2020
interval: string;
21+
resolution: string;
2122
prometheusPrefix: string;
2223
autoRefresh: boolean;
2324
subPath: string;

prometheus/src/components/Chart/DiskMetricsChart/DiskMetricsChart.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { SectionBox } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
22
import { Loader } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
33
import { useCluster } from '@kinvolk/headlamp-plugin/lib/lib/k8s';
4-
import { Box, Icon, IconButton } from '@mui/material';
54
import Alert from '@mui/material/Alert';
5+
import Box from '@mui/material/Box';
6+
import Icon from '@mui/material/Icon';
7+
import IconButton from '@mui/material/IconButton';
68
import { useEffect, useState } from 'react';
79
import {
810
getConfigStore,
911
getPrometheusInterval,
1012
getPrometheusPrefix,
13+
getPrometheusResolution,
1114
getPrometheusSubPath,
1215
} from '../../../util';
1316
import { PrometheusNotFoundBanner } from '../common';
@@ -76,6 +79,7 @@ export function DiskMetricsChart(props: DiskMetricsChartProps) {
7679
}
7780

7881
const interval = getPrometheusInterval(cluster);
82+
const resolution = getPrometheusResolution(cluster);
7983
const subPath = getPrometheusSubPath(cluster);
8084
return (
8185
<SectionBox>
@@ -116,6 +120,7 @@ export function DiskMetricsChart(props: DiskMetricsChartProps) {
116120
usageQuery={props.usageQuery}
117121
capacityQuery={props.capacityQuery}
118122
interval={interval}
123+
resolution={resolution}
119124
autoRefresh={refresh}
120125
prometheusPrefix={prometheusPrefix}
121126
subPath={subPath}

prometheus/src/components/Chart/FilesystemChart/FilesystemChart.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface FilesystemChartProps {
1919
readQuery: string;
2020
writeQuery: string;
2121
interval: string;
22+
resolution: string;
2223
prometheusPrefix: string;
2324
autoRefresh: boolean;
2425
subPath: string;

prometheus/src/components/Chart/GenericMetricsChart/GenericMetricsChart.tsx

+37-9
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ import { Icon } from '@iconify/react';
22
import { Loader } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
33
import { SectionBox } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
44
import { useCluster } from '@kinvolk/headlamp-plugin/lib/k8s';
5-
import {
6-
Box,
7-
Button,
8-
MenuItem,
9-
Paper,
10-
Select,
11-
ToggleButton,
12-
ToggleButtonGroup,
13-
} from '@mui/material';
145
import Alert from '@mui/material/Alert';
6+
import Box from '@mui/material/Box';
7+
import Button from '@mui/material/Button';
8+
import ListSubheader from '@mui/material/ListSubheader';
9+
import MenuItem from '@mui/material/MenuItem';
10+
import Paper from '@mui/material/Paper';
11+
import Select from '@mui/material/Select';
12+
import ToggleButton from '@mui/material/ToggleButton';
13+
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
1514
import { useEffect, useState } from 'react';
1615
import {
1716
getConfigStore,
1817
getPrometheusInterval,
1918
getPrometheusPrefix,
19+
getPrometheusResolution,
2020
getPrometheusSubPath,
2121
} from '../../../util';
2222
import { PrometheusNotFoundBanner } from '../common';
@@ -96,9 +96,11 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
9696
};
9797

9898
const interval = getPrometheusInterval(cluster);
99+
const graphResolution = getPrometheusResolution(cluster);
99100
const subPath = getPrometheusSubPath(cluster);
100101

101102
const [timespan, setTimespan] = useState(interval ?? '1h');
103+
const [resolution, setResolution] = useState(graphResolution ?? 'medium');
102104

103105
if (!isVisible) {
104106
return null;
@@ -160,6 +162,28 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
160162
<MenuItem value={'14d'}>14 days</MenuItem>
161163
</Select>
162164
</Box>
165+
<Box>
166+
<Select
167+
variant="outlined"
168+
size="small"
169+
name="Time"
170+
value={resolution}
171+
onChange={e => setResolution(e.target.value)}
172+
>
173+
<ListSubheader>Automatic resolution</ListSubheader>
174+
<MenuItem value="low">Low res.</MenuItem>
175+
<MenuItem value="medium">Medium res.</MenuItem>
176+
<MenuItem value="high">High res.</MenuItem>
177+
178+
<ListSubheader>Fixed resolution</ListSubheader>
179+
<MenuItem value="10s">10s</MenuItem>
180+
<MenuItem value="30s">30s</MenuItem>
181+
<MenuItem value="1m">1m</MenuItem>
182+
<MenuItem value="5m">5m</MenuItem>
183+
<MenuItem value="15m">15m</MenuItem>
184+
<MenuItem value="1h">1h</MenuItem>
185+
</Select>
186+
</Box>
163187
</Box>
164188
)}
165189
{state === prometheusState.INSTALLED ? (
@@ -174,6 +198,7 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
174198
autoRefresh={refresh}
175199
prometheusPrefix={prometheusPrefix}
176200
interval={timespan}
201+
resolution={resolution}
177202
subPath={subPath}
178203
/>
179204
)}
@@ -183,6 +208,7 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
183208
autoRefresh={refresh}
184209
prometheusPrefix={prometheusPrefix}
185210
interval={timespan}
211+
resolution={resolution}
186212
subPath={subPath}
187213
/>
188214
)}
@@ -192,6 +218,7 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
192218
txQuery={props.networkTxQuery}
193219
autoRefresh={refresh}
194220
interval={timespan}
221+
resolution={resolution}
195222
prometheusPrefix={prometheusPrefix}
196223
subPath={subPath}
197224
/>
@@ -202,6 +229,7 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
202229
writeQuery={props.filesystemWriteQuery}
203230
autoRefresh={refresh}
204231
interval={timespan}
232+
resolution={resolution}
205233
prometheusPrefix={prometheusPrefix}
206234
subPath={subPath}
207235
/>

prometheus/src/components/Chart/MemoryChart/MemoryChart.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface MemoryChartProps {
1818
query: string;
1919
prometheusPrefix: string;
2020
interval: string;
21+
resolution: string;
2122
autoRefresh: boolean;
2223
subPath: string;
2324
}

prometheus/src/components/Chart/NetworkChart/NetworkChart.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface NetworkChartProps {
1919
rxQuery: string;
2020
txQuery: string;
2121
interval: string;
22+
resolution: string;
2223
prometheusPrefix: string;
2324
autoRefresh: boolean;
2425
subPath: string;

prometheus/src/components/Settings/Settings.tsx

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NameValueTable } from '@kinvolk/headlamp-plugin/lib/components/common';
22
import { useClustersConf } from '@kinvolk/headlamp-plugin/lib/k8s';
33
import Box from '@mui/material/Box';
4+
import ListSubheader from '@mui/material/ListSubheader';
45
import MenuItem from '@mui/material/MenuItem';
56
import Select from '@mui/material/Select';
67
import Switch from '@mui/material/Switch';
@@ -23,7 +24,7 @@ function isValidAddress(address: string): boolean {
2324
/**
2425
* Props for the Settings component.
2526
* @interface SettingsProps
26-
* @property {Object.<string, {isMetricsEnabled?: boolean, autoDetect?: boolean, address?: string, defaultTimespan?: string}>} data - Configuration data for each cluster
27+
* @property {Object.<string, {isMetricsEnabled?: boolean, autoDetect?: boolean, address?: string, defaultTimespan?: string, defaultResolution?: string}>} data - Configuration data for each cluster
2728
* @property {Function} onDataChange - Callback function when data changes
2829
*/
2930
interface SettingsProps {
@@ -35,6 +36,7 @@ interface SettingsProps {
3536
address?: string;
3637
subPath?: string;
3738
defaultTimespan?: string;
39+
defaultResolution?: string;
3840
}
3941
>;
4042
onDataChange: (newData: SettingsProps['data']) => void;
@@ -64,6 +66,7 @@ export function Settings(props: SettingsProps) {
6466
isMetricsEnabled: true,
6567
autoDetect: true,
6668
defaultTimespan: '24h',
69+
defaultResolution: 'medium',
6770
},
6871
});
6972
}
@@ -164,7 +167,7 @@ export function Settings(props: SettingsProps) {
164167
),
165168
},
166169
{
167-
name: 'Default timespan',
170+
name: 'Default Timespan',
168171
value: (
169172
<Select
170173
disabled={!isMetricsEnabled}
@@ -196,6 +199,37 @@ export function Settings(props: SettingsProps) {
196199
</Select>
197200
),
198201
},
202+
{
203+
name: 'Default Resolution',
204+
value: (
205+
<Select
206+
disabled={!isMetricsEnabled}
207+
value={data?.[selectedCluster]?.defaultResolution || 'medium'}
208+
onChange={e =>
209+
onDataChange({
210+
...(data || {}),
211+
[selectedCluster]: {
212+
...((data || {})[selectedCluster] || {}),
213+
defaultResolution: e.target.value,
214+
},
215+
})
216+
}
217+
>
218+
<ListSubheader>Automatic resolution</ListSubheader>
219+
<MenuItem value="low">Low res.</MenuItem>
220+
<MenuItem value="medium">Medium res.</MenuItem>
221+
<MenuItem value="high">High res.</MenuItem>
222+
223+
<ListSubheader>Fixed resolution</ListSubheader>
224+
<MenuItem value="10s">10s</MenuItem>
225+
<MenuItem value="30s">30s</MenuItem>
226+
<MenuItem value="1m">1m</MenuItem>
227+
<MenuItem value="5m">5m</MenuItem>
228+
<MenuItem value="15m">15m</MenuItem>
229+
<MenuItem value="1h">1h</MenuItem>
230+
</Select>
231+
),
232+
},
199233
];
200234

201235
return (

0 commit comments

Comments
 (0)