diff --git a/.betterer.results b/.betterer.results
index 1f4e6445dee..7e9cc245d29 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -6266,8 +6266,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
- [0, 0, 0, "Do not use any type assertions.", "3"],
- [0, 0, 0, "Unexpected any. Specify a different type.", "4"]
+ [0, 0, 0, "Unexpected any. Specify a different type.", "3"],
+ [0, 0, 0, "Do not use any type assertions.", "4"],
+ [0, 0, 0, "Unexpected any. Specify a different type.", "5"]
],
"public/app/plugins/datasource/prometheus/query_hints.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
diff --git a/docs/sources/datasources/prometheus/template-variables/index.md b/docs/sources/datasources/prometheus/template-variables/index.md
index 8004fd233a9..8b69205c235 100644
--- a/docs/sources/datasources/prometheus/template-variables/index.md
+++ b/docs/sources/datasources/prometheus/template-variables/index.md
@@ -23,17 +23,17 @@ For an introduction to templating and template variables, refer to the [Templati
## Use query variables
-Use variables of the type _Query_ to query Prometheus for a list of metrics, labels, or label values.
+You can use variables of the type _Query_ to query Prometheus for a list of metrics, labels, or label values.
-Select a Prometheus data source query type and enter the required inputs:
+You can use these Prometheus data source functions in the **Query** input field:
-| Query Type | Input(\* required) | Description | Used API endpoints |
-| -------------- | ------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------- |
-| `Label names` | none | Returns a list of all label names. | /api/v1/labels |
-| `Label values` | `label`\*, `metric` | Returns a list of label values for the `label` in all metrics or the optional metric. | /api/v1/label/`label`/values or /api/v1/series |
-| `Metrics` | `metric` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
-| `Query result` | `query` | Returns a list of Prometheus query result for the `query`. | /api/v1/query |
-| `Series query` | `metric`, `label` or both | Returns a list of time series associated with the entered data. | /api/v1/series |
+| Name | Description | Used API endpoints |
+| ----------------------------- | ----------------------------------------------------------------------- | --------------------------------- |
+| `label_names()` | Returns a list of label names. | /api/v1/labels |
+| `label_values(label)` | Returns a list of label values for the `label` in every metric. | /api/v1/label/`label`/values |
+| `label_values(metric, label)` | Returns a list of label values for the `label` in the specified metric. | /api/v1/series |
+| `metrics(metric)` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
+| `query_result(query)` | Returns a list of Prometheus query result for the `query`. | /api/v1/query |
For details on _metric names_, _label names_, and _label values_, refer to the [Prometheus documentation](http://prometheus.io/docs/concepts/data_model/#metric-names-and-labels).
diff --git a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx
deleted file mode 100644
index 099e7709da5..00000000000
--- a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-import { render, screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import React from 'react';
-import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
-
-import { PrometheusDatasource } from '../datasource';
-
-import { PromVariableQueryEditor, Props } from './VariableQueryEditor';
-
-const refId = 'PrometheusVariableQueryEditor-VariableQuery';
-
-describe('PromVariableQueryEditor', () => {
- let props: Props;
-
- beforeEach(() => {
- props = {
- datasource: {
- hasLabelsMatchAPISupport: () => 1,
- languageProvider: {
- start: () => Promise.resolve([]),
- syntax: () => {},
- getLabelKeys: () => [],
- metrics: [],
- },
- getInitHints: () => [],
- } as unknown as PrometheusDatasource,
- query: {
- refId: 'test',
- query: 'label_names()',
- },
- onRunQuery: () => {},
- onChange: () => {},
- history: [],
- };
- });
-
- test('Displays a group of function options', async () => {
- render();
-
- const select = screen.getByLabelText('Query type').parentElement!;
- await userEvent.click(select);
-
- await waitFor(() => expect(screen.getAllByText('Label names')).toHaveLength(2));
- await waitFor(() => expect(screen.getByText('Label values')).toBeInTheDocument());
- await waitFor(() => expect(screen.getByText('Metrics')).toBeInTheDocument());
- await waitFor(() => expect(screen.getByText('Query result')).toBeInTheDocument());
- await waitFor(() => expect(screen.getByText('Series query')).toBeInTheDocument());
- });
-
- test('Calls onChange for label_names() query', async () => {
- const onChange = jest.fn();
-
- props.query = {
- refId: 'test',
- query: '',
- };
-
- render();
-
- await selectOptionInTest(screen.getByLabelText('Query type'), 'Label names');
-
- expect(onChange).toHaveBeenCalledWith({
- query: 'label_names()',
- refId,
- });
- });
-
- test('Does not call onChange for other queries', async () => {
- const onChange = jest.fn();
-
- render();
-
- await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics');
- await selectOptionInTest(screen.getByLabelText('Query type'), 'Query result');
- await selectOptionInTest(screen.getByLabelText('Query type'), 'Series query');
-
- expect(onChange).not.toHaveBeenCalled();
- });
-
- test('Calls onChange for metrics() with argument onBlur', async () => {
- const onChange = jest.fn();
-
- props.query = {
- refId: 'test',
- query: 'metrics(a)',
- };
-
- render();
-
- const labelSelect = screen.getByLabelText('Metric selector');
- await userEvent.click(labelSelect);
- const functionSelect = screen.getByLabelText('Query type').parentElement!;
- await userEvent.click(functionSelect);
-
- expect(onChange).toHaveBeenCalledWith({
- query: 'metrics(a)',
- refId,
- });
- });
-
- test('Calls onChange for query_result() with argument onBlur', async () => {
- const onChange = jest.fn();
-
- props.query = {
- refId: 'test',
- query: 'query_result(a)',
- };
-
- render();
-
- const labelSelect = screen.getByLabelText('Prometheus Query');
- await userEvent.click(labelSelect);
- const functionSelect = screen.getByLabelText('Query type').parentElement!;
- await userEvent.click(functionSelect);
-
- expect(onChange).toHaveBeenCalledWith({
- query: 'query_result(a)',
- refId,
- });
- });
-
- test('Calls onChange for Match[] series with argument onBlur', async () => {
- const onChange = jest.fn();
-
- props.query = {
- refId: 'test',
- query: '{a: "example"}',
- };
-
- render();
-
- const labelSelect = screen.getByLabelText('Series Query');
- await userEvent.click(labelSelect);
- const functionSelect = screen.getByLabelText('Query type').parentElement!;
- await userEvent.click(functionSelect);
-
- expect(onChange).toHaveBeenCalledWith({
- query: '{a: "example"}',
- refId,
- });
- });
-});
diff --git a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx
deleted file mode 100644
index ebe23e6e179..00000000000
--- a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx
+++ /dev/null
@@ -1,257 +0,0 @@
-import React, { FC, FormEvent, useEffect, useState } from 'react';
-
-import { QueryEditorProps, SelectableValue } from '@grafana/data';
-import { InlineField, InlineFieldRow, Input, Select, TextArea } from '@grafana/ui';
-
-import { PrometheusDatasource } from '../datasource';
-import {
- migrateVariableEditorBackToVariableSupport,
- migrateVariableQueryToEditor,
-} from '../migrations/variableMigration';
-import { PromOptions, PromQuery, PromVariableQuery, PromVariableQueryType as QueryType } from '../types';
-
-export const variableOptions = [
- { label: 'Label names', value: QueryType.LabelNames },
- { label: 'Label values', value: QueryType.LabelValues },
- { label: 'Metrics', value: QueryType.MetricNames },
- { label: 'Query result', value: QueryType.VarQueryResult },
- { label: 'Series query', value: QueryType.SeriesQuery },
-];
-
-export type Props = QueryEditorProps;
-
-const refId = 'PrometheusVariableQueryEditor-VariableQuery';
-
-export const PromVariableQueryEditor: FC = ({ onChange, query, datasource }) => {
- // to select the query type, i.e. label_names, label_values, etc.
- const [qryType, setQryType] = useState(undefined);
-
- // list of variables for each function
- const [label, setLabel] = useState('');
- // metric is used for both label_values() and metric()
- // label_values() metric requires a whole/complete metric
- // metric() is expected to be a part of a metric string
- const [metric, setMetric] = useState('');
- // varQuery is a whole query, can include math/rates/etc
- const [varQuery, setVarQuery] = useState('');
- // seriesQuery is only a whole
- const [seriesQuery, setSeriesQuery] = useState('');
-
- // list of label names for label_values(), /api/v1/labels, contains the same results as label_names() function
- const [labelOptions, setLabelOptions] = useState>>([]);
-
- useEffect(() => {
- if (!query) {
- return;
- }
- // Changing from standard to custom variable editor changes the string attr from expr to query
- const variableQuery = query.query ? migrateVariableQueryToEditor(query.query) : query;
-
- setQryType(variableQuery.qryType);
- setLabel(variableQuery.label ?? '');
- setMetric(variableQuery.metric ?? '');
- setVarQuery(variableQuery.varQuery ?? '');
- setSeriesQuery(variableQuery.seriesQuery ?? '');
-
- // set the migrated label in the label options
- if (variableQuery.label) {
- setLabelOptions([{ label: variableQuery.label, value: variableQuery.label }]);
- }
- }, [query]);
-
- // set the label names options for the label values var query
- useEffect(() => {
- if (qryType !== QueryType.LabelValues) {
- return;
- }
-
- datasource.getLabelNames().then((labelNames: Array<{ text: string }>) => {
- setLabelOptions(labelNames.map(({ text }) => ({ label: text, value: text })));
- });
- }, [datasource, qryType]);
-
- const onChangeWithVariableString = (qryType: QueryType) => {
- const queryVar = {
- qryType: qryType,
- label,
- metric,
- varQuery,
- seriesQuery,
- refId: 'PrometheusVariableQueryEditor-VariableQuery',
- };
-
- const queryString = migrateVariableEditorBackToVariableSupport(queryVar);
-
- onChange({
- query: queryString,
- refId,
- });
- };
-
- const onQueryTypeChange = (newType: SelectableValue) => {
- setQryType(newType.value);
- if (newType.value === QueryType.LabelNames) {
- onChangeWithVariableString(newType.value);
- }
- };
-
- const onLabelChange = (newLabel: SelectableValue) => {
- setLabel(newLabel.value ?? '');
- };
-
- const onMetricChange = (e: FormEvent) => {
- setMetric(e.currentTarget.value);
- };
-
- const onVarQueryChange = (e: FormEvent) => {
- setVarQuery(e.currentTarget.value);
- };
-
- const onSeriesQueryChange = (e: FormEvent) => {
- setSeriesQuery(e.currentTarget.value);
- };
-
- const handleBlur = () => {
- if (qryType === QueryType.LabelNames) {
- onChangeWithVariableString(qryType);
- } else if (qryType === QueryType.LabelValues && label) {
- onChangeWithVariableString(qryType);
- } else if (qryType === QueryType.MetricNames && metric) {
- onChangeWithVariableString(qryType);
- } else if (qryType === QueryType.VarQueryResult && varQuery) {
- onChangeWithVariableString(qryType);
- } else if (qryType === QueryType.SeriesQuery && seriesQuery) {
- onChangeWithVariableString(qryType);
- }
- };
-
- return (
-
- The Prometheus data source plugin provides the following query types for template variables.
- }
- >
-
-
- {qryType === QueryType.LabelValues && (
- <>
-
- Returns a list of label values for the label name in all metrics unless the metric is specified.
-
- }
- >
-
-
- Optional: returns a list of label values for the label name in the specified metric.}
- >
-
-
- >
- )}
- {qryType === QueryType.MetricNames && (
- <>
- Returns a list of metrics matching the specified metric regex.}
- >
-
-
- >
- )}
- {qryType === QueryType.VarQueryResult && (
- <>
-
- Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e.
- sum(go_goroutines).
-
- }
- >
-
-
- >
- )}
- {qryType === QueryType.SeriesQuery && (
- <>
-
- Enter enter a metric with labels, only a metric or only labels, i.e.
- go_goroutines{instance="localhost:9090"}, go_goroutines, or
- {instance="localhost:9090"}. Returns a list of time series associated with the
- entered data.
-
- }
- >
-
-
- >
- )}
-
- );
-};
diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts
index 041372af5b3..8e8cce4aed7 100644
--- a/public/app/plugins/datasource/prometheus/datasource.test.ts
+++ b/public/app/plugins/datasource/prometheus/datasource.test.ts
@@ -153,7 +153,7 @@ describe('PrometheusDatasource', () => {
).rejects.toMatchObject({
message: expect.stringMatching('Browser access'),
});
- await expect(directDs.getLabelNames()).rejects.toMatchObject({
+ await expect(directDs.getTagKeys()).rejects.toMatchObject({
message: expect.stringMatching('Browser access'),
});
await expect(directDs.getTagValues()).rejects.toMatchObject({
diff --git a/public/app/plugins/datasource/prometheus/datasource.tsx b/public/app/plugins/datasource/prometheus/datasource.tsx
index 356a6b28364..ad84f5af598 100644
--- a/public/app/plugins/datasource/prometheus/datasource.tsx
+++ b/public/app/plugins/datasource/prometheus/datasource.tsx
@@ -286,7 +286,7 @@ export class PrometheusDatasource
hideFromInspector: true,
...options,
})
- ); // toPromise until we change getTagValues, getLabelNames to Observable
+ ); // toPromise until we change getTagValues, getTagKeys to Observable
}
interpolateQueryExpr(value: string | string[] = [], variable: any) {
@@ -908,10 +908,7 @@ export class PrometheusDatasource
);
}
- // this is used to get label keys, a.k.a label names
- // it is used in metric_find_query.ts
- // and in Tempo here grafana/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
- async getLabelNames(options?: any) {
+ async getTagKeys(options?: any) {
if (options?.series) {
// Get tags for the provided series only
const seriesLabels: Array> = await Promise.all(
diff --git a/public/app/plugins/datasource/prometheus/metric_find_query.ts b/public/app/plugins/datasource/prometheus/metric_find_query.ts
index 2c6bea204c8..f3f678d1d2a 100644
--- a/public/app/plugins/datasource/prometheus/metric_find_query.ts
+++ b/public/app/plugins/datasource/prometheus/metric_find_query.ts
@@ -24,7 +24,7 @@ export default class PrometheusMetricFindQuery {
const queryResultRegex = /^query_result\((.+)\)\s*$/;
const labelNamesQuery = this.query.match(labelNamesRegex);
if (labelNamesQuery) {
- return this.datasource.getLabelNames();
+ return this.labelNamesQuery();
}
const labelValuesQuery = this.query.match(labelValuesRegex);
@@ -47,12 +47,24 @@ export default class PrometheusMetricFindQuery {
}
// if query contains full metric name, return metric name and label list
- const expressions = ['label_values()', 'metrics()', 'query_result()'];
- if (!expressions.includes(this.query)) {
- return this.metricNameAndLabelsQuery(this.query);
- }
+ return this.metricNameAndLabelsQuery(this.query);
+ }
- return Promise.resolve([]);
+ labelNamesQuery() {
+ const start = this.datasource.getPrometheusTime(this.range.from, false);
+ const end = this.datasource.getPrometheusTime(this.range.to, true);
+ const params = {
+ start: start.toString(),
+ end: end.toString(),
+ };
+
+ const url = `/api/v1/labels`;
+
+ return this.datasource.metadataRequest(url, params).then((result: any) => {
+ return _map(result.data.data, (value) => {
+ return { text: value };
+ });
+ });
}
labelValuesQuery(label: string, metric?: string) {
diff --git a/public/app/plugins/datasource/prometheus/migrations/variableMigration.ts b/public/app/plugins/datasource/prometheus/migrations/variableMigration.ts
deleted file mode 100644
index 17c44fb850a..00000000000
--- a/public/app/plugins/datasource/prometheus/migrations/variableMigration.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { PromVariableQuery, PromVariableQueryType as QueryType } from '../types';
-
-const labelNamesRegex = /^label_names\(\)\s*$/;
-const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
-const metricNamesRegex = /^metrics\((.+)\)\s*$/;
-const queryResultRegex = /^query_result\((.+)\)\s*$/;
-
-export function migrateVariableQueryToEditor(rawQuery: string | PromVariableQuery): PromVariableQuery {
- // If not string, we assume PromVariableQuery
- if (typeof rawQuery !== 'string') {
- return rawQuery;
- }
-
- const queryBase = {
- refId: 'PrometheusDatasource-VariableQuery',
- qryType: QueryType.LabelNames,
- };
-
- const labelNames = rawQuery.match(labelNamesRegex);
- if (labelNames) {
- return {
- ...queryBase,
- qryType: QueryType.LabelNames,
- };
- }
-
- const labelValues = rawQuery.match(labelValuesRegex);
-
- if (labelValues) {
- const label = labelValues[2];
- const metric = labelValues[1];
- if (metric) {
- return {
- ...queryBase,
- qryType: QueryType.LabelValues,
- label,
- metric,
- };
- } else {
- return {
- ...queryBase,
- qryType: QueryType.LabelValues,
- label,
- };
- }
- }
-
- const metricNames = rawQuery.match(metricNamesRegex);
- if (metricNames) {
- return {
- ...queryBase,
- qryType: QueryType.MetricNames,
- metric: metricNames[1],
- };
- }
-
- const queryResult = rawQuery.match(queryResultRegex);
- if (queryResult) {
- return {
- ...queryBase,
- qryType: QueryType.VarQueryResult,
- varQuery: queryResult[1],
- };
- }
-
- // seriesQuery does not have a function and no regex above
- if (!labelNames && !labelValues && !metricNames && !queryResult) {
- return {
- ...queryBase,
- qryType: QueryType.SeriesQuery,
- seriesQuery: rawQuery,
- };
- }
-
- return queryBase;
-}
-
-// migrate it back to a string with the correct varialbes in place
-export function migrateVariableEditorBackToVariableSupport(QueryVariable: PromVariableQuery): string {
- switch (QueryVariable.qryType) {
- case QueryType.LabelNames:
- return 'label_names()';
- case QueryType.LabelValues:
- if (QueryVariable.metric) {
- return `label_values(${QueryVariable.metric},${QueryVariable.label})`;
- } else {
- return `label_values(${QueryVariable.label})`;
- }
- case QueryType.MetricNames:
- return `metrics(${QueryVariable.metric})`;
- case QueryType.VarQueryResult:
- const varQuery = removeLineBreaks(QueryVariable.varQuery);
- return `query_result(${varQuery})`;
- case QueryType.SeriesQuery:
- return '' + QueryVariable.seriesQuery;
- }
-
- return '';
-}
-
-// allow line breaks in query result textarea
-function removeLineBreaks(input?: string) {
- return input ? input.replace(/[\r\n]+/gm, '') : '';
-}
diff --git a/public/app/plugins/datasource/prometheus/types.ts b/public/app/plugins/datasource/prometheus/types.ts
index 0119e30020a..62aec75433b 100644
--- a/public/app/plugins/datasource/prometheus/types.ts
+++ b/public/app/plugins/datasource/prometheus/types.ts
@@ -22,7 +22,6 @@ export interface PromQuery extends DataQuery {
showingTable?: boolean;
/** Code, Builder or Explain */
editorMode?: QueryEditorMode;
- query?: string;
}
export interface PromOptions extends DataSourceJsonData {
@@ -166,21 +165,3 @@ export enum LegendFormatMode {
Verbose = '__verbose',
Custom = '__custom',
}
-
-export enum PromVariableQueryType {
- LabelNames,
- LabelValues,
- MetricNames,
- VarQueryResult,
- SeriesQuery,
-}
-
-export interface PromVariableQuery extends DataQuery {
- query?: string;
- expr?: string;
- qryType?: PromVariableQueryType;
- label?: string;
- metric?: string;
- varQuery?: string;
- seriesQuery?: string;
-}
diff --git a/public/app/plugins/datasource/prometheus/variables.ts b/public/app/plugins/datasource/prometheus/variables.ts
index 5098147016d..ac92f27dd0e 100644
--- a/public/app/plugins/datasource/prometheus/variables.ts
+++ b/public/app/plugins/datasource/prometheus/variables.ts
@@ -1,17 +1,22 @@
import { from, Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
-import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, rangeUtil } from '@grafana/data';
+import {
+ DataQueryRequest,
+ DataQueryResponse,
+ rangeUtil,
+ StandardVariableQuery,
+ StandardVariableSupport,
+} from '@grafana/data';
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { getTimeSrv, TimeSrv } from '../../../features/dashboard/services/TimeSrv';
-import { PromVariableQueryEditor } from './components/VariableQueryEditor';
import { PrometheusDatasource } from './datasource';
import PrometheusMetricFindQuery from './metric_find_query';
import { PromQuery } from './types';
-export class PrometheusVariableSupport extends CustomVariableSupport {
+export class PrometheusVariableSupport extends StandardVariableSupport {
constructor(
private readonly datasource: PrometheusDatasource,
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
@@ -21,10 +26,8 @@ export class PrometheusVariableSupport extends CustomVariableSupport): Observable {
- const query = request.targets[0].query;
+ const query = request.targets[0].expr;
if (!query) {
return of({ data: [] });
}
@@ -45,4 +48,11 @@ export class PrometheusVariableSupport extends CustomVariableSupport ({ data: results })));
}
+
+ toDataQuery(query: StandardVariableQuery): PromQuery {
+ return {
+ refId: 'PrometheusDatasource-VariableQuery',
+ expr: query.query,
+ };
+ }
}
diff --git a/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx b/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
index 1c5785dec69..edaa5ea1d8c 100644
--- a/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
+++ b/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx
@@ -29,7 +29,7 @@ export function ServiceGraphSection({
const [hasKeys, setHasKeys] = useState(undefined);
useEffect(() => {
async function fn(ds: PrometheusDatasource) {
- const keys = await ds.getLabelNames({
+ const keys = await ds.getTagKeys({
series: [
'traces_service_graph_request_server_seconds_sum',
'traces_service_graph_request_total',