The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/containers/Explore/utils/prometheus.ts

91 lines
3.1 KiB

export const RATE_RANGES = ['1m', '5m', '10m', '30m', '1h'];
export function processLabels(labels, withName = false) {
const values = {};
labels.forEach(l => {
const { __name__, ...rest } = l;
if (withName) {
values['__name__'] = values['__name__'] || [];
if (values['__name__'].indexOf(__name__) === -1) {
values['__name__'].push(__name__);
}
}
Object.keys(rest).forEach(key => {
if (!values[key]) {
values[key] = [];
}
if (values[key].indexOf(rest[key]) === -1) {
values[key].push(rest[key]);
}
});
});
return { values, keys: Object.keys(values) };
}
// Strip syntax chars
export const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
// const cleanSelectorRegexp = /\{(\w+="[^"\n]*?")(,\w+="[^"\n]*?")*\}/;
const selectorRegexp = /\{[^}]*?\}/;
const labelRegexp = /\b\w+="[^"\n]*?"/g;
export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any[]; selector: string } {
if (!query.match(selectorRegexp)) {
// Special matcher for metrics
if (query.match(/^\w+$/)) {
return {
selector: `{__name__="${query}"}`,
labelKeys: ['__name__'],
};
}
throw new Error('Query must contain a selector: ' + query);
}
// Check if inside a selector
const prefix = query.slice(0, cursorOffset);
const prefixOpen = prefix.lastIndexOf('{');
const prefixClose = prefix.lastIndexOf('}');
if (prefixOpen === -1) {
throw new Error('Not inside selector, missing open brace: ' + prefix);
}
if (prefixClose > -1 && prefixClose > prefixOpen) {
throw new Error('Not inside selector, previous selector already closed: ' + prefix);
}
const suffix = query.slice(cursorOffset);
const suffixCloseIndex = suffix.indexOf('}');
const suffixClose = suffixCloseIndex + cursorOffset;
const suffixOpenIndex = suffix.indexOf('{');
const suffixOpen = suffixOpenIndex + cursorOffset;
if (suffixClose === -1) {
throw new Error('Not inside selector, missing closing brace in suffix: ' + suffix);
}
if (suffixOpenIndex > -1 && suffixOpen < suffixClose) {
throw new Error('Not inside selector, next selector opens before this one closed: ' + suffix);
}
// Extract clean labels to form clean selector, incomplete labels are dropped
const selector = query.slice(prefixOpen, suffixClose);
const labels = {};
selector.replace(labelRegexp, match => {
const delimiterIndex = match.indexOf('=');
const key = match.slice(0, delimiterIndex);
const value = match.slice(delimiterIndex + 1, match.length);
labels[key] = value;
return '';
});
// Add metric if there is one before the selector
const metricPrefix = query.slice(0, prefixOpen);
const metricMatch = metricPrefix.match(/\w+$/);
if (metricMatch) {
labels['__name__'] = `"${metricMatch[0]}"`;
}
// Build sorted selector
const labelKeys = Object.keys(labels).sort();
const cleanSelector = labelKeys.map(key => `${key}=${labels[key]}`).join(',');
const selectorString = ['{', cleanSelector, '}'].join('');
return { labelKeys, selector: selectorString };
}