mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Remove running of duplicated metrics query (#30108)
* Remove metrics rerenders * Refactor * Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com> * Update public/app/plugins/datasource/prometheus/language_utils.ts Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com> * Add test * Update public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
This commit is contained in:
parent
ae1d2fb505
commit
8ad79a2635
@ -94,6 +94,55 @@ describe('PromQueryField', () => {
|
|||||||
checkMetricsInCascader(await screen.findByRole('button'), changedMetrics);
|
checkMetricsInCascader(await screen.findByRole('button'), changedMetrics);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not refreshes metrics when after rounding to minute time range does not change', async () => {
|
||||||
|
const defaultProps = {
|
||||||
|
query: { expr: '', refId: '' },
|
||||||
|
onRunQuery: () => {},
|
||||||
|
onChange: () => {},
|
||||||
|
history: [],
|
||||||
|
};
|
||||||
|
const metrics = ['foo', 'bar'];
|
||||||
|
const changedMetrics = ['foo', 'baz'];
|
||||||
|
const range = {
|
||||||
|
from: dateTime('2020-10-28T00:00:00Z'),
|
||||||
|
to: dateTime('2020-10-28T01:00:00Z'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const languageProvider = makeLanguageProvider({ metrics: [metrics, changedMetrics] });
|
||||||
|
const queryField = render(
|
||||||
|
<PromQueryField
|
||||||
|
// @ts-ignore
|
||||||
|
datasource={{ languageProvider }}
|
||||||
|
range={{
|
||||||
|
...range,
|
||||||
|
raw: range,
|
||||||
|
}}
|
||||||
|
{...defaultProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
checkMetricsInCascader(await screen.findByRole('button'), metrics);
|
||||||
|
|
||||||
|
const newRange = {
|
||||||
|
from: dateTime('2020-10-28T00:00:01Z'),
|
||||||
|
to: dateTime('2020-10-28T01:00:01Z'),
|
||||||
|
};
|
||||||
|
queryField.rerender(
|
||||||
|
<PromQueryField
|
||||||
|
// @ts-ignore
|
||||||
|
datasource={{ languageProvider }}
|
||||||
|
range={{
|
||||||
|
...newRange,
|
||||||
|
raw: newRange,
|
||||||
|
}}
|
||||||
|
{...defaultProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
let cascader = screen.getByRole('button');
|
||||||
|
// Should not show loading
|
||||||
|
expect(cascader.textContent).toContain('Metrics');
|
||||||
|
checkMetricsInCascader(await screen.findByRole('button'), metrics);
|
||||||
|
});
|
||||||
|
|
||||||
it('refreshes metrics when time range changes but dont show loading state', async () => {
|
it('refreshes metrics when time range changes but dont show loading state', async () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
query: { expr: '', refId: '' },
|
query: { expr: '', refId: '' },
|
||||||
|
@ -16,8 +16,16 @@ import { LanguageMap, languages as prismLanguages } from 'prismjs';
|
|||||||
|
|
||||||
// dom also includes Element polyfills
|
// dom also includes Element polyfills
|
||||||
import { PromQuery, PromOptions, PromMetricsMetadata } from '../types';
|
import { PromQuery, PromOptions, PromMetricsMetadata } from '../types';
|
||||||
|
import { roundMsToMin } from '../language_utils';
|
||||||
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
|
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
|
||||||
import { ExploreQueryFieldProps, QueryHint, isDataFrame, toLegacyResponseData, HistoryItem } from '@grafana/data';
|
import {
|
||||||
|
ExploreQueryFieldProps,
|
||||||
|
QueryHint,
|
||||||
|
isDataFrame,
|
||||||
|
toLegacyResponseData,
|
||||||
|
HistoryItem,
|
||||||
|
TimeRange,
|
||||||
|
} from '@grafana/data';
|
||||||
import { DOMUtil, SuggestionsState } from '@grafana/ui';
|
import { DOMUtil, SuggestionsState } from '@grafana/ui';
|
||||||
import { PrometheusDatasource } from '../datasource';
|
import { PrometheusDatasource } from '../datasource';
|
||||||
|
|
||||||
@ -168,17 +176,6 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
range,
|
range,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const rangeChanged =
|
|
||||||
range &&
|
|
||||||
prevProps.range &&
|
|
||||||
!_.isEqual(
|
|
||||||
{ from: range.from.valueOf(), to: range.to.valueOf() },
|
|
||||||
{
|
|
||||||
from: prevProps.range.from.valueOf(),
|
|
||||||
to: prevProps.range.to.valueOf(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (languageProvider !== prevProps.datasource.languageProvider) {
|
if (languageProvider !== prevProps.datasource.languageProvider) {
|
||||||
// We reset this only on DS change so we do not flesh loading state on every rangeChange which happens on every
|
// We reset this only on DS change so we do not flesh loading state on every rangeChange which happens on every
|
||||||
// query run if using relative range.
|
// query run if using relative range.
|
||||||
@ -188,7 +185,9 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (languageProvider !== prevProps.datasource.languageProvider || rangeChanged) {
|
const changedRangeToRefresh = this.rangeChangedToRefresh(range, prevProps.range);
|
||||||
|
// We want to refresh metrics when language provider changes and/or when range changes (we round up intervals to a minute)
|
||||||
|
if (languageProvider !== prevProps.datasource.languageProvider || changedRangeToRefresh) {
|
||||||
this.refreshMetrics();
|
this.refreshMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +236,16 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rangeChangedToRefresh(range?: TimeRange, prevRange?: TimeRange): boolean {
|
||||||
|
if (range && prevRange) {
|
||||||
|
const sameMinuteFrom = roundMsToMin(range.from.valueOf()) === roundMsToMin(prevRange.from.valueOf());
|
||||||
|
const sameMinuteTo = roundMsToMin(range.to.valueOf()) === roundMsToMin(prevRange.to.valueOf());
|
||||||
|
// If both are same, don't need to refresh.
|
||||||
|
return !(sameMinuteFrom && sameMinuteTo);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onChangeMetrics = (values: string[], selectedOptions: CascaderOption[]) => {
|
onChangeMetrics = (values: string[], selectedOptions: CascaderOption[]) => {
|
||||||
let query;
|
let query;
|
||||||
if (selectedOptions.length === 1) {
|
if (selectedOptions.length === 1) {
|
||||||
|
@ -5,7 +5,13 @@ import { Value } from 'slate';
|
|||||||
import { dateTime, HistoryItem, LanguageProvider } from '@grafana/data';
|
import { dateTime, HistoryItem, LanguageProvider } from '@grafana/data';
|
||||||
import { CompletionItem, CompletionItemGroup, TypeaheadInput, TypeaheadOutput } from '@grafana/ui';
|
import { CompletionItem, CompletionItemGroup, TypeaheadInput, TypeaheadOutput } from '@grafana/ui';
|
||||||
|
|
||||||
import { fixSummariesMetadata, parseSelector, processHistogramLabels, processLabels } from './language_utils';
|
import {
|
||||||
|
fixSummariesMetadata,
|
||||||
|
parseSelector,
|
||||||
|
processHistogramLabels,
|
||||||
|
processLabels,
|
||||||
|
roundSecToMin,
|
||||||
|
} from './language_utils';
|
||||||
import PromqlSyntax, { FUNCTIONS, RATE_RANGES } from './promql';
|
import PromqlSyntax, { FUNCTIONS, RATE_RANGES } from './promql';
|
||||||
|
|
||||||
import { PrometheusDatasource } from './datasource';
|
import { PrometheusDatasource } from './datasource';
|
||||||
@ -421,10 +427,6 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
return { [key]: data };
|
return { [key]: data };
|
||||||
};
|
};
|
||||||
|
|
||||||
roundToMinutes(seconds: number): number {
|
|
||||||
return Math.floor(seconds / 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch labels for a series. This is cached by it's args but also by the global timeRange currently selected as
|
* Fetch labels for a series. This is cached by it's args but also by the global timeRange currently selected as
|
||||||
* they can change over requested time.
|
* they can change over requested time.
|
||||||
@ -443,8 +445,8 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
// The rounding may seem strange but makes relative intervals like now-1h less prone to need separate request every
|
// The rounding may seem strange but makes relative intervals like now-1h less prone to need separate request every
|
||||||
// millisecond while still actually getting all the keys for the correct interval. This still can create problems
|
// millisecond while still actually getting all the keys for the correct interval. This still can create problems
|
||||||
// when user does not the newest values for a minute if already cached.
|
// when user does not the newest values for a minute if already cached.
|
||||||
params.set('start', this.roundToMinutes(tRange['start']).toString());
|
params.set('start', roundSecToMin(tRange['start']).toString());
|
||||||
params.set('end', this.roundToMinutes(tRange['end']).toString());
|
params.set('end', roundSecToMin(tRange['end']).toString());
|
||||||
params.append('withName', withName ? 'true' : 'false');
|
params.append('withName', withName ? 'true' : 'false');
|
||||||
const cacheKey = `/api/v1/series?${params.toString()}`;
|
const cacheKey = `/api/v1/series?${params.toString()}`;
|
||||||
let value = this.labelsCache.get(cacheKey);
|
let value = this.labelsCache.get(cacheKey);
|
||||||
|
@ -185,3 +185,11 @@ export function fixSummariesMetadata(metadata: PromMetricsMetadata): PromMetrics
|
|||||||
}
|
}
|
||||||
return { ...metadata, ...summaryMetadata };
|
return { ...metadata, ...summaryMetadata };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function roundMsToMin(milliseconds: number): number {
|
||||||
|
return roundSecToMin(milliseconds / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function roundSecToMin(seconds: number): number {
|
||||||
|
return Math.floor(seconds / 60);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user