mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Remove timeSrv imports (#76118)
* Remove timeSrv imports from prometheus datasource * Fix language_provider unit test * Fix datasource unit tests * Remove timeSrv imports from metric_find_query * Remove timeSrv imports * MetricsBrowser with timeRange
This commit is contained in:
parent
e5f92c010d
commit
df3184a94a
@ -713,7 +713,7 @@ abstract class LanguageProvider {
|
|||||||
* Returns startTask that resolves with a task list when main syntax is loaded.
|
* Returns startTask that resolves with a task list when main syntax is loaded.
|
||||||
* Task list consists of secondary promises that load more detailed language features.
|
* Task list consists of secondary promises that load more detailed language features.
|
||||||
*/
|
*/
|
||||||
abstract start: () => Promise<Array<Promise<any>>>;
|
abstract start: (timeRange?: TimeRange) => Promise<Array<Promise<any>>>;
|
||||||
startTask?: Promise<any[]>;
|
startTask?: Promise<any[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +174,11 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
|
|
||||||
refreshMetrics = async () => {
|
refreshMetrics = async () => {
|
||||||
const {
|
const {
|
||||||
|
range,
|
||||||
datasource: { languageProvider },
|
datasource: { languageProvider },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.languageProviderInitializationPromise = makePromiseCancelable(languageProvider.start());
|
this.languageProviderInitializationPromise = makePromiseCancelable(languageProvider.start(range));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const remainingTasks = await this.languageProviderInitializationPromise.promise;
|
const remainingTasks = await this.languageProviderInitializationPromise.promise;
|
||||||
@ -327,6 +328,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
lastUsedLabels={lastUsedLabels || []}
|
lastUsedLabels={lastUsedLabels || []}
|
||||||
storeLastUsedLabels={onLastUsedLabelsSave}
|
storeLastUsedLabels={onLastUsedLabelsSave}
|
||||||
deleteLastUsedLabels={onLastUsedLabelsDelete}
|
deleteLastUsedLabels={onLastUsedLabelsDelete}
|
||||||
|
timeRange={this.props.range}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
|
|||||||
import React, { ChangeEvent } from 'react';
|
import React, { ChangeEvent } from 'react';
|
||||||
import { FixedSizeList } from 'react-window';
|
import { FixedSizeList } from 'react-window';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
HorizontalGroup,
|
HorizontalGroup,
|
||||||
@ -31,6 +31,7 @@ export interface BrowserProps {
|
|||||||
lastUsedLabels: string[];
|
lastUsedLabels: string[];
|
||||||
storeLastUsedLabels: (labels: string[]) => void;
|
storeLastUsedLabels: (labels: string[]) => void;
|
||||||
deleteLastUsedLabels: () => void;
|
deleteLastUsedLabels: () => void;
|
||||||
|
timeRange?: TimeRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BrowserState {
|
interface BrowserState {
|
||||||
@ -319,7 +320,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
|
|||||||
const { languageProvider, lastUsedLabels } = this.props;
|
const { languageProvider, lastUsedLabels } = this.props;
|
||||||
if (languageProvider) {
|
if (languageProvider) {
|
||||||
const selectedLabels: string[] = lastUsedLabels;
|
const selectedLabels: string[] = lastUsedLabels;
|
||||||
languageProvider.start().then(() => {
|
languageProvider.start(this.props.timeRange).then(() => {
|
||||||
let rawLabels: string[] = languageProvider.getLabelKeys();
|
let rawLabels: string[] = languageProvider.getLabelKeys();
|
||||||
// Get metrics
|
// Get metrics
|
||||||
this.fetchValues(METRIC_LABEL, EMPTY_SELECTOR);
|
this.fetchValues(METRIC_LABEL, EMPTY_SELECTOR);
|
||||||
|
@ -13,10 +13,11 @@ import {
|
|||||||
Field,
|
Field,
|
||||||
getFieldDisplayName,
|
getFieldDisplayName,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
|
rangeUtil,
|
||||||
|
TimeRange,
|
||||||
toDataFrame,
|
toDataFrame,
|
||||||
VariableHide,
|
VariableHide,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
import { QueryOptions } from 'app/types';
|
import { QueryOptions } from 'app/types';
|
||||||
|
|
||||||
@ -49,23 +50,23 @@ const templateSrvStub = {
|
|||||||
const fromSeconds = 1674500289215;
|
const fromSeconds = 1674500289215;
|
||||||
const toSeconds = 1674500349215;
|
const toSeconds = 1674500349215;
|
||||||
|
|
||||||
const timeSrvStubOld = {
|
const mockTimeRangeOld: TimeRange = {
|
||||||
timeRange() {
|
from: dateTime(1531468681),
|
||||||
return {
|
to: dateTime(1531489712),
|
||||||
from: dateTime(1531468681),
|
raw: {
|
||||||
to: dateTime(1531489712),
|
from: '1531468681',
|
||||||
};
|
to: '1531489712',
|
||||||
},
|
},
|
||||||
} as TimeSrv;
|
};
|
||||||
|
|
||||||
const timeSrvStub: TimeSrv = {
|
const mockTimeRange: TimeRange = {
|
||||||
timeRange() {
|
from: dateTime(fromSeconds),
|
||||||
return {
|
to: dateTime(toSeconds),
|
||||||
from: dateTime(fromSeconds),
|
raw: {
|
||||||
to: dateTime(toSeconds),
|
from: fromSeconds.toString(),
|
||||||
};
|
to: toSeconds.toString(),
|
||||||
},
|
},
|
||||||
} as TimeSrv;
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@ -87,7 +88,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Some functions are required by the parent datasource class to provide functionality such as ad-hoc filters, which requires the definition of the getTagKeys, and getTagValues functions
|
// Some functions are required by the parent datasource class to provide functionality such as ad-hoc filters, which requires the definition of the getTagKeys, and getTagValues functions
|
||||||
@ -142,7 +143,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
},
|
},
|
||||||
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
const range = { from: time({ seconds: 63 }), to: time({ seconds: 183 }) };
|
const range = { from: time({ seconds: 63 }), to: time({ seconds: 183 }) };
|
||||||
const directDs = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const directDs = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
lastValueFrom(directDs.query(createDataRequest([{}, {}], { app: CoreApp.Dashboard })))
|
lastValueFrom(directDs.query(createDataRequest([{}, {}], { app: CoreApp.Dashboard })))
|
||||||
@ -191,7 +192,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
it('should still perform a GET request with the DS HTTP method set to POST and not POST-friendly endpoint', () => {
|
it('should still perform a GET request with the DS HTTP method set to POST and not POST-friendly endpoint', () => {
|
||||||
const postSettings = cloneDeep(instanceSettings);
|
const postSettings = cloneDeep(instanceSettings);
|
||||||
postSettings.jsonData.httpMethod = 'POST';
|
postSettings.jsonData.httpMethod = 'POST';
|
||||||
const promDs = new PrometheusDatasource(postSettings, templateSrvStub, timeSrvStub);
|
const promDs = new PrometheusDatasource(postSettings, templateSrvStub);
|
||||||
promDs.metadataRequest('/foo');
|
promDs.metadataRequest('/foo');
|
||||||
expect(fetchMock.mock.calls.length).toBe(1);
|
expect(fetchMock.mock.calls.length).toBe(1);
|
||||||
expect(fetchMock.mock.calls[0][0].method).toBe('GET');
|
expect(fetchMock.mock.calls[0][0].method).toBe('GET');
|
||||||
@ -199,7 +200,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
it('should try to perform a POST request with the DS HTTP method set to POST and POST-friendly endpoint', () => {
|
it('should try to perform a POST request with the DS HTTP method set to POST and POST-friendly endpoint', () => {
|
||||||
const postSettings = cloneDeep(instanceSettings);
|
const postSettings = cloneDeep(instanceSettings);
|
||||||
postSettings.jsonData.httpMethod = 'POST';
|
postSettings.jsonData.httpMethod = 'POST';
|
||||||
const promDs = new PrometheusDatasource(postSettings, templateSrvStub, timeSrvStub);
|
const promDs = new PrometheusDatasource(postSettings, templateSrvStub);
|
||||||
promDs.metadataRequest('api/v1/series', { bar: 'baz baz', foo: 'foo' });
|
promDs.metadataRequest('api/v1/series', { bar: 'baz baz', foo: 'foo' });
|
||||||
expect(fetchMock.mock.calls.length).toBe(1);
|
expect(fetchMock.mock.calls.length).toBe(1);
|
||||||
expect(fetchMock.mock.calls[0][0].method).toBe('POST');
|
expect(fetchMock.mock.calls[0][0].method).toBe('POST');
|
||||||
@ -222,8 +223,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
describe('with GET http method', () => {
|
describe('with GET http method', () => {
|
||||||
const promDs = new PrometheusDatasource(
|
const promDs = new PrometheusDatasource(
|
||||||
{ ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'GET' } },
|
{ ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'GET' } },
|
||||||
templateSrvStub,
|
templateSrvStub
|
||||||
timeSrvStub
|
|
||||||
);
|
);
|
||||||
|
|
||||||
it('added to metadata request', () => {
|
it('added to metadata request', () => {
|
||||||
@ -257,8 +257,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
describe('with POST http method', () => {
|
describe('with POST http method', () => {
|
||||||
const promDs = new PrometheusDatasource(
|
const promDs = new PrometheusDatasource(
|
||||||
{ ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'POST' } },
|
{ ...instanceSettings, jsonData: { customQueryParameters: 'customQuery=123', httpMethod: 'POST' } },
|
||||||
templateSrvStub,
|
templateSrvStub
|
||||||
timeSrvStub
|
|
||||||
);
|
);
|
||||||
|
|
||||||
it('added to metadata request with non-POST endpoint', () => {
|
it('added to metadata request with non-POST endpoint', () => {
|
||||||
@ -307,7 +306,12 @@ describe('PrometheusDatasource', () => {
|
|||||||
const target: PromQuery = { expr: DEFAULT_QUERY_EXPRESSION, refId: 'A' };
|
const target: PromQuery = { expr: DEFAULT_QUERY_EXPRESSION, refId: 'A' };
|
||||||
|
|
||||||
it('should not modify expression with no filters', () => {
|
it('should not modify expression with no filters', () => {
|
||||||
const result = ds.createQuery(target, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 0);
|
const result = ds.createQuery(
|
||||||
|
target,
|
||||||
|
{ interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
expect(result).toMatchObject({ expr: DEFAULT_QUERY_EXPRESSION });
|
expect(result).toMatchObject({ expr: DEFAULT_QUERY_EXPRESSION });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -324,7 +328,12 @@ describe('PrometheusDatasource', () => {
|
|||||||
value: 'v2',
|
value: 'v2',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const result = ds.createQuery(target, { interval: '15s', filters } as DataQueryRequest<PromQuery>, 0, 0);
|
const result = ds.createQuery(
|
||||||
|
target,
|
||||||
|
{ interval: '15s', range: getMockTimeRange(), filters } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
expect(result).toMatchObject({ expr: 'metric{job="foo", k1="v1", k2!="v2"} - metric{k1="v1", k2!="v2"}' });
|
expect(result).toMatchObject({ expr: 'metric{job="foo", k1="v1", k2!="v2"} - metric{k1="v1", k2!="v2"}' });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -342,7 +351,12 @@ describe('PrometheusDatasource', () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const result = ds.createQuery(target, { interval: '15s', filters } as DataQueryRequest<PromQuery>, 0, 0);
|
const result = ds.createQuery(
|
||||||
|
target,
|
||||||
|
{ interval: '15s', range: getMockTimeRange(), filters } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
expr: `metric{job="foo", k1=~"v.*", k2=~"v\\\\'.*"} - metric{k1=~"v.*", k2=~"v\\\\'.*"}`,
|
expr: `metric{job="foo", k1=~"v.*", k2=~"v\\\\'.*"} - metric{k1=~"v.*", k2=~"v\\\\'.*"}`,
|
||||||
});
|
});
|
||||||
@ -445,10 +459,9 @@ describe('PrometheusDatasource', () => {
|
|||||||
...instanceSettings,
|
...instanceSettings,
|
||||||
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.Low },
|
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.Low },
|
||||||
},
|
},
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
templateSrvStub as unknown as TemplateSrv
|
||||||
timeSrvStub as unknown as TimeSrv
|
|
||||||
);
|
);
|
||||||
const quantizedRange = dataSource.getAdjustedInterval();
|
const quantizedRange = dataSource.getAdjustedInterval(mockTimeRange);
|
||||||
// For "1 minute" the window contains all the minutes, so a query from 1:11:09 - 1:12:09 becomes 1:11 - 1:13
|
// For "1 minute" the window contains all the minutes, so a query from 1:11:09 - 1:12:09 becomes 1:11 - 1:13
|
||||||
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(120);
|
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(120);
|
||||||
});
|
});
|
||||||
@ -459,10 +472,9 @@ describe('PrometheusDatasource', () => {
|
|||||||
...instanceSettings,
|
...instanceSettings,
|
||||||
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.Medium },
|
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.Medium },
|
||||||
},
|
},
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
templateSrvStub as unknown as TemplateSrv
|
||||||
timeSrvStub as unknown as TimeSrv
|
|
||||||
);
|
);
|
||||||
const quantizedRange = dataSource.getAdjustedInterval();
|
const quantizedRange = dataSource.getAdjustedInterval(mockTimeRange);
|
||||||
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(600);
|
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(600);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -472,10 +484,9 @@ describe('PrometheusDatasource', () => {
|
|||||||
...instanceSettings,
|
...instanceSettings,
|
||||||
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.High },
|
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.High },
|
||||||
},
|
},
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
templateSrvStub as unknown as TemplateSrv
|
||||||
timeSrvStub as unknown as TimeSrv
|
|
||||||
);
|
);
|
||||||
const quantizedRange = dataSource.getAdjustedInterval();
|
const quantizedRange = dataSource.getAdjustedInterval(mockTimeRange);
|
||||||
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(3600);
|
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(3600);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -485,10 +496,9 @@ describe('PrometheusDatasource', () => {
|
|||||||
...instanceSettings,
|
...instanceSettings,
|
||||||
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.None },
|
jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.None },
|
||||||
},
|
},
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
templateSrvStub as unknown as TemplateSrv
|
||||||
timeSrvStub as unknown as TimeSrv
|
|
||||||
);
|
);
|
||||||
const quantizedRange = dataSource.getAdjustedInterval();
|
const quantizedRange = dataSource.getAdjustedInterval(mockTimeRange);
|
||||||
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(
|
expect(parseInt(quantizedRange.end, 10) - parseInt(quantizedRange.start, 10)).toBe(
|
||||||
(toSeconds - fromSeconds) / 1000
|
(toSeconds - fromSeconds) / 1000
|
||||||
);
|
);
|
||||||
@ -840,11 +850,10 @@ describe('PrometheusDatasource', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const prometheusDatasource = new PrometheusDatasource(
|
const prometheusDatasource = new PrometheusDatasource(
|
||||||
{ ...instanceSettings, jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.None } },
|
{ ...instanceSettings, jsonData: { ...instanceSettings.jsonData, cacheLevel: PrometheusCacheLevel.None } },
|
||||||
templateSrvStub,
|
templateSrvStub
|
||||||
timeSrvStubOld
|
|
||||||
);
|
);
|
||||||
const query = 'query_result(topk(5,rate(http_request_duration_microseconds_count[$__interval])))';
|
const query = 'query_result(topk(5,rate(http_request_duration_microseconds_count[$__interval])))';
|
||||||
prometheusDatasource.metricFindQuery(query);
|
prometheusDatasource.metricFindQuery(query, { range: mockTimeRangeOld });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call templateSrv.replace with scopedVars', () => {
|
it('should call templateSrv.replace with scopedVars', () => {
|
||||||
@ -888,7 +897,7 @@ describe('PrometheusDatasource2', () => {
|
|||||||
|
|
||||||
let ds: PrometheusDatasource;
|
let ds: PrometheusDatasource;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('When querying prometheus with one target using query editor target spec', () => {
|
describe('When querying prometheus with one target using query editor target spec', () => {
|
||||||
@ -1510,7 +1519,7 @@ describe('PrometheusDatasource2', () => {
|
|||||||
it('should be determined by the 11000 data points limit when too small', async () => {
|
it('should be determined by the 11000 data points limit when too small', async () => {
|
||||||
const query = {
|
const query = {
|
||||||
// 1 week range
|
// 1 week range
|
||||||
range: { from: time({}), to: time({ hours: 7 * 24 }) },
|
range: { from: time({ minutes: 1 }), to: time({ hours: 7 * 24, minutes: 1 }) },
|
||||||
targets: [
|
targets: [
|
||||||
{
|
{
|
||||||
expr: 'test',
|
expr: 'test',
|
||||||
@ -1521,9 +1530,9 @@ describe('PrometheusDatasource2', () => {
|
|||||||
} as DataQueryRequest<PromQuery>;
|
} as DataQueryRequest<PromQuery>;
|
||||||
let end = 7 * 24 * 60 * 60;
|
let end = 7 * 24 * 60 * 60;
|
||||||
end -= end % 55;
|
end -= end % 55;
|
||||||
const start = 0;
|
const start = 60;
|
||||||
const step = 55;
|
const step = 55;
|
||||||
const adjusted = alignRange(start, end, step, timeSrvStub.timeRange().to.utcOffset() * 60);
|
const adjusted = alignRange(start, end, step, query.range.to.utcOffset() * 60);
|
||||||
const urlExpected =
|
const urlExpected =
|
||||||
'proxied/api/v1/query_range?query=test' +
|
'proxied/api/v1/query_range?query=test' +
|
||||||
'&start=' +
|
'&start=' +
|
||||||
@ -1760,7 +1769,7 @@ describe('PrometheusDatasource2', () => {
|
|||||||
it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => {
|
it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => {
|
||||||
const query = {
|
const query = {
|
||||||
// 1 week range
|
// 1 week range
|
||||||
range: { from: time({}), to: time({ hours: 7 * 24 }) },
|
range: { from: time({ minutes: 1 }), to: time({ hours: 7 * 24, minutes: 1 }) },
|
||||||
targets: [
|
targets: [
|
||||||
{
|
{
|
||||||
expr: 'rate(test[$__interval])',
|
expr: 'rate(test[$__interval])',
|
||||||
@ -1775,9 +1784,9 @@ describe('PrometheusDatasource2', () => {
|
|||||||
};
|
};
|
||||||
let end = 7 * 24 * 60 * 60;
|
let end = 7 * 24 * 60 * 60;
|
||||||
end -= end % 55;
|
end -= end % 55;
|
||||||
const start = 0;
|
const start = 60;
|
||||||
const step = 55;
|
const step = 55;
|
||||||
const adjusted = alignRange(start, end, step, timeSrvStub.timeRange().to.utcOffset() * 60);
|
const adjusted = alignRange(start, end, step, query.range.to.utcOffset() * 60);
|
||||||
const urlExpected =
|
const urlExpected =
|
||||||
'proxied/api/v1/query_range?query=' +
|
'proxied/api/v1/query_range?query=' +
|
||||||
encodeURIComponent('rate(test[$__interval])') +
|
encodeURIComponent('rate(test[$__interval])') +
|
||||||
@ -1872,40 +1881,70 @@ describe('PrometheusDatasource2', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be 4 times the scrape interval if interval + scrape interval is lower', () => {
|
it('should be 4 times the scrape interval if interval + scrape interval is lower', () => {
|
||||||
ds.createQuery(target, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 300);
|
ds.createQuery(target, { interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>, 0, 300);
|
||||||
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
||||||
});
|
});
|
||||||
it('should be interval + scrape interval if 4 times the scrape interval is lower', () => {
|
it('should be interval + scrape interval if 4 times the scrape interval is lower', () => {
|
||||||
ds.createQuery(target, { interval: '5m' } as DataQueryRequest<PromQuery>, 0, 10080);
|
ds.createQuery(target, { interval: '5m', range: getMockTimeRange() } as DataQueryRequest<PromQuery>, 0, 10080);
|
||||||
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('315s');
|
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('315s');
|
||||||
});
|
});
|
||||||
it('should fall back to a scrape interval of 15s if min step is set to 0, resulting in 4*15s = 60s', () => {
|
it('should fall back to a scrape interval of 15s if min step is set to 0, resulting in 4*15s = 60s', () => {
|
||||||
ds.createQuery({ ...target, interval: '' }, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 300);
|
ds.createQuery(
|
||||||
|
{ ...target, interval: '' },
|
||||||
|
{ interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
300
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
||||||
});
|
});
|
||||||
it('should be 4 times the scrape interval if min step set to 1m and interval is 15s', () => {
|
it('should be 4 times the scrape interval if min step set to 1m and interval is 15s', () => {
|
||||||
// For a 5m graph, $__interval is 15s
|
// For a 5m graph, $__interval is 15s
|
||||||
ds.createQuery({ ...target, interval: '1m' }, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 300);
|
ds.createQuery(
|
||||||
|
{ ...target, interval: '1m' },
|
||||||
|
{ interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
300
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls[2][1]['__rate_interval'].value).toBe('240s');
|
expect(replaceMock.mock.calls[2][1]['__rate_interval'].value).toBe('240s');
|
||||||
});
|
});
|
||||||
it('should be interval + scrape interval if min step set to 1m and interval is 5m', () => {
|
it('should be interval + scrape interval if min step set to 1m and interval is 5m', () => {
|
||||||
// For a 7d graph, $__interval is 5m
|
// For a 7d graph, $__interval is 5m
|
||||||
ds.createQuery({ ...target, interval: '1m' }, { interval: '5m' } as DataQueryRequest<PromQuery>, 0, 10080);
|
ds.createQuery(
|
||||||
|
{ ...target, interval: '1m' },
|
||||||
|
{ interval: '5m', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
10080
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls[2][1]['__rate_interval'].value).toBe('360s');
|
expect(replaceMock.mock.calls[2][1]['__rate_interval'].value).toBe('360s');
|
||||||
});
|
});
|
||||||
it('should be interval + scrape interval if resolution is set to 1/2 and interval is 10m', () => {
|
it('should be interval + scrape interval if resolution is set to 1/2 and interval is 10m', () => {
|
||||||
// For a 7d graph, $__interval is 10m
|
// For a 7d graph, $__interval is 10m
|
||||||
ds.createQuery({ ...target, intervalFactor: 2 }, { interval: '10m' } as DataQueryRequest<PromQuery>, 0, 10080);
|
ds.createQuery(
|
||||||
|
{ ...target, intervalFactor: 2 },
|
||||||
|
{ interval: '10m', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
10080
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('1215s');
|
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('1215s');
|
||||||
});
|
});
|
||||||
it('should be 4 times the scrape interval if resolution is set to 1/2 and interval is 15s', () => {
|
it('should be 4 times the scrape interval if resolution is set to 1/2 and interval is 15s', () => {
|
||||||
// For a 5m graph, $__interval is 15s
|
// For a 5m graph, $__interval is 15s
|
||||||
ds.createQuery({ ...target, intervalFactor: 2 }, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 300);
|
ds.createQuery(
|
||||||
|
{ ...target, intervalFactor: 2 },
|
||||||
|
{ interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
300
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
expect(replaceMock.mock.calls[1][1]['__rate_interval'].value).toBe('60s');
|
||||||
});
|
});
|
||||||
it('should interpolate min step if set', () => {
|
it('should interpolate min step if set', () => {
|
||||||
replaceMock.mockImplementation((_: string) => '15s');
|
replaceMock.mockImplementation((_: string) => '15s');
|
||||||
ds.createQuery({ ...target, interval: '$int' }, { interval: '15s' } as DataQueryRequest<PromQuery>, 0, 300);
|
ds.createQuery(
|
||||||
|
{ ...target, interval: '$int' },
|
||||||
|
{ interval: '15s', range: getMockTimeRange() } as DataQueryRequest<PromQuery>,
|
||||||
|
0,
|
||||||
|
300
|
||||||
|
);
|
||||||
expect(replaceMock.mock.calls).toHaveLength(3);
|
expect(replaceMock.mock.calls).toHaveLength(3);
|
||||||
replaceMock.mockImplementation((str) => str);
|
replaceMock.mockImplementation((str) => str);
|
||||||
});
|
});
|
||||||
@ -1952,7 +1991,7 @@ describe('PrometheusDatasource for POST', () => {
|
|||||||
|
|
||||||
let ds: PrometheusDatasource;
|
let ds: PrometheusDatasource;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('When querying prometheus with one target using query editor target spec', () => {
|
describe('When querying prometheus with one target using query editor target spec', () => {
|
||||||
@ -2021,11 +2060,7 @@ describe('PrometheusDatasource for POST', () => {
|
|||||||
|
|
||||||
let ds: PrometheusDatasource;
|
let ds: PrometheusDatasource;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds = new PrometheusDatasource(
|
ds = new PrometheusDatasource(instanceSettings, templateSrvStub as unknown as TemplateSrv);
|
||||||
instanceSettings,
|
|
||||||
templateSrvStub as unknown as TemplateSrv,
|
|
||||||
timeSrvStub as unknown as TimeSrv
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with proxy access tracing headers should be added', () => {
|
it('with proxy access tracing headers should be added', () => {
|
||||||
@ -2043,11 +2078,7 @@ describe('PrometheusDatasource for POST', () => {
|
|||||||
jsonData: { httpMethod: 'POST' },
|
jsonData: { httpMethod: 'POST' },
|
||||||
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
} as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
|
|
||||||
const mockDs = new PrometheusDatasource(
|
const mockDs = new PrometheusDatasource({ ...instanceSettings, url: 'http://127.0.0.1:8000' }, templateSrvStub);
|
||||||
{ ...instanceSettings, url: 'http://127.0.0.1:8000' },
|
|
||||||
templateSrvStub,
|
|
||||||
timeSrvStub
|
|
||||||
);
|
|
||||||
mockDs._addTracingHeaders(httpOptions, options);
|
mockDs._addTracingHeaders(httpOptions, options);
|
||||||
expect(httpOptions.headers['X-Dashboard-Id']).toBe(undefined);
|
expect(httpOptions.headers['X-Dashboard-Id']).toBe(undefined);
|
||||||
expect(httpOptions.headers['X-Panel-Id']).toBe(undefined);
|
expect(httpOptions.headers['X-Panel-Id']).toBe(undefined);
|
||||||
@ -2083,10 +2114,11 @@ function getPrepareTargetsContext({
|
|||||||
interval: '1s',
|
interval: '1s',
|
||||||
panelId,
|
panelId,
|
||||||
app,
|
app,
|
||||||
|
range: getMockTimeRange(),
|
||||||
...queryOptions,
|
...queryOptions,
|
||||||
} as unknown as DataQueryRequest<PromQuery>;
|
} as unknown as DataQueryRequest<PromQuery>;
|
||||||
|
|
||||||
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
if (languageProvider) {
|
if (languageProvider) {
|
||||||
ds.languageProvider = languageProvider;
|
ds.languageProvider = languageProvider;
|
||||||
}
|
}
|
||||||
@ -2392,7 +2424,7 @@ describe('modifyQuery', () => {
|
|||||||
const query: PromQuery = { refId: 'A', expr: 'go_goroutines' };
|
const query: PromQuery = { refId: 'A', expr: 'go_goroutines' };
|
||||||
const action = { options: { key: 'cluster', value: 'us-cluster' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'cluster', value: 'us-cluster' }, type: 'ADD_FILTER' };
|
||||||
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
@ -2406,7 +2438,7 @@ describe('modifyQuery', () => {
|
|||||||
const query: PromQuery = { refId: 'A', expr: 'go_goroutines{cluster="us-cluster"}' };
|
const query: PromQuery = { refId: 'A', expr: 'go_goroutines{cluster="us-cluster"}' };
|
||||||
const action = { options: { key: 'pod', value: 'pod-123' }, type: 'ADD_FILTER' };
|
const action = { options: { key: 'pod', value: 'pod-123' }, type: 'ADD_FILTER' };
|
||||||
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
@ -2422,7 +2454,7 @@ describe('modifyQuery', () => {
|
|||||||
const query: PromQuery = { refId: 'A', expr: 'go_goroutines' };
|
const query: PromQuery = { refId: 'A', expr: 'go_goroutines' };
|
||||||
const action = { options: { key: 'cluster', value: 'us-cluster' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'cluster', value: 'us-cluster' }, type: 'ADD_FILTER_OUT' };
|
||||||
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
@ -2436,7 +2468,7 @@ describe('modifyQuery', () => {
|
|||||||
const query: PromQuery = { refId: 'A', expr: 'go_goroutines{cluster="us-cluster"}' };
|
const query: PromQuery = { refId: 'A', expr: 'go_goroutines{cluster="us-cluster"}' };
|
||||||
const action = { options: { key: 'pod', value: 'pod-123' }, type: 'ADD_FILTER_OUT' };
|
const action = { options: { key: 'pod', value: 'pod-123' }, type: 'ADD_FILTER_OUT' };
|
||||||
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
const instanceSettings = { jsonData: {} } as unknown as DataSourceInstanceSettings<PromOptions>;
|
||||||
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub, timeSrvStub);
|
const ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
|
||||||
|
|
||||||
const result = ds.modifyQuery(query, action);
|
const result = ds.modifyQuery(query, action);
|
||||||
|
|
||||||
@ -2559,3 +2591,10 @@ function createEmptyAnnotationResponse() {
|
|||||||
|
|
||||||
return { ...response };
|
return { ...response };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMockTimeRange(range = '6h'): TimeRange {
|
||||||
|
return rangeUtil.convertRawToRange({
|
||||||
|
from: `now-${range}`,
|
||||||
|
to: 'now',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -19,6 +19,8 @@ import {
|
|||||||
DataSourceWithQueryExportSupport,
|
DataSourceWithQueryExportSupport,
|
||||||
DataSourceWithQueryImportSupport,
|
DataSourceWithQueryImportSupport,
|
||||||
dateTime,
|
dateTime,
|
||||||
|
getDefaultTimeRange,
|
||||||
|
LegacyMetricFindQueryOptions,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
MetricFindValue,
|
MetricFindValue,
|
||||||
QueryFixAction,
|
QueryFixAction,
|
||||||
@ -38,7 +40,6 @@ import {
|
|||||||
toDataQueryResponse,
|
toDataQueryResponse,
|
||||||
} from '@grafana/runtime';
|
} from '@grafana/runtime';
|
||||||
import { safeStringifyValue } from 'app/core/utils/explore';
|
import { safeStringifyValue } from 'app/core/utils/explore';
|
||||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
|
||||||
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
|
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
|
||||||
import { addLabelToQuery } from './add_label_to_query';
|
import { addLabelToQuery } from './add_label_to_query';
|
||||||
@ -109,7 +110,6 @@ export class PrometheusDatasource
|
|||||||
constructor(
|
constructor(
|
||||||
instanceSettings: DataSourceInstanceSettings<PromOptions>,
|
instanceSettings: DataSourceInstanceSettings<PromOptions>,
|
||||||
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
||||||
private readonly timeSrv: TimeSrv = getTimeSrv(),
|
|
||||||
languageProvider?: PrometheusLanguageProvider
|
languageProvider?: PrometheusLanguageProvider
|
||||||
) {
|
) {
|
||||||
super(instanceSettings);
|
super(instanceSettings);
|
||||||
@ -136,7 +136,7 @@ export class PrometheusDatasource
|
|||||||
this.datasourceConfigurationPrometheusVersion = instanceSettings.jsonData.prometheusVersion;
|
this.datasourceConfigurationPrometheusVersion = instanceSettings.jsonData.prometheusVersion;
|
||||||
this.defaultEditor = instanceSettings.jsonData.defaultEditor;
|
this.defaultEditor = instanceSettings.jsonData.defaultEditor;
|
||||||
this.disableRecordingRules = instanceSettings.jsonData.disableRecordingRules ?? false;
|
this.disableRecordingRules = instanceSettings.jsonData.disableRecordingRules ?? false;
|
||||||
this.variables = new PrometheusVariableSupport(this, this.templateSrv, this.timeSrv);
|
this.variables = new PrometheusVariableSupport(this, this.templateSrv);
|
||||||
this.exemplarsAvailable = true;
|
this.exemplarsAvailable = true;
|
||||||
this.cacheLevel = instanceSettings.jsonData.cacheLevel ?? PrometheusCacheLevel.Low;
|
this.cacheLevel = instanceSettings.jsonData.cacheLevel ?? PrometheusCacheLevel.Low;
|
||||||
|
|
||||||
@ -448,7 +448,7 @@ export class PrometheusDatasource
|
|||||||
exemplar: this.shouldRunExemplarQuery(target, request),
|
exemplar: this.shouldRunExemplarQuery(target, request),
|
||||||
requestId: request.panelId + target.refId,
|
requestId: request.panelId + target.refId,
|
||||||
// We need to pass utcOffsetSec to backend to calculate aligned range
|
// We need to pass utcOffsetSec to backend to calculate aligned range
|
||||||
utcOffsetSec: this.timeSrv.timeRange().to.utcOffset() * 60,
|
utcOffsetSec: request.range.to.utcOffset() * 60,
|
||||||
};
|
};
|
||||||
if (target.instant && target.range) {
|
if (target.instant && target.range) {
|
||||||
// We have query type "Both" selected
|
// We have query type "Both" selected
|
||||||
@ -673,7 +673,7 @@ export class PrometheusDatasource
|
|||||||
|
|
||||||
// Align query interval with step to allow query caching and to ensure
|
// Align query interval with step to allow query caching and to ensure
|
||||||
// that about-same-time query results look the same.
|
// that about-same-time query results look the same.
|
||||||
const adjusted = alignRange(start, end, query.step, this.timeSrv.timeRange().to.utcOffset() * 60);
|
const adjusted = alignRange(start, end, query.step, options.range.to.utcOffset() * 60);
|
||||||
query.start = adjusted.start;
|
query.start = adjusted.start;
|
||||||
query.end = adjusted.end;
|
query.end = adjusted.end;
|
||||||
this._addTracingHeaders(query, options);
|
this._addTracingHeaders(query, options);
|
||||||
@ -789,7 +789,7 @@ export class PrometheusDatasource
|
|||||||
return error;
|
return error;
|
||||||
};
|
};
|
||||||
|
|
||||||
metricFindQuery(query: string) {
|
metricFindQuery(query: string, options?: LegacyMetricFindQueryOptions) {
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
@ -797,14 +797,14 @@ export class PrometheusDatasource
|
|||||||
const scopedVars = {
|
const scopedVars = {
|
||||||
__interval: { text: this.interval, value: this.interval },
|
__interval: { text: this.interval, value: this.interval },
|
||||||
__interval_ms: { text: rangeUtil.intervalToMs(this.interval), value: rangeUtil.intervalToMs(this.interval) },
|
__interval_ms: { text: rangeUtil.intervalToMs(this.interval), value: rangeUtil.intervalToMs(this.interval) },
|
||||||
...this.getRangeScopedVars(this.timeSrv.timeRange()),
|
...this.getRangeScopedVars(options?.range ?? getDefaultTimeRange()),
|
||||||
};
|
};
|
||||||
const interpolated = this.templateSrv.replace(query, scopedVars, this.interpolateQueryExpr);
|
const interpolated = this.templateSrv.replace(query, scopedVars, this.interpolateQueryExpr);
|
||||||
const metricFindQuery = new PrometheusMetricFindQuery(this, interpolated);
|
const metricFindQuery = new PrometheusMetricFindQuery(this, interpolated);
|
||||||
return metricFindQuery.process();
|
return metricFindQuery.process(options?.range ?? getDefaultTimeRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
getRangeScopedVars(range: TimeRange = this.timeSrv.timeRange()) {
|
getRangeScopedVars(range: TimeRange) {
|
||||||
const msRange = range.to.diff(range.from);
|
const msRange = range.to.diff(range.from);
|
||||||
const sRange = Math.round(msRange / 1000);
|
const sRange = Math.round(msRange / 1000);
|
||||||
return {
|
return {
|
||||||
@ -963,7 +963,7 @@ export class PrometheusDatasource
|
|||||||
// and in Tempo here grafana/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
|
// and in Tempo here grafana/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
|
||||||
async getTagKeys(options: DataSourceGetTagKeysOptions): Promise<MetricFindValue[]> {
|
async getTagKeys(options: DataSourceGetTagKeysOptions): Promise<MetricFindValue[]> {
|
||||||
if (!options || options.filters.length === 0) {
|
if (!options || options.filters.length === 0) {
|
||||||
await this.languageProvider.fetchLabels();
|
await this.languageProvider.fetchLabels(options.timeRange);
|
||||||
return this.languageProvider.getLabelKeys().map((k) => ({ value: k, text: k }));
|
return this.languageProvider.getLabelKeys().map((k) => ({ value: k, text: k }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1005,7 +1005,7 @@ export class PrometheusDatasource
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = this.getTimeRangeParams();
|
const params = this.getTimeRangeParams(options.timeRange ?? getDefaultTimeRange());
|
||||||
const result = await this.metadataRequest(`/api/v1/label/${options.key}/values`, params);
|
const result = await this.metadataRequest(`/api/v1/label/${options.key}/values`, params);
|
||||||
return result?.data?.data?.map((value: any) => ({ text: value })) ?? [];
|
return result?.data?.data?.map((value: any) => ({ text: value })) ?? [];
|
||||||
}
|
}
|
||||||
@ -1123,9 +1123,8 @@ export class PrometheusDatasource
|
|||||||
/**
|
/**
|
||||||
* Returns the adjusted "snapped" interval parameters
|
* Returns the adjusted "snapped" interval parameters
|
||||||
*/
|
*/
|
||||||
getAdjustedInterval(): { start: string; end: string } {
|
getAdjustedInterval(timeRange: TimeRange): { start: string; end: string } {
|
||||||
const range = this.timeSrv.timeRange();
|
return getRangeSnapInterval(this.cacheLevel, timeRange);
|
||||||
return getRangeSnapInterval(this.cacheLevel, range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1133,16 +1132,15 @@ export class PrometheusDatasource
|
|||||||
* and then a little extra padding to round up/down to the nearest nth minute,
|
* and then a little extra padding to round up/down to the nearest nth minute,
|
||||||
* defined by the result of the getCacheDurationInMinutes.
|
* defined by the result of the getCacheDurationInMinutes.
|
||||||
*
|
*
|
||||||
* For longer cache durations, and shorter query durations, the window we're calculating might be much bigger then the user's current window,
|
* For longer cache durations, and shorter query durations,
|
||||||
* resulting in us returning labels/values that might not be applicable for the given window, this is a necessary trade off if we want to cache larger durations
|
* the window we're calculating might be much bigger then the user's current window,
|
||||||
*
|
* resulting in us returning labels/values that might not be applicable for the given window,
|
||||||
|
* this is a necessary trade-off if we want to cache larger durations
|
||||||
*/
|
*/
|
||||||
|
getTimeRangeParams(timeRange: TimeRange): { start: string; end: string } {
|
||||||
getTimeRangeParams(): { start: string; end: string } {
|
|
||||||
const range = this.timeSrv.timeRange();
|
|
||||||
return {
|
return {
|
||||||
start: getPrometheusTime(range.from, false).toString(),
|
start: getPrometheusTime(timeRange.from, false).toString(),
|
||||||
end: getPrometheusTime(range.to, true).toString(),
|
end: getPrometheusTime(timeRange.to, true).toString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,21 @@ const fromPrometheusTime = getPrometheusTime(dateTime(now - timeRangeDurationSec
|
|||||||
const toPrometheusTimeString = toPrometheusTime.toString(10);
|
const toPrometheusTimeString = toPrometheusTime.toString(10);
|
||||||
const fromPrometheusTimeString = fromPrometheusTime.toString(10);
|
const fromPrometheusTimeString = fromPrometheusTime.toString(10);
|
||||||
|
|
||||||
const getTimeRangeParams = (override?: Partial<{ start: string; end: string }>): { start: string; end: string } => ({
|
const getMockTimeRange = (): TimeRange => {
|
||||||
|
return {
|
||||||
|
to: dateTime(now).utc(),
|
||||||
|
from: dateTime(now).subtract(timeRangeDurationSeconds, 'second').utc(),
|
||||||
|
raw: {
|
||||||
|
from: fromPrometheusTimeString,
|
||||||
|
to: toPrometheusTimeString,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTimeRangeParams = (
|
||||||
|
timRange: TimeRange,
|
||||||
|
override?: Partial<{ start: string; end: string }>
|
||||||
|
): { start: string; end: string } => ({
|
||||||
start: fromPrometheusTimeString,
|
start: fromPrometheusTimeString,
|
||||||
end: toPrometheusTimeString,
|
end: toPrometheusTimeString,
|
||||||
...override,
|
...override,
|
||||||
@ -125,7 +139,8 @@ describe('Language completion provider', () => {
|
|||||||
it('should call series endpoint', () => {
|
it('should call series endpoint', () => {
|
||||||
const languageProvider = new LanguageProvider({
|
const languageProvider = new LanguageProvider({
|
||||||
...defaultDatasource,
|
...defaultDatasource,
|
||||||
getAdjustedInterval: () => getRangeSnapInterval(PrometheusCacheLevel.None, getMockQuantizedTimeRangeParams()),
|
getAdjustedInterval: (timeRange: TimeRange) =>
|
||||||
|
getRangeSnapInterval(PrometheusCacheLevel.None, getMockQuantizedTimeRangeParams()),
|
||||||
} as PrometheusDatasource);
|
} as PrometheusDatasource);
|
||||||
const getSeriesLabels = languageProvider.getSeriesLabels;
|
const getSeriesLabels = languageProvider.getSeriesLabels;
|
||||||
const requestSpy = jest.spyOn(languageProvider, 'request');
|
const requestSpy = jest.spyOn(languageProvider, 'request');
|
||||||
@ -152,7 +167,8 @@ describe('Language completion provider', () => {
|
|||||||
...defaultDatasource,
|
...defaultDatasource,
|
||||||
hasLabelsMatchAPISupport: () => true,
|
hasLabelsMatchAPISupport: () => true,
|
||||||
cacheLevel: PrometheusCacheLevel.Low,
|
cacheLevel: PrometheusCacheLevel.Low,
|
||||||
getAdjustedInterval: () => getRangeSnapInterval(PrometheusCacheLevel.Low, getMockQuantizedTimeRangeParams()),
|
getAdjustedInterval: (timeRange: TimeRange) =>
|
||||||
|
getRangeSnapInterval(PrometheusCacheLevel.Low, getMockQuantizedTimeRangeParams()),
|
||||||
getCacheDurationInMinutes: () => timeSnapMinutes,
|
getCacheDurationInMinutes: () => timeSnapMinutes,
|
||||||
} as PrometheusDatasource);
|
} as PrometheusDatasource);
|
||||||
const getSeriesLabels = languageProvider.getSeriesLabels;
|
const getSeriesLabels = languageProvider.getSeriesLabels;
|
||||||
@ -251,16 +267,21 @@ describe('Language completion provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('fetchSeries', () => {
|
describe('fetchSeries', () => {
|
||||||
it('should use match[] parameter', () => {
|
it('should use match[] parameter', async () => {
|
||||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||||
const fetchSeries = languageProvider.fetchSeries;
|
const timeRange = getMockTimeRange();
|
||||||
|
await languageProvider.start(timeRange);
|
||||||
const requestSpy = jest.spyOn(languageProvider, 'request');
|
const requestSpy = jest.spyOn(languageProvider, 'request');
|
||||||
fetchSeries('{job="grafana"}');
|
await languageProvider.fetchSeries('{job="grafana"}');
|
||||||
expect(requestSpy).toHaveBeenCalled();
|
expect(requestSpy).toHaveBeenCalled();
|
||||||
expect(requestSpy).toHaveBeenCalledWith(
|
expect(requestSpy).toHaveBeenCalledWith(
|
||||||
'/api/v1/series',
|
'/api/v1/series',
|
||||||
{},
|
{},
|
||||||
{ end: toPrometheusTimeString, 'match[]': '{job="grafana"}', start: fromPrometheusTimeString },
|
{
|
||||||
|
end: toPrometheusTimeString,
|
||||||
|
'match[]': '{job="grafana"}',
|
||||||
|
start: fromPrometheusTimeString,
|
||||||
|
},
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -7,8 +7,10 @@ import {
|
|||||||
AbstractLabelOperator,
|
AbstractLabelOperator,
|
||||||
AbstractQuery,
|
AbstractQuery,
|
||||||
dateTime,
|
dateTime,
|
||||||
|
getDefaultTimeRange,
|
||||||
HistoryItem,
|
HistoryItem,
|
||||||
LanguageProvider,
|
LanguageProvider,
|
||||||
|
TimeRange,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { BackendSrvRequest } from '@grafana/runtime';
|
import { BackendSrvRequest } from '@grafana/runtime';
|
||||||
import { CompletionItem, CompletionItemGroup, SearchFunctionType, TypeaheadInput, TypeaheadOutput } from '@grafana/ui';
|
import { CompletionItem, CompletionItemGroup, SearchFunctionType, TypeaheadInput, TypeaheadOutput } from '@grafana/ui';
|
||||||
@ -107,7 +109,7 @@ interface AutocompleteContext {
|
|||||||
const secondsInDay = 86400;
|
const secondsInDay = 86400;
|
||||||
export default class PromQlLanguageProvider extends LanguageProvider {
|
export default class PromQlLanguageProvider extends LanguageProvider {
|
||||||
histogramMetrics: string[];
|
histogramMetrics: string[];
|
||||||
timeRange?: { start: number; end: number };
|
timeRange: TimeRange;
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricsMetadata?: PromMetricsMetadata;
|
metricsMetadata?: PromMetricsMetadata;
|
||||||
declare startTask: Promise<any>;
|
declare startTask: Promise<any>;
|
||||||
@ -120,7 +122,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
|
|
||||||
this.datasource = datasource;
|
this.datasource = datasource;
|
||||||
this.histogramMetrics = [];
|
this.histogramMetrics = [];
|
||||||
this.timeRange = { start: 0, end: 0 };
|
this.timeRange = getDefaultTimeRange();
|
||||||
this.metrics = [];
|
this.metrics = [];
|
||||||
|
|
||||||
Object.assign(this, initialValues);
|
Object.assign(this, initialValues);
|
||||||
@ -155,7 +157,9 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
start = async (): Promise<any[]> => {
|
start = async (timeRange?: TimeRange): Promise<any[]> => {
|
||||||
|
this.timeRange = timeRange ?? getDefaultTimeRange();
|
||||||
|
|
||||||
if (this.datasource.lookupsDisabled) {
|
if (this.datasource.lookupsDisabled) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -504,7 +508,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
fetchLabelValues = async (key: string): Promise<string[]> => {
|
fetchLabelValues = async (key: string): Promise<string[]> => {
|
||||||
const params = this.datasource.getAdjustedInterval();
|
const params = this.datasource.getAdjustedInterval(this.timeRange);
|
||||||
const interpolatedName = this.datasource.interpolateString(key);
|
const interpolatedName = this.datasource.interpolateString(key);
|
||||||
const url = `/api/v1/label/${interpolatedName}/values`;
|
const url = `/api/v1/label/${interpolatedName}/values`;
|
||||||
const value = await this.request(url, [], params, this.getDefaultCacheHeaders());
|
const value = await this.request(url, [], params, this.getDefaultCacheHeaders());
|
||||||
@ -518,9 +522,12 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
/**
|
/**
|
||||||
* Fetches all label keys
|
* Fetches all label keys
|
||||||
*/
|
*/
|
||||||
async fetchLabels(): Promise<string[]> {
|
async fetchLabels(timeRange?: TimeRange): Promise<string[]> {
|
||||||
|
if (timeRange) {
|
||||||
|
this.timeRange = timeRange;
|
||||||
|
}
|
||||||
const url = '/api/v1/labels';
|
const url = '/api/v1/labels';
|
||||||
const params = this.datasource.getAdjustedInterval();
|
const params = this.datasource.getAdjustedInterval(this.timeRange);
|
||||||
this.labelFetchTs = Date.now().valueOf();
|
this.labelFetchTs = Date.now().valueOf();
|
||||||
|
|
||||||
const res = await this.request(url, [], params, this.getDefaultCacheHeaders());
|
const res = await this.request(url, [], params, this.getDefaultCacheHeaders());
|
||||||
@ -554,7 +561,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
fetchSeriesValuesWithMatch = async (name: string, match?: string): Promise<string[]> => {
|
fetchSeriesValuesWithMatch = async (name: string, match?: string): Promise<string[]> => {
|
||||||
const interpolatedName = name ? this.datasource.interpolateString(name) : null;
|
const interpolatedName = name ? this.datasource.interpolateString(name) : null;
|
||||||
const interpolatedMatch = match ? this.datasource.interpolateString(match) : null;
|
const interpolatedMatch = match ? this.datasource.interpolateString(match) : null;
|
||||||
const range = this.datasource.getAdjustedInterval();
|
const range = this.datasource.getAdjustedInterval(this.timeRange);
|
||||||
const urlParams = {
|
const urlParams = {
|
||||||
...range,
|
...range,
|
||||||
...(interpolatedMatch && { 'match[]': interpolatedMatch }),
|
...(interpolatedMatch && { 'match[]': interpolatedMatch }),
|
||||||
@ -603,7 +610,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
*/
|
*/
|
||||||
fetchSeriesLabels = async (name: string, withName?: boolean): Promise<Record<string, string[]>> => {
|
fetchSeriesLabels = async (name: string, withName?: boolean): Promise<Record<string, string[]>> => {
|
||||||
const interpolatedName = this.datasource.interpolateString(name);
|
const interpolatedName = this.datasource.interpolateString(name);
|
||||||
const range = this.datasource.getAdjustedInterval();
|
const range = this.datasource.getAdjustedInterval(this.timeRange);
|
||||||
const urlParams = {
|
const urlParams = {
|
||||||
...range,
|
...range,
|
||||||
'match[]': interpolatedName,
|
'match[]': interpolatedName,
|
||||||
@ -623,7 +630,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
*/
|
*/
|
||||||
fetchSeriesLabelsMatch = async (name: string, withName?: boolean): Promise<Record<string, string[]>> => {
|
fetchSeriesLabelsMatch = async (name: string, withName?: boolean): Promise<Record<string, string[]>> => {
|
||||||
const interpolatedName = this.datasource.interpolateString(name);
|
const interpolatedName = this.datasource.interpolateString(name);
|
||||||
const range = this.datasource.getAdjustedInterval();
|
const range = this.datasource.getAdjustedInterval(this.timeRange);
|
||||||
const urlParams = {
|
const urlParams = {
|
||||||
...range,
|
...range,
|
||||||
'match[]': interpolatedName,
|
'match[]': interpolatedName,
|
||||||
@ -641,7 +648,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
|||||||
*/
|
*/
|
||||||
fetchSeries = async (match: string): Promise<Array<Record<string, string>>> => {
|
fetchSeries = async (match: string): Promise<Array<Record<string, string>>> => {
|
||||||
const url = '/api/v1/series';
|
const url = '/api/v1/series';
|
||||||
const range = this.datasource.getTimeRangeParams();
|
const range = this.datasource.getTimeRangeParams(this.timeRange);
|
||||||
const params = { ...range, 'match[]': match };
|
const params = { ...range, 'match[]': match };
|
||||||
return await this.request(url, {}, params, this.getDefaultCacheHeaders());
|
return await this.request(url, {}, params, this.getDefaultCacheHeaders());
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'whatwg-fetch'; // fetch polyfill needed backendSrv
|
import 'whatwg-fetch'; // fetch polyfill needed backendSrv
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
|
import { DataSourceInstanceSettings, TimeRange, toUtc } from '@grafana/data';
|
||||||
import { FetchResponse } from '@grafana/runtime';
|
import { FetchResponse } from '@grafana/runtime';
|
||||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
@ -26,24 +26,16 @@ const instanceSettings = {
|
|||||||
password: 'mupp',
|
password: 'mupp',
|
||||||
jsonData: { httpMethod: 'GET' },
|
jsonData: { httpMethod: 'GET' },
|
||||||
} as Partial<DataSourceInstanceSettings<PromOptions>> as DataSourceInstanceSettings<PromOptions>;
|
} as Partial<DataSourceInstanceSettings<PromOptions>> as DataSourceInstanceSettings<PromOptions>;
|
||||||
const raw = {
|
|
||||||
|
const raw: TimeRange = {
|
||||||
from: toUtc('2018-04-25 10:00'),
|
from: toUtc('2018-04-25 10:00'),
|
||||||
to: toUtc('2018-04-25 11:00'),
|
to: toUtc('2018-04-25 11:00'),
|
||||||
|
raw: {
|
||||||
|
from: '2018-04-25 10:00',
|
||||||
|
to: '2018-04-25 11:00',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
|
|
||||||
__esModule: true,
|
|
||||||
getTimeSrv: jest.fn().mockReturnValue({
|
|
||||||
timeRange() {
|
|
||||||
return {
|
|
||||||
from: raw.from,
|
|
||||||
to: raw.to,
|
|
||||||
raw: raw,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const templateSrvStub = {
|
const templateSrvStub = {
|
||||||
getAdhocFilters: jest.fn().mockImplementation(() => []),
|
getAdhocFilters: jest.fn().mockImplementation(() => []),
|
||||||
replace: jest.fn().mockImplementation((a: string) => a),
|
replace: jest.fn().mockImplementation((a: string) => a),
|
||||||
@ -80,7 +72,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
data: ['name1', 'name2', 'name3'],
|
data: ['name1', 'name2', 'name3'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -102,7 +94,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
data: ['value1', 'value2', 'value3'],
|
data: ['value1', 'value2', 'value3'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -126,7 +118,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -152,7 +144,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -176,7 +168,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(2);
|
expect(results).toHaveLength(2);
|
||||||
expect(results[0].text).toBe('value1');
|
expect(results[0].text).toBe('value1');
|
||||||
@ -201,7 +193,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
data: ['metric1', 'metric2', 'metric3', 'nomatch'],
|
data: ['metric1', 'metric2', 'metric3', 'nomatch'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -228,7 +220,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(1);
|
expect(results).toHaveLength(1);
|
||||||
expect(results[0].text).toBe('metric{job="testjob"} 3846 1443454528000');
|
expect(results[0].text).toBe('metric{job="testjob"} 3846 1443454528000');
|
||||||
@ -251,7 +243,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
expect(results).toHaveLength(1);
|
expect(results).toHaveLength(1);
|
||||||
expect(results[0].text).toBe('2');
|
expect(results[0].text).toBe('2');
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -274,7 +266,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(results[0].text).toBe('up{instance="127.0.0.1:1234",job="job1"}');
|
expect(results[0].text).toBe('up{instance="127.0.0.1:1234",job="job1"}');
|
||||||
@ -309,7 +301,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
},
|
},
|
||||||
prometheusDatasource
|
prometheusDatasource
|
||||||
);
|
);
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(3);
|
expect(results).toHaveLength(3);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
@ -337,7 +329,7 @@ describe('PrometheusMetricFindQuery', () => {
|
|||||||
},
|
},
|
||||||
prometheusDatasource
|
prometheusDatasource
|
||||||
);
|
);
|
||||||
const results = await query.process();
|
const results = await query.process(raw);
|
||||||
|
|
||||||
expect(results).toHaveLength(1);
|
expect(results).toHaveLength(1);
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
|
@ -2,8 +2,7 @@ import { chain, map as _map, uniq } from 'lodash';
|
|||||||
import { lastValueFrom } from 'rxjs';
|
import { lastValueFrom } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MetricFindValue, TimeRange } from '@grafana/data';
|
import { getDefaultTimeRange, MetricFindValue, TimeRange } from '@grafana/data';
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
|
||||||
|
|
||||||
import { PrometheusDatasource } from './datasource';
|
import { PrometheusDatasource } from './datasource';
|
||||||
import { getPrometheusTime } from './language_utils';
|
import { getPrometheusTime } from './language_utils';
|
||||||
@ -24,10 +23,11 @@ export default class PrometheusMetricFindQuery {
|
|||||||
) {
|
) {
|
||||||
this.datasource = datasource;
|
this.datasource = datasource;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.range = getTimeSrv().timeRange();
|
this.range = getDefaultTimeRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
process(): Promise<MetricFindValue[]> {
|
process(timeRange: TimeRange): Promise<MetricFindValue[]> {
|
||||||
|
this.range = timeRange;
|
||||||
const labelNamesRegex = PrometheusLabelNamesRegex;
|
const labelNamesRegex = PrometheusLabelNamesRegex;
|
||||||
const labelNamesRegexWithMatch = PrometheusLabelNamesRegexWithMatch;
|
const labelNamesRegexWithMatch = PrometheusLabelNamesRegexWithMatch;
|
||||||
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
|
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
|
||||||
@ -46,7 +46,7 @@ export default class PrometheusMetricFindQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (labelNamesQuery) {
|
if (labelNamesQuery) {
|
||||||
return this.datasource.getTagKeys({ filters: [] });
|
return this.datasource.getTagKeys({ filters: [], timeRange });
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelValuesQuery = this.query.match(labelValuesRegex);
|
const labelValuesQuery = this.query.match(labelValuesRegex);
|
||||||
|
@ -60,6 +60,7 @@ export function MetricsLabelsSection({
|
|||||||
const onGetLabelNames = async (forLabel: Partial<QueryBuilderLabelFilter>): Promise<SelectableValue[]> => {
|
const onGetLabelNames = async (forLabel: Partial<QueryBuilderLabelFilter>): Promise<SelectableValue[]> => {
|
||||||
// If no metric we need to use a different method
|
// If no metric we need to use a different method
|
||||||
if (!query.metric) {
|
if (!query.metric) {
|
||||||
|
// FIXME pass timeRange to fetchLabels method
|
||||||
await datasource.languageProvider.fetchLabels();
|
await datasource.languageProvider.fetchLabels();
|
||||||
return datasource.languageProvider.getLabelKeys().map((k) => ({ value: k }));
|
return datasource.languageProvider.getLabelKeys().map((k) => ({ value: k }));
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,6 @@ function createDatasource(options?: Partial<DataSourceInstanceSettings<PromOptio
|
|||||||
...options,
|
...options,
|
||||||
} as DataSourceInstanceSettings<PromOptions>,
|
} as DataSourceInstanceSettings<PromOptions>,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
);
|
);
|
||||||
return { datasource, languageProvider };
|
return { datasource, languageProvider };
|
||||||
|
@ -44,7 +44,6 @@ function setup(queryOverrides: Partial<PromQuery> = {}) {
|
|||||||
meta: {} as DataSourcePluginMeta,
|
meta: {} as DataSourcePluginMeta,
|
||||||
} as DataSourceInstanceSettings,
|
} as DataSourceInstanceSettings,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ function createDatasource() {
|
|||||||
meta: {} as DataSourcePluginMeta,
|
meta: {} as DataSourcePluginMeta,
|
||||||
} as DataSourceInstanceSettings,
|
} as DataSourceInstanceSettings,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
);
|
);
|
||||||
return { datasource, languageProvider };
|
return { datasource, languageProvider };
|
||||||
|
@ -84,7 +84,6 @@ const getDefaultDatasource = (jsonDataOverrides = {}) =>
|
|||||||
readOnly: false,
|
readOnly: false,
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
new EmptyLanguageProviderMock() as unknown as PromQlLanguageProvider
|
new EmptyLanguageProviderMock() as unknown as PromQlLanguageProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -233,7 +233,6 @@ function createDatasource(withLabels?: boolean) {
|
|||||||
meta: {} as DataSourcePluginMeta,
|
meta: {} as DataSourcePluginMeta,
|
||||||
} as DataSourceInstanceSettings<PromOptions>,
|
} as DataSourceInstanceSettings<PromOptions>,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
);
|
);
|
||||||
return datasource;
|
return datasource;
|
||||||
|
@ -116,7 +116,6 @@ function createDatasource(withLabels?: boolean) {
|
|||||||
meta: {} as DataSourcePluginMeta,
|
meta: {} as DataSourcePluginMeta,
|
||||||
} as DataSourceInstanceSettings<PromOptions>,
|
} as DataSourceInstanceSettings<PromOptions>,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
);
|
);
|
||||||
return datasource;
|
return datasource;
|
||||||
|
@ -73,7 +73,6 @@ function setup(query: PromVisualQuery = defaultQuery) {
|
|||||||
meta: {},
|
meta: {},
|
||||||
} as DataSourceInstanceSettings<PromOptions>,
|
} as DataSourceInstanceSettings<PromOptions>,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
languageProvider
|
languageProvider
|
||||||
) as DataSourceApi,
|
) as DataSourceApi,
|
||||||
onRunQuery: () => {},
|
onRunQuery: () => {},
|
||||||
|
@ -12,7 +12,6 @@ import { faro } from '@grafana/faro-web-sdk';
|
|||||||
import { config, reportInteraction } from '@grafana/runtime/src';
|
import { config, reportInteraction } from '@grafana/runtime/src';
|
||||||
import { amendTable, Table, trimTable } from 'app/features/live/data/amendTimeSeries';
|
import { amendTable, Table, trimTable } from 'app/features/live/data/amendTimeSeries';
|
||||||
|
|
||||||
import { getTimeSrv } from '../../../../features/dashboard/services/TimeSrv';
|
|
||||||
import { PromQuery } from '../types';
|
import { PromQuery } from '../types';
|
||||||
|
|
||||||
// dashboardUID + panelId + refId
|
// dashboardUID + panelId + refId
|
||||||
@ -260,7 +259,7 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
|||||||
let doPartialQuery = shouldCache;
|
let doPartialQuery = shouldCache;
|
||||||
let prevTo: TimestampMs | undefined = undefined;
|
let prevTo: TimestampMs | undefined = undefined;
|
||||||
|
|
||||||
const refreshIntervalMs = getTimeSrv().refreshMS;
|
const refreshIntervalMs = request.intervalMs;
|
||||||
|
|
||||||
// pre-compute reqTargSigs
|
// pre-compute reqTargSigs
|
||||||
const reqTargSigs = new Map<TargetIdent, TargetSig>();
|
const reqTargSigs = new Map<TargetIdent, TargetSig>();
|
||||||
|
@ -4,8 +4,6 @@ import { map } from 'rxjs/operators';
|
|||||||
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, rangeUtil } from '@grafana/data';
|
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, rangeUtil } from '@grafana/data';
|
||||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { getTimeSrv, TimeSrv } from '../../../features/dashboard/services/TimeSrv';
|
|
||||||
|
|
||||||
import { PromVariableQueryEditor } from './components/VariableQueryEditor';
|
import { PromVariableQueryEditor } from './components/VariableQueryEditor';
|
||||||
import { PrometheusDatasource } from './datasource';
|
import { PrometheusDatasource } from './datasource';
|
||||||
import PrometheusMetricFindQuery from './metric_find_query';
|
import PrometheusMetricFindQuery from './metric_find_query';
|
||||||
@ -14,8 +12,7 @@ import { PromVariableQuery } from './types';
|
|||||||
export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusDatasource> {
|
export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusDatasource> {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly datasource: PrometheusDatasource,
|
private readonly datasource: PrometheusDatasource,
|
||||||
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
private readonly templateSrv: TemplateSrv = getTemplateSrv()
|
||||||
private readonly timeSrv: TimeSrv = getTimeSrv()
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -49,12 +46,12 @@ export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusD
|
|||||||
text: rangeUtil.intervalToMs(this.datasource.interval),
|
text: rangeUtil.intervalToMs(this.datasource.interval),
|
||||||
value: rangeUtil.intervalToMs(this.datasource.interval),
|
value: rangeUtil.intervalToMs(this.datasource.interval),
|
||||||
},
|
},
|
||||||
...this.datasource.getRangeScopedVars(this.timeSrv.timeRange()),
|
...this.datasource.getRangeScopedVars(request.range),
|
||||||
};
|
};
|
||||||
|
|
||||||
const interpolated = this.templateSrv.replace(query, scopedVars, this.datasource.interpolateQueryExpr);
|
const interpolated = this.templateSrv.replace(query, scopedVars, this.datasource.interpolateQueryExpr);
|
||||||
const metricFindQuery = new PrometheusMetricFindQuery(this.datasource, interpolated);
|
const metricFindQuery = new PrometheusMetricFindQuery(this.datasource, interpolated);
|
||||||
const metricFindStream = from(metricFindQuery.process());
|
const metricFindStream = from(metricFindQuery.process(request.range));
|
||||||
|
|
||||||
return metricFindStream.pipe(map((results) => ({ data: results })));
|
return metricFindStream.pipe(map((results) => ({ data: results })));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user