mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Refactor template variable logic and remove reliance on timeSrv
(#78586)
* Loki: Refactor variables support to reuse loic * Remove redundant methods * Make parseStringToVariableQuery private
This commit is contained in:
parent
8120306fea
commit
8a7eb4b484
@ -5947,8 +5947,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
|
||||
],
|
||||
"public/app/plugins/datasource/loki/queryUtils.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { LokiVariableSupport } from './LokiVariableSupport';
|
||||
import { createLokiDatasource, createMetadataRequest } from './mocks';
|
||||
import { LokiVariableQueryType } from './types';
|
||||
import { LokiVariableSupport } from './variables';
|
||||
|
||||
describe('LokiVariableSupport', () => {
|
||||
let lokiVariableSupport: LokiVariableSupport;
|
@ -26,14 +26,7 @@ describe('LokiVariableQueryEditor', () => {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
jest.spyOn(props.datasource, 'labelNamesQuery').mockResolvedValue([
|
||||
{
|
||||
text: 'moon',
|
||||
},
|
||||
{
|
||||
text: 'luna',
|
||||
},
|
||||
]);
|
||||
jest.spyOn(props.datasource.languageProvider, 'fetchLabels').mockResolvedValue(['luna', 'moon']);
|
||||
});
|
||||
|
||||
test('Allows to create a Label names variable', async () => {
|
||||
|
@ -38,8 +38,8 @@ export const LokiVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
||||
return;
|
||||
}
|
||||
|
||||
datasource.labelNamesQuery().then((labelNames: Array<{ text: string }>) => {
|
||||
setLabelOptions(labelNames.map(({ text }) => ({ label: text, value: text })));
|
||||
datasource.languageProvider.fetchLabels().then((labelNames: string[]) => {
|
||||
setLabelOptions(labelNames.map((labelName) => ({ label: labelName, value: labelName })));
|
||||
});
|
||||
}, [datasource, type]);
|
||||
|
||||
|
@ -28,12 +28,12 @@ import {
|
||||
TemplateSrv,
|
||||
} from '@grafana/runtime';
|
||||
|
||||
import { LokiVariableSupport } from './LokiVariableSupport';
|
||||
import { LokiDatasource, REF_ID_DATA_SAMPLES } from './datasource';
|
||||
import { createLokiDatasource, createMetadataRequest } from './mocks';
|
||||
import { runSplitQuery } from './querySplitting';
|
||||
import { parseToNodeNamesArray } from './queryUtils';
|
||||
import { LokiOptions, LokiQuery, LokiQueryType, LokiVariableQueryType, SupportingQueryType } from './types';
|
||||
import { LokiVariableSupport } from './variables';
|
||||
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
return {
|
||||
|
@ -37,6 +37,9 @@ import {
|
||||
LegacyMetricFindQueryOptions,
|
||||
AdHocVariableFilter,
|
||||
urlUtil,
|
||||
MetricFindValue,
|
||||
DataSourceGetTagValuesOptions,
|
||||
DataSourceGetTagKeysOptions,
|
||||
DataSourceWithQueryModificationSupport,
|
||||
} from '@grafana/data';
|
||||
import { Duration } from '@grafana/lezer-logql';
|
||||
@ -51,6 +54,7 @@ import { replaceVariables, returnVariables } from '../prometheus/querybuilder/sh
|
||||
import LanguageProvider from './LanguageProvider';
|
||||
import { LiveStreams, LokiLiveTarget } from './LiveStreams';
|
||||
import { LogContextProvider } from './LogContextProvider';
|
||||
import { LokiVariableSupport } from './LokiVariableSupport';
|
||||
import { transformBackendResult } from './backendResultTransformer';
|
||||
import { LokiAnnotationsQueryEditor } from './components/AnnotationsQueryEditor';
|
||||
import { placeHolderScopedVars } from './components/monaco-query-field/monaco-completion-provider/validation';
|
||||
@ -94,7 +98,6 @@ import {
|
||||
QueryStats,
|
||||
SupportingQueryType,
|
||||
} from './types';
|
||||
import { LokiVariableSupport } from './variables';
|
||||
|
||||
export type RangeQueryOptions = DataQueryRequest<LokiQuery> | AnnotationQueryRequest<LokiQuery>;
|
||||
export const DEFAULT_MAX_LINES = 1000;
|
||||
@ -646,23 +649,31 @@ export class LokiDatasource
|
||||
* Implemented as part of DataSourceAPI and used for template variable queries.
|
||||
* @returns A Promise that resolves to an array of results from the metric find query.
|
||||
*/
|
||||
async metricFindQuery(query: LokiVariableQuery | string, options?: LegacyMetricFindQueryOptions) {
|
||||
async metricFindQuery(
|
||||
query: LokiVariableQuery | string,
|
||||
options?: LegacyMetricFindQueryOptions
|
||||
): Promise<MetricFindValue[]> {
|
||||
if (!query) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
let interpolatedVariableQuery: LokiVariableQuery | undefined;
|
||||
|
||||
if (typeof query === 'string') {
|
||||
const interpolated = this.interpolateString(query, options?.scopedVars);
|
||||
return await this.legacyProcessMetricFindQuery(interpolated);
|
||||
interpolatedVariableQuery = this.parseStringToVariableQuery(this.interpolateString(query, options?.scopedVars));
|
||||
} else {
|
||||
interpolatedVariableQuery = {
|
||||
...query,
|
||||
label: this.interpolateString(query.label || '', options?.scopedVars),
|
||||
stream: this.interpolateString(query.stream || '', options?.scopedVars),
|
||||
};
|
||||
}
|
||||
|
||||
const interpolatedQuery = {
|
||||
...query,
|
||||
label: this.interpolateString(query.label || '', options?.scopedVars),
|
||||
stream: this.interpolateString(query.stream || '', options?.scopedVars),
|
||||
};
|
||||
if (interpolatedVariableQuery) {
|
||||
return await this.processMetricFindQuery(interpolatedVariableQuery, options?.range);
|
||||
}
|
||||
|
||||
return await this.processMetricFindQuery(interpolatedQuery);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -670,9 +681,10 @@ export class LokiDatasource
|
||||
* @returns A Promise that resolves to an array of variable results based on the query type and parameters.
|
||||
*/
|
||||
|
||||
private async processMetricFindQuery(query: LokiVariableQuery) {
|
||||
private async processMetricFindQuery(query: LokiVariableQuery, timeRange?: TimeRange): Promise<MetricFindValue[]> {
|
||||
if (query.type === LokiVariableQueryType.LabelNames) {
|
||||
return this.labelNamesQuery();
|
||||
const result = await this.languageProvider.fetchLabels({ timeRange });
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
if (!query.label) {
|
||||
@ -681,81 +693,38 @@ export class LokiDatasource
|
||||
|
||||
// If we have stream selector, use /series endpoint
|
||||
if (query.stream) {
|
||||
return this.labelValuesSeriesQuery(query.stream, query.label);
|
||||
const result = await this.languageProvider.fetchSeriesLabels(query.stream, { timeRange });
|
||||
return result[query.label].map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
return this.labelValuesQuery(query.label);
|
||||
const result = await this.languageProvider.fetchLabelValues(query.label, { timeRange });
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in `metricFindQuery` to process legacy query strings (label_name() and label_values()) and return variable results.
|
||||
* @returns A Promise that resolves to an array of variables based on the legacy query string.
|
||||
* @todo It can be refactored in the future to return a LokiVariableQuery and be used in `processMetricFindQuery`
|
||||
* to not duplicate querying logic.
|
||||
* Used in `metricFindQuery` to process legacy query strings (label_name() and label_values()) to variable query objects.
|
||||
* @returns LokiVariableQuery object based on the provided query string, or undefined if string can't be parsed.
|
||||
*/
|
||||
async legacyProcessMetricFindQuery(query: string) {
|
||||
private parseStringToVariableQuery(query: string): LokiVariableQuery | undefined {
|
||||
const refId = 'LokiVariableQueryEditor-VariableQuery';
|
||||
const labelNames = query.match(labelNamesRegex);
|
||||
if (labelNames) {
|
||||
return await this.labelNamesQuery();
|
||||
return {
|
||||
type: LokiVariableQueryType.LabelNames,
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
const labelValues = query.match(labelValuesRegex);
|
||||
if (labelValues) {
|
||||
// If we have stream selector, use /series endpoint
|
||||
if (labelValues[1]) {
|
||||
return await this.labelValuesSeriesQuery(labelValues[1], labelValues[2]);
|
||||
}
|
||||
return await this.labelValuesQuery(labelValues[2]);
|
||||
return {
|
||||
type: LokiVariableQueryType.LabelValues,
|
||||
label: labelValues[2],
|
||||
stream: labelValues[1],
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method used in `processMetricFindQuery`, `legacyProcessMetricFindQuery` and `getTagKeys` to fetch label names.
|
||||
* @returns A Promise that resolves to an array of label names as text values.
|
||||
* @todo Future exploration may involve using the `languageProvider.fetchLabels()` to avoid duplicating logic.
|
||||
*/
|
||||
async labelNamesQuery() {
|
||||
const url = 'labels';
|
||||
const params = this.getTimeRangeParams();
|
||||
const result = await this.metadataRequest(url, params);
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method used in `processMetricFindQuery`, `legacyProcessMetricFindQuery` `getTagValues` to fetch label values.
|
||||
* @returns A Promise that resolves to an array of label values as text values.
|
||||
* @todo Future exploration may involve using the `languageProvider.fetchLabelValues()` method to avoid duplicating logic.
|
||||
*/
|
||||
private async labelValuesQuery(label: string) {
|
||||
const params = this.getTimeRangeParams();
|
||||
const url = `label/${label}/values`;
|
||||
const result = await this.metadataRequest(url, params);
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method used in `processMetricFindQuery` and `legacyProcessMetricFindQuery` to fetch label values for specified stream.
|
||||
* @returns A Promise that resolves to an array of label values as text values.
|
||||
* @todo Future exploration may involve using the `languageProvider.fetchLabelValues()` or `languageProvider.fetchSeriesLabels()` method to avoid duplicating logic.
|
||||
*/
|
||||
private async labelValuesSeriesQuery(expr: string, label: string) {
|
||||
const timeParams = this.getTimeRangeParams();
|
||||
const params = {
|
||||
...timeParams,
|
||||
'match[]': expr,
|
||||
};
|
||||
const url = 'series';
|
||||
const streams = new Set();
|
||||
const result = await this.metadataRequest(url, params);
|
||||
result.forEach((stream: { [key: string]: string }) => {
|
||||
if (stream[label]) {
|
||||
streams.add({ text: stream[label] });
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(streams);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -784,18 +753,20 @@ export class LokiDatasource
|
||||
|
||||
/**
|
||||
* Implemented as part of the DataSourceAPI. Retrieves tag keys that can be used for ad-hoc filtering.
|
||||
* @returns A Promise that resolves to an array of label names.
|
||||
* @returns A Promise that resolves to an array of label names represented as MetricFindValue objects.
|
||||
*/
|
||||
async getTagKeys() {
|
||||
return await this.labelNamesQuery();
|
||||
async getTagKeys(options?: DataSourceGetTagKeysOptions): Promise<MetricFindValue[]> {
|
||||
const result = await this.languageProvider.fetchLabels({ timeRange: options?.timeRange });
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented as part of the DataSourceAPI. Retrieves tag values that can be used for ad-hoc filtering.
|
||||
* @returns A Promise that resolves to an array of label values.
|
||||
* @returns A Promise that resolves to an array of label values represented as MetricFindValue objects
|
||||
*/
|
||||
async getTagValues(options: any = {}) {
|
||||
return await this.labelValuesQuery(options.key);
|
||||
async getTagValues(options: DataSourceGetTagValuesOptions): Promise<MetricFindValue[]> {
|
||||
const result = await this.languageProvider.fetchLabelValues(options.key, { timeRange: options.timeRange });
|
||||
return result.map((value: string) => ({ text: value }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user