Commit a73e6f72 by Hugo Häggmark Committed by GitHub

Prometheus: Use fetch instead of deprecated datasourceRequest (#27090)

* Prometheus: replaces dataSourcRequest with fetch

* Tests: fixes typings

* Refactor: removes unnecessary from operator

* Refactor: removes weird json() function calls

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/metric_find_query.test.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
parent 0fb7ee05
......@@ -18,13 +18,13 @@ import {
TimeRange,
TimeSeries,
} from '@grafana/data';
import { forkJoin, from, merge, Observable, of } from 'rxjs';
import { filter, map, tap } from 'rxjs/operators';
import { forkJoin, merge, Observable, of, throwError } from 'rxjs';
import { catchError, filter, map, tap } from 'rxjs/operators';
import PrometheusMetricFindQuery from './metric_find_query';
import { ResultTransformer } from './result_transformer';
import PrometheusLanguageProvider from './language_provider';
import { getBackendSrv, BackendSrvRequest } from '@grafana/runtime';
import { BackendSrvRequest, getBackendSrv } from '@grafana/runtime';
import addLabelToQuery from './add_label_to_query';
import { getQueryHints } from './query_hints';
import { expandRecordingRules } from './language_utils';
......@@ -111,7 +111,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
}
}
_request(url: string, data: Record<string, string> | null, overrides: Partial<BackendSrvRequest> = {}) {
_request<T = any>(url: string, data: Record<string, string> | null, overrides: Partial<BackendSrvRequest> = {}) {
const options: BackendSrvRequest = defaults(overrides, {
url: this.url + url,
method: this.httpMethod,
......@@ -140,12 +140,12 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
options.headers!.Authorization = this.basicAuth;
}
return getBackendSrv().datasourceRequest(options);
return getBackendSrv().fetch<T>(options);
}
// Use this for tab completion features, wont publish response to other components
metadataRequest(url: string) {
return this._request(url, null, { method: 'GET', hideFromInspector: true });
metadataRequest<T = any>(url: string) {
return this._request<T>(url, null, { method: 'GET', hideFromInspector: true }).toPromise(); // toPromise until we change getTagValues, getTagKeys to Observable
}
interpolateQueryExpr(value: string | string[] = [], variable: any) {
......@@ -272,8 +272,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
const target = activeTargets[index];
let observable = query.instant
? from(this.performInstantQuery(query, end))
: from(this.performTimeSeriesQuery(query, query.start, query.end));
? this.performInstantQuery(query, end)
: this.performTimeSeriesQuery(query, query.start, query.end);
return observable.pipe(
// Decrease the counter here. We assume that each request returns only single value and then completes
......@@ -305,8 +305,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
const target = activeTargets[index];
let observable = query.instant
? from(this.performInstantQuery(query, end))
: from(this.performTimeSeriesQuery(query, query.start, query.end));
? this.performInstantQuery(query, end)
: this.performTimeSeriesQuery(query, query.start, query.end);
return observable.pipe(
filter((response: any) => (response.cancelled ? false : true)),
......@@ -448,13 +448,15 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
}
}
return this._request(url, data, { requestId: query.requestId, headers: query.headers }).catch((err: any) => {
if (err.cancelled) {
return err;
}
return this._request(url, data, { requestId: query.requestId, headers: query.headers }).pipe(
catchError(err => {
if (err.cancelled) {
return of(err);
}
throw this.handleErrors(err, query);
});
return throwError(this.handleErrors(err, query));
})
);
}
performInstantQuery(query: PromQueryRequest, time: number) {
......@@ -474,13 +476,15 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
}
}
return this._request(url, data, { requestId: query.requestId, headers: query.headers }).catch((err: any) => {
if (err.cancelled) {
return err;
}
return this._request(url, data, { requestId: query.requestId, headers: query.headers }).pipe(
catchError(err => {
if (err.cancelled) {
return of(err);
}
throw this.handleErrors(err, query);
});
return throwError(this.handleErrors(err, query));
})
);
}
handleErrors = (err: any, target: PromQuery) => {
......@@ -582,7 +586,11 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
const query = this.createQuery(queryModel, queryOptions, start, end);
const self = this;
const response: PromDataQueryResponse = await this.performTimeSeriesQuery(query, query.start, query.end);
const response: PromDataQueryResponse = await this.performTimeSeriesQuery(
query,
query.start,
query.end
).toPromise();
const eventList: AnnotationEvent[] = [];
const splitKeys = tagKeys.split(',');
......@@ -662,7 +670,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
async testDatasource() {
const now = new Date().getTime();
const query = { expr: '1+1' } as PromQueryRequest;
const response = await this.performInstantQuery(query, now / 1000);
const response = await this.performInstantQuery(query, now / 1000).toPromise();
return response.data.status === 'success'
? { status: 'success', message: 'Data source is working' }
: { status: 'error', message: response.error };
......@@ -690,9 +698,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
async loadRules() {
try {
const res = await this.metadataRequest('/api/v1/rules');
const body = res.data || res.json();
const groups = res.data?.data?.groups;
const groups = body?.data?.groups;
if (groups) {
this.ruleMappings = extractRuleMappingFromGroups(groups);
}
......
......@@ -2,14 +2,14 @@ import _ from 'lodash';
import LRU from 'lru-cache';
import { Value } from 'slate';
import { dateTime, LanguageProvider, HistoryItem } from '@grafana/data';
import { CompletionItem, TypeaheadInput, TypeaheadOutput, CompletionItemGroup } from '@grafana/ui';
import { dateTime, HistoryItem, LanguageProvider } from '@grafana/data';
import { CompletionItem, CompletionItemGroup, TypeaheadInput, TypeaheadOutput } from '@grafana/ui';
import { parseSelector, processLabels, processHistogramLabels, fixSummariesMetadata } from './language_utils';
import { fixSummariesMetadata, parseSelector, processHistogramLabels, processLabels } from './language_utils';
import PromqlSyntax, { FUNCTIONS, RATE_RANGES } from './promql';
import { PrometheusDatasource } from './datasource';
import { PromQuery, PromMetricsMetadata } from './types';
import { PromMetricsMetadata, PromQuery } from './types';
const DEFAULT_KEYS = ['job', 'instance'];
const EMPTY_SELECTOR = '{}';
......@@ -101,9 +101,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
request = async (url: string, defaultValue: any): Promise<any> => {
try {
const res = await this.datasource.metadataRequest(url);
const body = await (res.data || res.json());
return body.data;
return res.data.data;
} catch (error) {
console.error(error);
}
......
import 'whatwg-fetch'; // fetch polyfill needed backendSrv
import { of } from 'rxjs';
import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
import { PrometheusDatasource } from './datasource';
import PrometheusMetricFindQuery from './metric_find_query';
import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
import { PromOptions } from './types';
import { FetchResponse } from '@grafana/runtime';
jest.mock('app/features/templating/template_srv', () => {
return {
......@@ -16,7 +20,7 @@ jest.mock('@grafana/runtime', () => ({
getBackendSrv: () => backendSrv,
}));
const datasourceRequestMock = jest.spyOn(backendSrv, 'datasourceRequest');
const fetchMock = jest.spyOn(backendSrv, 'fetch');
const instanceSettings = ({
url: 'proxied',
......@@ -54,7 +58,7 @@ describe('PrometheusMetricFindQuery', () => {
});
const setupMetricFindQuery = (data: any) => {
datasourceRequestMock.mockImplementation(() => Promise.resolve({ status: 'success', data: data.response }));
fetchMock.mockImplementation(() => of(({ status: 'success', data: data.response } as unknown) as FetchResponse));
return new PrometheusMetricFindQuery(ds, data.query);
};
......@@ -69,8 +73,8 @@ describe('PrometheusMetricFindQuery', () => {
const results = await query.process();
expect(results).toHaveLength(3);
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/labels',
hideFromInspector: true,
......@@ -88,8 +92,8 @@ describe('PrometheusMetricFindQuery', () => {
const results = await query.process();
expect(results).toHaveLength(3);
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/label/resource/values',
hideFromInspector: true,
......@@ -111,8 +115,8 @@ describe('PrometheusMetricFindQuery', () => {
const results = await query.process();
expect(results).toHaveLength(3);
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `proxied/api/v1/series?match${encodeURIComponent(
'[]'
......@@ -136,8 +140,8 @@ describe('PrometheusMetricFindQuery', () => {
const results = await query.process();
expect(results).toHaveLength(3);
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url:
'proxied/api/v1/series?match%5B%5D=metric%7Blabel1%3D%22foo%22%2C+label2%3D%22bar%22%2C+label3%3D%22baz%22%7D&start=1524650400&end=1524654000',
......@@ -162,8 +166,8 @@ describe('PrometheusMetricFindQuery', () => {
expect(results).toHaveLength(2);
expect(results[0].text).toBe('value1');
expect(results[1].text).toBe('value2');
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `proxied/api/v1/series?match${encodeURIComponent(
'[]'
......@@ -183,8 +187,8 @@ describe('PrometheusMetricFindQuery', () => {
const results = await query.process();
expect(results).toHaveLength(3);
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: 'proxied/api/v1/label/__name__/values',
hideFromInspector: true,
......@@ -211,8 +215,8 @@ describe('PrometheusMetricFindQuery', () => {
expect(results).toHaveLength(1);
expect(results[0].text).toBe('metric{job="testjob"} 3846 1443454528000');
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `proxied/api/v1/query?query=metric&time=${raw.to.unix()}`,
requestId: undefined,
......@@ -237,8 +241,8 @@ describe('PrometheusMetricFindQuery', () => {
expect(results[0].text).toBe('up{instance="127.0.0.1:1234",job="job1"}');
expect(results[1].text).toBe('up{instance="127.0.0.1:5678",job="job1"}');
expect(results[2].text).toBe('up{instance="127.0.0.1:9102",job="job1"}');
expect(datasourceRequestMock).toHaveBeenCalledTimes(1);
expect(datasourceRequestMock).toHaveBeenCalledWith({
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `proxied/api/v1/series?match${encodeURIComponent('[]')}=${encodeURIComponent(
'up{job="job1"}'
......
import _ from 'lodash';
import { TimeRange, MetricFindValue } from '@grafana/data';
import { PrometheusDatasource, PromDataQueryResponse } from './datasource';
import { map } from 'rxjs/operators';
import { MetricFindValue, TimeRange } from '@grafana/data';
import { PromDataQueryResponse, PrometheusDatasource } from './datasource';
import { PromQueryRequest } from './types';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
......@@ -39,7 +40,7 @@ export default class PrometheusMetricFindQuery {
const queryResultQuery = this.query.match(queryResultRegex);
if (queryResultQuery) {
return this.queryResultQuery(queryResultQuery[1]);
return this.queryResultQuery(queryResultQuery[1]).toPromise();
}
// if query contains full metric name, return metric name and label list
......@@ -116,24 +117,26 @@ export default class PrometheusMetricFindQuery {
queryResultQuery(query: string) {
const end = this.datasource.getPrometheusTime(this.range.to, true);
const instantQuery: PromQueryRequest = { expr: query } as PromQueryRequest;
return this.datasource.performInstantQuery(instantQuery, end).then((result: PromDataQueryResponse) => {
return _.map(result.data.data.result, metricData => {
let text = metricData.metric.__name__ || '';
delete metricData.metric.__name__;
text +=
'{' +
_.map(metricData.metric, (v, k) => {
return k + '="' + v + '"';
}).join(',') +
'}';
text += ' ' + metricData.value[1] + ' ' + metricData.value[0] * 1000;
return this.datasource.performInstantQuery(instantQuery, end).pipe(
map((result: PromDataQueryResponse) => {
return _.map(result.data.data.result, metricData => {
let text = metricData.metric.__name__ || '';
delete metricData.metric.__name__;
text +=
'{' +
_.map(metricData.metric, (v, k) => {
return k + '="' + v + '"';
}).join(',') +
'}';
text += ' ' + metricData.value[1] + ' ' + metricData.value[0] * 1000;
return {
text: text,
expandable: true,
};
});
});
return {
text: text,
expandable: true,
};
});
})
);
}
metricNameAndLabelsQuery(query: string): Promise<MetricFindValue[]> {
......
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