2021-04-21 02:38:00 -05:00
|
|
|
import { escapeRegExp } from 'lodash';
|
2021-06-21 11:50:42 -05:00
|
|
|
import { PIPE_PARSERS } from './syntax';
|
2022-02-03 03:25:37 -06:00
|
|
|
import { LokiQuery, LokiQueryType } from './types';
|
2019-05-13 02:58:26 -05:00
|
|
|
|
2020-07-06 14:16:27 -05:00
|
|
|
export function formatQuery(selector: string | undefined): string {
|
2020-05-06 04:21:25 -05:00
|
|
|
return `${selector || ''}`.trim();
|
2018-11-28 03:46:35 -06:00
|
|
|
}
|
2019-05-13 02:58:26 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns search terms from a LogQL query.
|
|
|
|
* E.g., `{} |= foo |=bar != baz` returns `['foo', 'bar']`.
|
|
|
|
*/
|
|
|
|
export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
|
|
|
let expression = input;
|
|
|
|
const results = [];
|
2020-07-06 14:16:27 -05:00
|
|
|
|
2019-05-13 02:58:26 -05:00
|
|
|
// Consume filter expression from left to right
|
|
|
|
while (expression) {
|
|
|
|
const filterStart = expression.search(/\|=|\|~|!=|!~/);
|
|
|
|
// Nothing more to search
|
|
|
|
if (filterStart === -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Drop terms for negative filters
|
2020-01-16 10:09:49 -06:00
|
|
|
const filterOperator = expression.substr(filterStart, 2);
|
2019-05-13 02:58:26 -05:00
|
|
|
const skip = expression.substr(filterStart).search(/!=|!~/) === 0;
|
|
|
|
expression = expression.substr(filterStart + 2);
|
|
|
|
if (skip) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Check if there is more chained
|
|
|
|
const filterEnd = expression.search(/\|=|\|~|!=|!~/);
|
|
|
|
let filterTerm;
|
|
|
|
if (filterEnd === -1) {
|
|
|
|
filterTerm = expression.trim();
|
|
|
|
} else {
|
2019-07-02 03:06:04 -05:00
|
|
|
filterTerm = expression.substr(0, filterEnd).trim();
|
2019-05-13 02:58:26 -05:00
|
|
|
expression = expression.substr(filterEnd);
|
|
|
|
}
|
|
|
|
|
2021-06-24 05:55:25 -05:00
|
|
|
const quotedTerm = filterTerm.match(/"(.*?)"/);
|
|
|
|
const backtickedTerm = filterTerm.match(/`(.*?)`/);
|
|
|
|
const term = quotedTerm || backtickedTerm;
|
2019-07-02 03:06:04 -05:00
|
|
|
|
2021-06-24 05:55:25 -05:00
|
|
|
if (term) {
|
|
|
|
const unwrappedFilterTerm = term[1];
|
2020-01-16 10:09:49 -06:00
|
|
|
const regexOperator = filterOperator === '|~';
|
2021-06-24 05:55:25 -05:00
|
|
|
|
|
|
|
// Only filter expressions with |~ operator are treated as regular expressions
|
|
|
|
if (regexOperator) {
|
|
|
|
// When using backticks, Loki doesn't require to escape special characters and we can just push regular expression to highlights array
|
|
|
|
// When using quotes, we have extra backslash escaping and we need to replace \\ with \
|
|
|
|
results.push(backtickedTerm ? unwrappedFilterTerm : unwrappedFilterTerm.replace(/\\\\/g, '\\'));
|
|
|
|
} else {
|
|
|
|
// We need to escape this string so it is not matched as regular expression
|
|
|
|
results.push(escapeRegExp(unwrappedFilterTerm));
|
|
|
|
}
|
2019-07-02 03:06:04 -05:00
|
|
|
} else {
|
2021-06-24 05:55:25 -05:00
|
|
|
return results;
|
2019-07-02 03:06:04 -05:00
|
|
|
}
|
2019-05-13 02:58:26 -05:00
|
|
|
}
|
2020-07-06 14:16:27 -05:00
|
|
|
|
2019-05-13 02:58:26 -05:00
|
|
|
return results;
|
|
|
|
}
|
2021-06-21 11:50:42 -05:00
|
|
|
|
|
|
|
export function queryHasPipeParser(expr: string): boolean {
|
|
|
|
const parsers = PIPE_PARSERS.map((parser) => `${parser.label}`).join('|');
|
|
|
|
const regexp = new RegExp(`\\\|\\\s?(${parsers})`);
|
|
|
|
return regexp.test(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function addParsedLabelToQuery(expr: string, key: string, value: string | number, operator: string) {
|
|
|
|
return expr + ` | ${key}${operator}"${value.toString()}"`;
|
|
|
|
}
|
2022-02-03 03:25:37 -06:00
|
|
|
|
|
|
|
// we are migrating from `.instant` and `.range` to `.queryType`
|
|
|
|
// this function returns a new query object that:
|
|
|
|
// - has `.queryType`
|
|
|
|
// - does not have `.instant`
|
|
|
|
// - does not have `.range`
|
|
|
|
export function getNormalizedLokiQuery(query: LokiQuery): LokiQuery {
|
|
|
|
// if queryType exists, it is respected
|
|
|
|
if (query.queryType !== undefined) {
|
|
|
|
const { instant, range, ...rest } = query;
|
|
|
|
return rest;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no queryType, and instant===true, it's instant
|
|
|
|
if (query.instant === true) {
|
|
|
|
const { instant, range, ...rest } = query;
|
|
|
|
return { ...rest, queryType: LokiQueryType.Instant };
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise it is range
|
|
|
|
const { instant, range, ...rest } = query;
|
|
|
|
return { ...rest, queryType: LokiQueryType.Range };
|
|
|
|
}
|