Skip to content

Commit 260ff86

Browse files
authored
[BUGFIX] Prometheus calculate interval and minstep for query replacement (#475)
Signed-off-by: Seyed Mahmoud SHAHROKNI <[email protected]>
1 parent 18e690b commit 260ff86

File tree

3 files changed

+58
-9
lines changed

3 files changed

+58
-9
lines changed

prometheus/src/components/PromQLEditor.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,21 @@ export type PromQLEditorProps = {
3333
completeConfig: CompleteConfiguration;
3434
datasource: PrometheusDatasourceSelector;
3535
isReadOnly?: boolean;
36+
treeViewMetadata?: {
37+
minStepMs: number;
38+
intervalMs: number;
39+
};
3640
} & Omit<ReactCodeMirrorProps, 'theme' | 'extensions'>;
3741

38-
export function PromQLEditor({ completeConfig, datasource, isReadOnly, ...rest }: PromQLEditorProps): ReactElement {
42+
export function PromQLEditor({
43+
completeConfig,
44+
datasource,
45+
isReadOnly,
46+
treeViewMetadata,
47+
...rest
48+
}: PromQLEditorProps): ReactElement {
3949
const theme = useTheme();
50+
4051
const isDarkMode = theme.palette.mode === 'dark';
4152
const [isTreeViewVisible, setTreeViewVisible] = useState(false);
4253
const readOnly = isReadOnly ?? false;
@@ -46,12 +57,9 @@ export function PromQLEditor({ completeConfig, datasource, isReadOnly, ...rest }
4657
}, [completeConfig]);
4758

4859
let queryExpr = useReplaceVariablesInString(rest.value);
49-
if (queryExpr) {
50-
// TODO placeholder values for steps to be replaced with actual values
51-
// Looks like providing proper values involves some refactoring: currently we'd need to rely on the timeseries query context,
52-
// but these step values are actually computed independently / before the queries are getting fired, so it's useless to fire
53-
// queries here, so maybe we should extract this part to independant hook(s), to be reused here?
54-
queryExpr = replacePromBuiltinVariables(queryExpr, 12345, 12345);
60+
if (queryExpr && treeViewMetadata) {
61+
const { minStepMs, intervalMs } = treeViewMetadata;
62+
queryExpr = replacePromBuiltinVariables(queryExpr, minStepMs, intervalMs);
5563
}
5664

5765
const { data: parseQueryResponse, isLoading, error } = useParseQuery(queryExpr ?? '', datasource, isTreeViewVisible);

prometheus/src/plugins/prometheus-time-series-query/PrometheusTimeSeriesQueryEditor.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,24 @@ import { produce } from 'immer';
1515
import {
1616
DatasourceSelect,
1717
DatasourceSelectProps,
18+
replaceVariables,
19+
useAllVariableValues,
1820
useDatasource,
1921
useDatasourceClient,
2022
useDatasourceSelectValueToSelector,
23+
useSuggestedStepMs,
24+
useTimeRange,
2125
} from '@perses-dev/plugin-system';
2226
import { useId } from '@perses-dev/components';
2327
import { FormControl, Stack, TextField } from '@mui/material';
24-
import { ReactElement } from 'react';
28+
import { ReactElement, useContext, useMemo } from 'react';
29+
import { PanelEditorContext } from '@perses-dev/dashboards';
2530
import {
2631
DEFAULT_PROM,
2732
DurationString,
33+
getDurationStringSeconds,
34+
getPrometheusTimeRange,
35+
getRangeStep,
2836
isDefaultPromSelector,
2937
isPrometheusDatasourceSelector,
3038
PROM_DATASOURCE_KIND,
@@ -39,7 +47,6 @@ import {
3947
useFormatState,
4048
useMinStepState,
4149
} from './query-editor-model';
42-
4350
/**
4451
* The options editor component for editing a PrometheusTimeSeriesQuery's spec.
4552
*/
@@ -91,6 +98,37 @@ export function PrometheusTimeSeriesQueryEditor(props: PrometheusTimeSeriesQuery
9198
throw new Error('Got unexpected non-Prometheus datasource selector');
9299
};
93100

101+
const variableState = useAllVariableValues();
102+
const { absoluteTimeRange } = useTimeRange();
103+
const panelEditorContext = useContext(PanelEditorContext);
104+
const suggestedStepMs = useSuggestedStepMs(panelEditorContext?.preview.previewPanelWidth);
105+
106+
const minStepMs = useMemo(() => {
107+
/* Try catch is necessary, because when the minStep value is being typed, it will be valid when the duration unit is added. Example: 2m = 2 + m */
108+
try {
109+
const durationsSeconds = getDurationStringSeconds(
110+
replaceVariables(minStepPlaceholder, variableState) as DurationString
111+
);
112+
return durationsSeconds !== undefined ? durationsSeconds * 1000 : undefined;
113+
} catch {
114+
return undefined;
115+
}
116+
}, [variableState, minStepPlaceholder]);
117+
118+
const intervalMs = useMemo(() => {
119+
const minStepSeconds = (minStepMs ?? 0) / 1000;
120+
return getRangeStep(getPrometheusTimeRange(absoluteTimeRange), minStepSeconds, undefined, suggestedStepMs) * 1000;
121+
}, [absoluteTimeRange, minStepMs, suggestedStepMs]);
122+
123+
const treeViewMetadata = useMemo(() => {
124+
return minStepMs && intervalMs
125+
? {
126+
minStepMs,
127+
intervalMs,
128+
}
129+
: undefined;
130+
}, [minStepMs, intervalMs]);
131+
94132
return (
95133
<Stack spacing={2}>
96134
<FormControl margin="dense" fullWidth={false}>
@@ -111,6 +149,7 @@ export function PrometheusTimeSeriesQueryEditor(props: PrometheusTimeSeriesQuery
111149
onChange={handleQueryChange}
112150
onBlur={handleQueryBlur}
113151
isReadOnly={isReadonly}
152+
treeViewMetadata={treeViewMetadata}
114153
/>
115154
<Stack direction="row" spacing={2}>
116155
<TextField

prometheus/src/plugins/prometheus-time-series-query/get-time-series-data.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const getTimeSeriesData: TimeSeriesQueryPlugin<PrometheusTimeSeriesQueryS
7373
// TODO add a validation check to make sure the variable is a DurationString, to avoid the back & forth cast here
7474
replaceVariables(spec.minStep as string, context.variableState) as DurationString
7575
) ?? datasourceScrapeInterval;
76+
7677
const timeRange = getPrometheusTimeRange(context.timeRange);
7778
const step = getRangeStep(timeRange, minStep, undefined, context.suggestedStepMs); // TODO: resolution
7879

@@ -99,6 +100,7 @@ export const getTimeSeriesData: TimeSeriesQueryPlugin<PrometheusTimeSeriesQueryS
99100
// Replace variable placeholders in PromQL query
100101
const intervalMs = step * 1000;
101102
const minStepMs = minStep * 1000;
103+
102104
let query = replacePromBuiltinVariables(spec.query, minStepMs, intervalMs);
103105
query = replaceVariables(query, context.variableState);
104106

0 commit comments

Comments
 (0)