mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Revert "Prometheus Datasource: Improve Prom query variable editor" (#63278)
Revert "Prometheus Datasource: Improve Prom query variable editor (#58292)"
This reverts commit eedcd7d5b1
.
This commit is contained in:
parent
7295573e2e
commit
879f980084
@ -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.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
[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.", "3"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
|
[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": [
|
"public/app/plugins/datasource/prometheus/query_hints.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
|
@ -23,17 +23,17 @@ For an introduction to templating and template variables, refer to the [Templati
|
|||||||
|
|
||||||
## Use query variables
|
## 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 |
|
| Name | Description | Used API endpoints |
|
||||||
| -------------- | ------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
| ----------------------------- | ----------------------------------------------------------------------- | --------------------------------- |
|
||||||
| `Label names` | none | Returns a list of all label names. | /api/v1/labels |
|
| `label_names()` | Returns a list of 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 |
|
| `label_values(label)` | Returns a list of label values for the `label` in every metric. | /api/v1/label/`label`/values |
|
||||||
| `Metrics` | `metric` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
|
| `label_values(metric, label)` | Returns a list of label values for the `label` in the specified metric. | /api/v1/series |
|
||||||
| `Query result` | `query` | Returns a list of Prometheus query result for the `query`. | /api/v1/query |
|
| `metrics(metric)` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
|
||||||
| `Series query` | `metric`, `label` or both | Returns a list of time series associated with the entered data. | /api/v1/series |
|
| `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).
|
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).
|
||||||
|
|
||||||
|
@ -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(<PromVariableQueryEditor {...props} />);
|
|
||||||
|
|
||||||
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(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
|
||||||
|
|
||||||
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(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
|
||||||
|
|
||||||
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(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
|
||||||
|
|
||||||
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(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
|
||||||
|
|
||||||
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(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
|
||||||
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -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<PrometheusDatasource, PromQuery, PromOptions, PromVariableQuery>;
|
|
||||||
|
|
||||||
const refId = 'PrometheusVariableQueryEditor-VariableQuery';
|
|
||||||
|
|
||||||
export const PromVariableQueryEditor: FC<Props> = ({ onChange, query, datasource }) => {
|
|
||||||
// to select the query type, i.e. label_names, label_values, etc.
|
|
||||||
const [qryType, setQryType] = useState<number | undefined>(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<Array<SelectableValue<string>>>([]);
|
|
||||||
|
|
||||||
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<QueryType>) => {
|
|
||||||
setQryType(newType.value);
|
|
||||||
if (newType.value === QueryType.LabelNames) {
|
|
||||||
onChangeWithVariableString(newType.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLabelChange = (newLabel: SelectableValue<string>) => {
|
|
||||||
setLabel(newLabel.value ?? '');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMetricChange = (e: FormEvent<HTMLInputElement>) => {
|
|
||||||
setMetric(e.currentTarget.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onVarQueryChange = (e: FormEvent<HTMLTextAreaElement>) => {
|
|
||||||
setVarQuery(e.currentTarget.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSeriesQueryChange = (e: FormEvent<HTMLInputElement>) => {
|
|
||||||
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 (
|
|
||||||
<InlineFieldRow>
|
|
||||||
<InlineField
|
|
||||||
label="Query Type"
|
|
||||||
labelWidth={20}
|
|
||||||
tooltip={
|
|
||||||
<div>The Prometheus data source plugin provides the following query types for template variables.</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
placeholder="Select query type"
|
|
||||||
aria-label="Query type"
|
|
||||||
onChange={onQueryTypeChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={qryType}
|
|
||||||
options={variableOptions}
|
|
||||||
width={25}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
{qryType === QueryType.LabelValues && (
|
|
||||||
<>
|
|
||||||
<InlineField
|
|
||||||
label="Label"
|
|
||||||
labelWidth={20}
|
|
||||||
required
|
|
||||||
tooltip={
|
|
||||||
<div>
|
|
||||||
Returns a list of label values for the label name in all metrics unless the metric is specified.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
aria-label="label-select"
|
|
||||||
onChange={onLabelChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={label}
|
|
||||||
options={labelOptions}
|
|
||||||
width={25}
|
|
||||||
allowCustomValue
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
<InlineField
|
|
||||||
label="Metric"
|
|
||||||
labelWidth={20}
|
|
||||||
tooltip={<div>Optional: returns a list of label values for the label name in the specified metric.</div>}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
aria-label="Metric selector"
|
|
||||||
placeholder="Optional metric selector"
|
|
||||||
value={metric}
|
|
||||||
onChange={onMetricChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
width={25}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{qryType === QueryType.MetricNames && (
|
|
||||||
<>
|
|
||||||
<InlineField
|
|
||||||
label="Metric Regex"
|
|
||||||
labelWidth={20}
|
|
||||||
tooltip={<div>Returns a list of metrics matching the specified metric regex.</div>}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
aria-label="Metric selector"
|
|
||||||
placeholder="Metric Regex"
|
|
||||||
value={metric}
|
|
||||||
onChange={onMetricChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
width={25}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{qryType === QueryType.VarQueryResult && (
|
|
||||||
<>
|
|
||||||
<InlineField
|
|
||||||
label="Query"
|
|
||||||
labelWidth={20}
|
|
||||||
tooltip={
|
|
||||||
<div>
|
|
||||||
Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e.
|
|
||||||
sum(go_goroutines).
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
type="text"
|
|
||||||
aria-label="Prometheus Query"
|
|
||||||
placeholder="Prometheus Query"
|
|
||||||
value={varQuery}
|
|
||||||
onChange={onVarQueryChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
cols={100}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{qryType === QueryType.SeriesQuery && (
|
|
||||||
<>
|
|
||||||
<InlineField
|
|
||||||
label="Series Query"
|
|
||||||
labelWidth={20}
|
|
||||||
tooltip={
|
|
||||||
<div>
|
|
||||||
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.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
aria-label="Series Query"
|
|
||||||
placeholder="Series Query"
|
|
||||||
value={seriesQuery}
|
|
||||||
onChange={onSeriesQueryChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
width={100}
|
|
||||||
/>
|
|
||||||
</InlineField>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</InlineFieldRow>
|
|
||||||
);
|
|
||||||
};
|
|
@ -153,7 +153,7 @@ describe('PrometheusDatasource', () => {
|
|||||||
).rejects.toMatchObject({
|
).rejects.toMatchObject({
|
||||||
message: expect.stringMatching('Browser access'),
|
message: expect.stringMatching('Browser access'),
|
||||||
});
|
});
|
||||||
await expect(directDs.getLabelNames()).rejects.toMatchObject({
|
await expect(directDs.getTagKeys()).rejects.toMatchObject({
|
||||||
message: expect.stringMatching('Browser access'),
|
message: expect.stringMatching('Browser access'),
|
||||||
});
|
});
|
||||||
await expect(directDs.getTagValues()).rejects.toMatchObject({
|
await expect(directDs.getTagValues()).rejects.toMatchObject({
|
||||||
|
@ -286,7 +286,7 @@ export class PrometheusDatasource
|
|||||||
hideFromInspector: true,
|
hideFromInspector: true,
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
); // toPromise until we change getTagValues, getLabelNames to Observable
|
); // toPromise until we change getTagValues, getTagKeys to Observable
|
||||||
}
|
}
|
||||||
|
|
||||||
interpolateQueryExpr(value: string | string[] = [], variable: any) {
|
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
|
async getTagKeys(options?: any) {
|
||||||
// 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) {
|
|
||||||
if (options?.series) {
|
if (options?.series) {
|
||||||
// Get tags for the provided series only
|
// Get tags for the provided series only
|
||||||
const seriesLabels: Array<Record<string, string[]>> = await Promise.all(
|
const seriesLabels: Array<Record<string, string[]>> = await Promise.all(
|
||||||
|
@ -24,7 +24,7 @@ export default class PrometheusMetricFindQuery {
|
|||||||
const queryResultRegex = /^query_result\((.+)\)\s*$/;
|
const queryResultRegex = /^query_result\((.+)\)\s*$/;
|
||||||
const labelNamesQuery = this.query.match(labelNamesRegex);
|
const labelNamesQuery = this.query.match(labelNamesRegex);
|
||||||
if (labelNamesQuery) {
|
if (labelNamesQuery) {
|
||||||
return this.datasource.getLabelNames();
|
return this.labelNamesQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelValuesQuery = this.query.match(labelValuesRegex);
|
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
|
// if query contains full metric name, return metric name and label list
|
||||||
const expressions = ['label_values()', 'metrics()', 'query_result()'];
|
return this.metricNameAndLabelsQuery(this.query);
|
||||||
if (!expressions.includes(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) {
|
labelValuesQuery(label: string, metric?: string) {
|
||||||
|
@ -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, '') : '';
|
|
||||||
}
|
|
@ -22,7 +22,6 @@ export interface PromQuery extends DataQuery {
|
|||||||
showingTable?: boolean;
|
showingTable?: boolean;
|
||||||
/** Code, Builder or Explain */
|
/** Code, Builder or Explain */
|
||||||
editorMode?: QueryEditorMode;
|
editorMode?: QueryEditorMode;
|
||||||
query?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PromOptions extends DataSourceJsonData {
|
export interface PromOptions extends DataSourceJsonData {
|
||||||
@ -166,21 +165,3 @@ export enum LegendFormatMode {
|
|||||||
Verbose = '__verbose',
|
Verbose = '__verbose',
|
||||||
Custom = '__custom',
|
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;
|
|
||||||
}
|
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
import { from, Observable, of } from 'rxjs';
|
import { from, Observable, of } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
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 { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { getTimeSrv, TimeSrv } from '../../../features/dashboard/services/TimeSrv';
|
import { getTimeSrv, TimeSrv } from '../../../features/dashboard/services/TimeSrv';
|
||||||
|
|
||||||
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';
|
||||||
import { PromQuery } from './types';
|
import { PromQuery } from './types';
|
||||||
|
|
||||||
export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusDatasource> {
|
export class PrometheusVariableSupport extends StandardVariableSupport<PrometheusDatasource> {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly datasource: PrometheusDatasource,
|
private readonly datasource: PrometheusDatasource,
|
||||||
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
||||||
@ -21,10 +26,8 @@ export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusD
|
|||||||
this.query = this.query.bind(this);
|
this.query = this.query.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor = PromVariableQueryEditor;
|
|
||||||
|
|
||||||
query(request: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
|
query(request: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
|
||||||
const query = request.targets[0].query;
|
const query = request.targets[0].expr;
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return of({ data: [] });
|
return of({ data: [] });
|
||||||
}
|
}
|
||||||
@ -45,4 +48,11 @@ export class PrometheusVariableSupport extends CustomVariableSupport<PrometheusD
|
|||||||
|
|
||||||
return metricFindStream.pipe(map((results) => ({ data: results })));
|
return metricFindStream.pipe(map((results) => ({ data: results })));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toDataQuery(query: StandardVariableQuery): PromQuery {
|
||||||
|
return {
|
||||||
|
refId: 'PrometheusDatasource-VariableQuery',
|
||||||
|
expr: query.query,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export function ServiceGraphSection({
|
|||||||
const [hasKeys, setHasKeys] = useState<boolean | undefined>(undefined);
|
const [hasKeys, setHasKeys] = useState<boolean | undefined>(undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fn(ds: PrometheusDatasource) {
|
async function fn(ds: PrometheusDatasource) {
|
||||||
const keys = await ds.getLabelNames({
|
const keys = await ds.getTagKeys({
|
||||||
series: [
|
series: [
|
||||||
'traces_service_graph_request_server_seconds_sum',
|
'traces_service_graph_request_server_seconds_sum',
|
||||||
'traces_service_graph_request_total',
|
'traces_service_graph_request_total',
|
||||||
|
Loading…
Reference in New Issue
Block a user