Commit 0c703088 by Kemal Akkoyun Committed by GitHub

Prometheus: Add time range parameters to labels API (#27548)

* Add time range parameters to labels API

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Fix minor issues

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Add range to explore component

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Add range to query component

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Cache metric names for time range

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

* Remove unused method

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Only compare the ranges

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

* Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
parent 5c1c5f41
......@@ -4,7 +4,7 @@ import { act } from 'react-dom/test-utils';
import PromExploreQueryEditor from './PromExploreQueryEditor';
import { PrometheusDatasource } from '../datasource';
import { PromQuery } from '../types';
import { LoadingState, PanelData, toUtc } from '@grafana/data';
import { LoadingState, PanelData, toUtc, TimeRange } from '@grafana/data';
const setup = (renderMethod: any, propOverrides?: object) => {
const datasourceMock: unknown = {};
......@@ -12,6 +12,14 @@ const setup = (renderMethod: any, propOverrides?: object) => {
const onRunQuery = jest.fn();
const onChange = jest.fn();
const query: PromQuery = { expr: '', refId: 'A', interval: '1s' };
const range: TimeRange = {
from: toUtc('2020-01-01', 'YYYY-MM-DD'),
to: toUtc('2020-01-02', 'YYYY-MM-DD'),
raw: {
from: toUtc('2020-01-01', 'YYYY-MM-DD'),
to: toUtc('2020-01-02', 'YYYY-MM-DD'),
},
};
const data: PanelData = {
state: LoadingState.NotStarted,
series: [],
......@@ -50,6 +58,7 @@ const setup = (renderMethod: any, propOverrides?: object) => {
const props: any = {
query,
data,
range,
datasource,
exploreMode,
history,
......
......@@ -12,7 +12,7 @@ import { PromExploreExtraField } from './PromExploreExtraField';
export type Props = ExploreQueryFieldProps<PrometheusDatasource, PromQuery, PromOptions>;
export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
const { query, data, datasource, history, onChange, onRunQuery } = props;
const { range, query, data, datasource, history, onChange, onRunQuery } = props;
function onChangeQueryStep(value: string) {
const { query, onChange } = props;
......@@ -49,6 +49,7 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
<PromQueryField
datasource={datasource}
query={query}
range={range}
onRunQuery={onRunQuery}
onChange={onChange}
onBlur={() => {}}
......
......@@ -96,7 +96,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
};
render() {
const { datasource, query, data } = this.props;
const { datasource, query, range, data } = this.props;
const { formatOption, instant, interval, intervalFactorOption, legendFormat } = this.state;
return (
......@@ -104,6 +104,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
<PromQueryField
datasource={datasource}
query={query}
range={range}
onRunQuery={this.onRunQuery}
onChange={this.onFieldChange}
history={[]}
......
......@@ -17,7 +17,14 @@ import Prism from 'prismjs';
// dom also includes Element polyfills
import { PromQuery, PromOptions, PromMetricsMetadata } from '../types';
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
import { ExploreQueryFieldProps, QueryHint, isDataFrame, toLegacyResponseData, HistoryItem } from '@grafana/data';
import {
ExploreQueryFieldProps,
QueryHint,
isDataFrame,
toLegacyResponseData,
HistoryItem,
AbsoluteTimeRange,
} from '@grafana/data';
import { DOMUtil, SuggestionsState } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource';
......@@ -163,9 +170,24 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
const {
data,
datasource: { languageProvider },
range,
} = this.props;
if (languageProvider !== prevProps.datasource.languageProvider) {
let refreshed = false;
if (range && prevProps.range) {
const absoluteRange: AbsoluteTimeRange = { from: range.from.valueOf(), to: range.to.valueOf() };
const prevAbsoluteRange: AbsoluteTimeRange = {
from: prevProps.range.from.valueOf(),
to: prevProps.range.to.valueOf(),
};
if (!_.isEqual(absoluteRange, prevAbsoluteRange)) {
this.refreshMetrics();
refreshed = true;
}
}
if (!refreshed && languageProvider !== prevProps.datasource.languageProvider) {
this.refreshMetrics();
}
......
......@@ -57,5 +57,15 @@ exports[`PromExploreQueryEditor should render component 1`] = `
"refId": "A",
}
}
range={
Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
}
}
/>
`;
......@@ -203,26 +203,6 @@ describe('PrometheusDatasource', () => {
});
});
describe('When performing performSuggestQuery', () => {
it('should cache response', async () => {
fetchMock.mockImplementation(() =>
of({
status: 'success',
data: { data: ['value1', 'value2', 'value3'] },
})
);
let results = await ds.performSuggestQuery('value', true);
expect(results).toHaveLength(3);
fetchMock.mockImplementation(jest.fn());
results = await ds.performSuggestQuery('value', true);
expect(results).toHaveLength(3);
});
});
describe('When converting prometheus histogram to heatmap format', () => {
let query: any;
beforeEach(() => {
......
// Libraries
import cloneDeep from 'lodash/cloneDeep';
import LRU from 'lru-cache';
// Services & Utils
import {
AnnotationEvent,
......@@ -66,7 +67,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
directUrl: string;
basicAuth: any;
withCredentials: any;
metricsNameCache: any;
metricsNameCache = new LRU<string, string[]>(10);
interval: string;
queryTimeout: string;
httpMethod: string;
......@@ -527,20 +528,6 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
return error;
};
async performSuggestQuery(query: string, cache = false) {
if (cache && this.metricsNameCache?.expire > Date.now()) {
return this.metricsNameCache.data.filter((metricName: any) => metricName.indexOf(query) !== 1);
}
const response: PromLabelQueryResponse = await this.metadataRequest('/api/v1/label/__name__/values');
this.metricsNameCache = {
data: response.data.data,
expire: Date.now() + 60 * 1000,
};
return response.data.data.filter(metricName => metricName.indexOf(query) !== 1);
}
metricFindQuery(query: string) {
if (!query) {
return Promise.resolve([]);
......
......@@ -114,7 +114,14 @@ export default class PromQlLanguageProvider extends LanguageProvider {
return [];
}
this.metrics = await this.request('/api/v1/label/__name__/values', []);
const tRange = this.datasource.getTimeRange();
const params = new URLSearchParams({
start: tRange['start'].toString(),
end: tRange['end'].toString(),
});
const url = `/api/v1/label/__name__/values?${params.toString()}`;
this.metrics = await this.request(url, []);
this.lookupsDisabled = this.metrics.length > this.lookupMetricsThreshold;
this.metricsMetadata = fixSummariesMetadata(await this.request('/api/v1/metadata', {}));
this.processHistogramMetrics(this.metrics);
......@@ -404,7 +411,13 @@ export default class PromQlLanguageProvider extends LanguageProvider {
}
fetchLabelValues = async (key: string): Promise<Record<string, string[]>> => {
const data = await this.request(`/api/v1/label/${key}/values`, []);
const tRange = this.datasource.getTimeRange();
const params = new URLSearchParams({
start: tRange['start'].toString(),
end: tRange['end'].toString(),
});
const url = `/api/v1/label/${key}/values?${params.toString()}`;
const data = await this.request(url, []);
return { [key]: data };
};
......
......@@ -76,7 +76,7 @@ describe('PrometheusMetricFindQuery', () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/labels',
url: `proxied/api/v1/labels?start=${raw.from.unix()}&end=${raw.to.unix()}`,
hideFromInspector: true,
headers: {},
});
......@@ -95,7 +95,7 @@ describe('PrometheusMetricFindQuery', () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/label/resource/values',
url: `proxied/api/v1/label/resource/values?start=${raw.from.unix()}&end=${raw.to.unix()}`,
hideFromInspector: true,
headers: {},
});
......@@ -190,7 +190,7 @@ describe('PrometheusMetricFindQuery', () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/label/__name__/values',
url: `proxied/api/v1/label/__name__/values?start=${raw.from.unix()}&end=${raw.to.unix()}`,
hideFromInspector: true,
headers: {},
});
......
......@@ -48,7 +48,15 @@ export default class PrometheusMetricFindQuery {
}
labelNamesQuery() {
const url = '/api/v1/labels';
const start = this.datasource.getPrometheusTime(this.range.from, false);
const end = this.datasource.getPrometheusTime(this.range.to, true);
const params = new URLSearchParams({
start: start.toString(),
end: end.toString(),
});
const url = `/api/v1/labels?${params.toString()}`;
return this.datasource.metadataRequest(url).then((result: any) => {
return _.map(result.data.data, value => {
return { text: value };
......@@ -57,11 +65,18 @@ export default class PrometheusMetricFindQuery {
}
labelValuesQuery(label: string, metric?: string) {
const start = this.datasource.getPrometheusTime(this.range.from, false);
const end = this.datasource.getPrometheusTime(this.range.to, true);
let url: string;
if (!metric) {
const params = new URLSearchParams({
start: start.toString(),
end: end.toString(),
});
// return label values globally
url = '/api/v1/label/' + label + '/values';
url = `/api/v1/label/${label}/values?${params.toString()}`;
return this.datasource.metadataRequest(url).then((result: any) => {
return _.map(result.data.data, value => {
......@@ -69,8 +84,6 @@ export default class PrometheusMetricFindQuery {
});
});
} else {
const start = this.datasource.getPrometheusTime(this.range.from, false);
const end = this.datasource.getPrometheusTime(this.range.to, true);
const params = new URLSearchParams({
'match[]': metric,
start: start.toString(),
......@@ -96,7 +109,13 @@ export default class PrometheusMetricFindQuery {
}
metricNameQuery(metricFilterPattern: string) {
const url = '/api/v1/label/__name__/values';
const start = this.datasource.getPrometheusTime(this.range.from, false);
const end = this.datasource.getPrometheusTime(this.range.to, true);
const params = new URLSearchParams({
start: start.toString(),
end: end.toString(),
});
const url = `/api/v1/label/__name__/values?${params.toString()}`;
return this.datasource.metadataRequest(url).then((result: any) => {
return _.chain(result.data.data)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment