Commit ddefcb26 by Hugo Häggmark Committed by GitHub

Fix: Fetch histogram series from other api route (#16768)

Closes: #15992
parent f7c8d90d
......@@ -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);
}
}
};
}
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 '';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment