mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Fix: Fetch histogram series from other api route (#16768)
Closes: #15992
This commit is contained in:
@@ -9,12 +9,11 @@ import {
|
||||
TypeaheadOutput,
|
||||
} from 'app/types/explore';
|
||||
|
||||
import { parseSelector, processLabels } from './language_utils';
|
||||
import { parseSelector, processLabels, processHistogramLabels } from './language_utils';
|
||||
import PromqlSyntax, { FUNCTIONS, RATE_RANGES } from './promql';
|
||||
|
||||
const DEFAULT_KEYS = ['job', 'instance'];
|
||||
const EMPTY_SELECTOR = '{}';
|
||||
const HISTOGRAM_SELECTOR = '{le!=""}'; // Returns all timeseries for histograms
|
||||
const HISTORY_ITEM_COUNT = 5;
|
||||
const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h
|
||||
|
||||
@@ -66,8 +65,17 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
return PromqlSyntax;
|
||||
}
|
||||
|
||||
request = (url: string) => {
|
||||
return this.datasource.metadataRequest(url);
|
||||
request = async (url: string) => {
|
||||
try {
|
||||
const res = await this.datasource.metadataRequest(url);
|
||||
const body = await (res.data || res.json());
|
||||
|
||||
return body.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
start = () => {
|
||||
@@ -78,7 +86,22 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
};
|
||||
|
||||
fetchMetrics = async () => {
|
||||
return this.fetchMetricNames().then(() => [this.fetchHistogramMetrics()]);
|
||||
this.metrics = await this.fetchMetricNames();
|
||||
this.processHistogramMetrics(this.metrics);
|
||||
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
|
||||
fetchMetricNames = async (): Promise<string[]> => {
|
||||
return this.request('/api/v1/label/__name__/values');
|
||||
};
|
||||
|
||||
processHistogramMetrics = (data: string[]) => {
|
||||
const { values } = processHistogramLabels(data);
|
||||
|
||||
if (values && values['__name__']) {
|
||||
this.histogramMetrics = values['__name__'].slice().sort();
|
||||
}
|
||||
};
|
||||
|
||||
// Keep this DOM-free for testing
|
||||
@@ -293,60 +316,28 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
return { context, refresher, suggestions };
|
||||
}
|
||||
|
||||
async fetchMetricNames() {
|
||||
const url = '/api/v1/label/__name__/values';
|
||||
fetchLabelValues = async (key: string) => {
|
||||
try {
|
||||
const res = await this.request(url);
|
||||
const body = await (res.data || res.json());
|
||||
this.metrics = body.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchHistogramMetrics() {
|
||||
await this.fetchSeriesLabels(HISTOGRAM_SELECTOR, true);
|
||||
const histogramSeries = this.labelValues[HISTOGRAM_SELECTOR];
|
||||
if (histogramSeries && histogramSeries['__name__']) {
|
||||
this.histogramMetrics = histogramSeries['__name__'].slice().sort();
|
||||
}
|
||||
}
|
||||
|
||||
async fetchLabelValues(key: string) {
|
||||
const url = `/api/v1/label/${key}/values`;
|
||||
try {
|
||||
const res = await this.request(url);
|
||||
const body = await (res.data || res.json());
|
||||
const exisingValues = this.labelValues[EMPTY_SELECTOR];
|
||||
const data = await this.request(`/api/v1/label/${key}/values`);
|
||||
const existingValues = this.labelValues[EMPTY_SELECTOR];
|
||||
const values = {
|
||||
...exisingValues,
|
||||
[key]: body.data,
|
||||
};
|
||||
this.labelValues = {
|
||||
...this.labelValues,
|
||||
[EMPTY_SELECTOR]: values,
|
||||
...existingValues,
|
||||
[key]: data,
|
||||
};
|
||||
this.labelValues[EMPTY_SELECTOR] = values;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async fetchSeriesLabels(name: string, withName?: boolean) {
|
||||
const url = `/api/v1/series?match[]=${name}`;
|
||||
fetchSeriesLabels = async (name: string, withName?: boolean) => {
|
||||
try {
|
||||
const res = await this.request(url);
|
||||
const body = await (res.data || res.json());
|
||||
const { keys, values } = processLabels(body.data, withName);
|
||||
this.labelKeys = {
|
||||
...this.labelKeys,
|
||||
[name]: keys,
|
||||
};
|
||||
this.labelValues = {
|
||||
...this.labelValues,
|
||||
[name]: values,
|
||||
};
|
||||
const data = await this.request(`/api/v1/series?match[]=${name}`);
|
||||
const { keys, values } = processLabels(data, withName);
|
||||
this.labelKeys[name] = keys;
|
||||
this.labelValues[name] = values;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
export const RATE_RANGES = ['1m', '5m', '10m', '30m', '1h'];
|
||||
|
||||
export function processLabels(labels, withName = false) {
|
||||
const values = {};
|
||||
labels.forEach(l => {
|
||||
export const processHistogramLabels = (labels: string[]) => {
|
||||
const result = [];
|
||||
const regexp = new RegExp('_bucket($|:)');
|
||||
for (let index = 0; index < labels.length; index++) {
|
||||
const label = labels[index];
|
||||
const isHistogramValue = regexp.test(label);
|
||||
if (isHistogramValue) {
|
||||
if (result.indexOf(label) === -1) {
|
||||
result.push(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { values: { __name__: result } };
|
||||
};
|
||||
|
||||
export function processLabels(labels: any, withName = false) {
|
||||
const values: { [key: string]: string[] } = {};
|
||||
labels.forEach((l: any) => {
|
||||
const { __name__, ...rest } = l;
|
||||
if (withName) {
|
||||
values['__name__'] = values['__name__'] || [];
|
||||
@@ -62,7 +78,7 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
|
||||
|
||||
// Extract clean labels to form clean selector, incomplete labels are dropped
|
||||
const selector = query.slice(prefixOpen, suffixClose);
|
||||
const labels = {};
|
||||
const labels: { [key: string]: { value: string; operator: string } } = {};
|
||||
selector.replace(labelRegexp, (_, key, operator, value) => {
|
||||
labels[key] = { value, operator };
|
||||
return '';
|
||||
|
||||
Reference in New Issue
Block a user