Commit 4f5ce48b by Ivana Huckova Committed by GitHub

Loki: Fix label matcher for log metrics queries (#24238)

* Fix switched filter buttons

* Fix filter for and filter out for metrics queries

* Add test coverage
parent 9420873e
......@@ -101,10 +101,10 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
{isLabel && (
<>
<td className={style.logsDetailsIcon}>
<IconButton name="search-minus" title="Filter for value" onClick={this.filterLabel} />
<IconButton name="search-plus" title="Filter for value" onClick={this.filterLabel} />
</td>
<td className={style.logsDetailsIcon}>
<IconButton name="search-plus" title="Filter out value" onClick={this.filterOutLabel} />
<IconButton name="search-minus" title="Filter out value" onClick={this.filterOutLabel} />
</td>
</>
)}
......
......@@ -6,12 +6,12 @@ import { map, filter, catchError, switchMap } from 'rxjs/operators';
// Services & Utils
import { DataFrame, dateMath, FieldCache } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { addLabelToSelector, keepSelectorFilters } from 'app/plugins/datasource/prometheus/add_label_to_query';
import { addLabelToQuery } from 'app/plugins/datasource/prometheus/add_label_to_query';
import { DatasourceRequestOptions } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { safeStringifyValue, convertToWebSocketUrl } from 'app/core/utils/explore';
import { lokiResultsToTableModel, processRangeQueryResponse, lokiStreamResultToDataFrame } from './result_transformer';
import { formatQuery, parseQuery, getHighlighterExpressionsFromQuery } from './query_utils';
import { parseQuery, getHighlighterExpressionsFromQuery } from './query_utils';
// Types
import {
......@@ -344,27 +344,20 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
}
modifyQuery(query: LokiQuery, action: any): LokiQuery {
const parsed = parseQuery(query.expr || '');
let { query: selector } = parsed;
let selectorLabels, selectorFilters;
let expression = query.expr ?? '';
switch (action.type) {
case 'ADD_FILTER': {
selectorLabels = addLabelToSelector(selector, action.key, action.value);
selectorFilters = keepSelectorFilters(selector);
selector = `${selectorLabels} ${selectorFilters}`.trim();
expression = addLabelToQuery(expression, action.key, action.value);
break;
}
case 'ADD_FILTER_OUT': {
selectorLabels = addLabelToSelector(selector, action.key, action.value, '!=');
selectorFilters = keepSelectorFilters(selector);
selector = `${selectorLabels} ${selectorFilters}`.trim();
expression = addLabelToQuery(expression, action.key, action.value, '!=');
break;
}
default:
break;
}
const expression = formatQuery(selector, parsed.regexp);
return { ...query, expr: expression };
}
......
import { addLabelToQuery, addLabelToSelector, keepSelectorFilters } from './add_label_to_query';
import { addLabelToQuery, addLabelToSelector } from './add_label_to_query';
describe('addLabelToQuery()', () => {
it('should add label to simple query', () => {
......@@ -58,6 +58,11 @@ describe('addLabelToQuery()', () => {
'avg(foo{bar="baz"}) + sum(xx_yy{bar="baz"})'
);
});
it('should not remove filters', () => {
expect(addLabelToQuery('{x="y"} |="yy"', 'bar', 'baz')).toBe('{bar="baz",x="y"} |="yy"');
expect(addLabelToQuery('{x="y"} |="yy" !~"xx"', 'bar', 'baz')).toBe('{bar="baz",x="y"} |="yy" !~"xx"');
});
});
describe('addLabelToSelector()', () => {
......@@ -72,15 +77,3 @@ describe('addLabelToSelector()', () => {
expect(addLabelToSelector('{}', 'baz', '42', '!=')).toBe('{baz!="42"}');
});
});
describe('keepSelectorFilters()', () => {
test('should return empty string if no filter is in selector', () => {
expect(keepSelectorFilters('{foo="bar"}')).toBe('');
});
test('should return a filter if filter is in selector', () => {
expect(keepSelectorFilters('{foo="bar"} |="baz"')).toBe('|="baz"');
});
test('should return multiple filters if multiple filters are in selector', () => {
expect(keepSelectorFilters('{foo!="bar"} |="baz" |~"yy" !~"xx"')).toBe('|="baz" |~"yy" !~"xx"');
});
});
......@@ -91,12 +91,6 @@ export function addLabelToSelector(selector: string, labelKey: string, labelValu
return `{${formatted}}`;
}
export function keepSelectorFilters(selector: string) {
// Remove all label-key between {} and return filters. If first character is space, remove it.
const filters = selector.replace(/\{(.*?)\}/g, '').replace(/^ /, '');
return filters;
}
function isPositionInsideChars(text: string, position: number, openChar: string, closeChar: string) {
const nextSelectorStart = text.slice(position).indexOf(openChar);
const nextSelectorEnd = text.slice(position).indexOf(closeChar);
......
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