mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Support utf8 metrics and labels in variable editor (#98345)
* utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support utf8 metric names in explore metrics * utf8 support in grouop by * utf8 support in label break down * utf8 metric and label support in metric_find_query for label values * use the same regex to check label values * no need to escape * support series endpoint * support series endpoint * support series endpoint * support series endpoint * fix tests * fix extracting labels from labelValuesQuery * betterer
This commit is contained in:
@@ -8,6 +8,7 @@ import { PrometheusDatasource } from './datasource';
|
||||
import { getPrometheusTime } from './language_utils';
|
||||
import { PrometheusMetricFindQuery } from './metric_find_query';
|
||||
import { PromApplication, PromOptions } from './types';
|
||||
import { escapeForUtf8Support } from './utf8_support';
|
||||
|
||||
const fetchMock = jest.fn((options: BackendSrvRequest): Observable<FetchResponse<BackendDataSourceResponse>> => {
|
||||
return of({} as unknown as FetchResponse);
|
||||
@@ -413,5 +414,51 @@ describe('PrometheusMetricFindQuery', () => {
|
||||
});
|
||||
});
|
||||
// </ ModernPrometheus>
|
||||
describe('utf8 metric and label support', () => {
|
||||
it('utf8 label - label_values(a_utf8_http_requests_total,instance.test) should generate label values query', () => {
|
||||
const metricName = 'a_utf8_http_requests_total';
|
||||
const label = 'instance.test';
|
||||
const query = `label_values(${metricName},${label})`;
|
||||
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
|
||||
metricFindQuery.process(raw);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock).toHaveBeenCalledWith({
|
||||
method: 'GET',
|
||||
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
|
||||
hideFromInspector: true,
|
||||
headers: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('utf8 metric - label_values(utf8.http_requests_total,instance_test) should generate label values query', () => {
|
||||
const metricName = 'utf8.http_requests_total';
|
||||
const label = 'instance_test';
|
||||
const query = `label_values(${metricName},${label})`;
|
||||
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
|
||||
metricFindQuery.process(raw);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock).toHaveBeenCalledWith({
|
||||
method: 'GET',
|
||||
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${label}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
|
||||
hideFromInspector: true,
|
||||
headers: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('utf8 metric and label - label_values(utf8.http_requests_total,instance.test) should generate label values query', () => {
|
||||
const metricName = 'utf8.http_requests_total';
|
||||
const label = 'instance.test';
|
||||
const query = `label_values(${metricName},${label})`;
|
||||
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
|
||||
metricFindQuery.process(raw);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock).toHaveBeenCalledWith({
|
||||
method: 'GET',
|
||||
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
|
||||
hideFromInspector: true,
|
||||
headers: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,9 +8,11 @@ import { getPrometheusTime } from './language_utils';
|
||||
import {
|
||||
PrometheusLabelNamesRegex,
|
||||
PrometheusLabelNamesRegexWithMatch,
|
||||
PrometheusLabelValuesRegex,
|
||||
PrometheusMetricNamesRegex,
|
||||
PrometheusQueryResultRegex,
|
||||
} from './migrations/variableMigration';
|
||||
import { escapeForUtf8Support, isValidLegacyName } from './utf8_support';
|
||||
|
||||
export class PrometheusMetricFindQuery {
|
||||
range: TimeRange;
|
||||
@@ -28,7 +30,7 @@ export class PrometheusMetricFindQuery {
|
||||
this.range = timeRange;
|
||||
const labelNamesRegex = PrometheusLabelNamesRegex;
|
||||
const labelNamesRegexWithMatch = PrometheusLabelNamesRegexWithMatch;
|
||||
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
|
||||
const labelValuesRegex = PrometheusLabelValuesRegex;
|
||||
const metricNamesRegex = PrometheusMetricNamesRegex;
|
||||
const queryResultRegex = PrometheusQueryResultRegex;
|
||||
const labelNamesQuery = this.query.match(labelNamesRegex);
|
||||
@@ -83,8 +85,13 @@ export class PrometheusMetricFindQuery {
|
||||
const end = getPrometheusTime(this.range.to, true);
|
||||
const params = { ...(metric && { 'match[]': metric }), start: start.toString(), end: end.toString() };
|
||||
|
||||
let escapedLabel = label;
|
||||
if (!isValidLegacyName(label)) {
|
||||
escapedLabel = escapeForUtf8Support(label);
|
||||
}
|
||||
|
||||
if (!metric || this.datasource.hasLabelsMatchAPISupport()) {
|
||||
const url = `/api/v1/label/${label}/values`;
|
||||
const url = `/api/v1/label/${escapedLabel}/values`;
|
||||
|
||||
return this.datasource.metadataRequest(url, params).then((result) => {
|
||||
return _map(result.data.data, (value) => {
|
||||
|
||||
@@ -4,8 +4,7 @@ import { buildVisualQueryFromString } from '../querybuilder/parsing';
|
||||
import { PromVariableQuery, PromVariableQueryType as QueryType } from '../types';
|
||||
|
||||
export const PrometheusLabelNamesRegex = /^label_names\(\)\s*$/;
|
||||
// Note that this regex is different from the one in metric_find_query.ts because this is used pre-interpolation
|
||||
export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_$][a-zA-Z0-9_]*)\)\s*$/;
|
||||
export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?(.+)\)\s*$/;
|
||||
export const PrometheusMetricNamesRegex = /^metrics\((.+)\)\s*$/;
|
||||
export const PrometheusQueryResultRegex = /^query_result\((.+)\)\s*$/;
|
||||
export const PrometheusLabelNamesRegexWithMatch = /^label_names\((.+)\)\s*$/;
|
||||
@@ -97,7 +96,7 @@ export function migrateVariableQueryToEditor(rawQuery: string | PromVariableQuer
|
||||
return queryBase;
|
||||
}
|
||||
|
||||
// migrate it back to a string with the correct varialbes in place
|
||||
// migrate it back to a string with the correct variables in place
|
||||
export function migrateVariableEditorBackToVariableSupport(QueryVariable: PromVariableQuery): string {
|
||||
switch (QueryVariable.qryType) {
|
||||
case QueryType.LabelNames:
|
||||
|
||||
Reference in New Issue
Block a user