mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
Loki: Add support for IP label and line filter in query builder (#52658)
* Add support for IP line filter * Add support for IP label filter * Updates for Explain mode * Update test * Remove invalid options in LabelFilterIpMatches
This commit is contained in:
parent
bdcef92e35
commit
77421907b7
@ -127,7 +127,7 @@ describe('LokiQueryModeller', () => {
|
||||
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||
operations: [{ id: LokiOperationId.LabelFilter, params: ['__error__', '=', 'value'] }],
|
||||
})
|
||||
).toBe('{app="grafana"} | __error__=`value`');
|
||||
).toBe('{app="grafana"} | __error__ = `value`');
|
||||
});
|
||||
|
||||
it('Can query with label filter expression using greater than operator', () => {
|
||||
|
@ -292,6 +292,27 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
addOperationHandler: addLokiOperation,
|
||||
explainHandler: (op) => `Return log lines that does not match regex \`${op.params[0]}\`.`,
|
||||
},
|
||||
{
|
||||
id: LokiOperationId.LineFilterIpMatches,
|
||||
name: 'IP line filter expression',
|
||||
params: [
|
||||
{ name: 'Operator', type: 'string', options: ['|=', '!='] },
|
||||
{
|
||||
name: 'Pattern',
|
||||
type: 'string',
|
||||
placeholder: '<pattern>',
|
||||
minWidth: 16,
|
||||
runQueryOnEnter: true,
|
||||
},
|
||||
],
|
||||
defaultParams: ['|=', ''],
|
||||
alternativesKey: 'line filter',
|
||||
category: LokiVisualQueryOperationCategory.LineFilters,
|
||||
orderRank: LokiOperationOrder.LineFilters,
|
||||
renderer: (op, def, innerExpr) => `${innerExpr} ${op.params[0]} ip(\`${op.params[1]}\`)`,
|
||||
addOperationHandler: addLokiOperation,
|
||||
explainHandler: (op) => `Return log lines using IP matching of \`${op.params[1]}\``,
|
||||
},
|
||||
{
|
||||
id: LokiOperationId.LabelFilter,
|
||||
name: 'Label filter expression',
|
||||
@ -308,6 +329,23 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
addOperationHandler: addLokiOperation,
|
||||
explainHandler: () => `Label expression filter allows filtering using original and extracted labels.`,
|
||||
},
|
||||
{
|
||||
id: LokiOperationId.LabelFilterIpMatches,
|
||||
name: 'IP label filter expression',
|
||||
params: [
|
||||
{ name: 'Label', type: 'string' },
|
||||
{ name: 'Operator', type: 'string', options: ['=', '!='] },
|
||||
{ name: 'Value', type: 'string' },
|
||||
],
|
||||
defaultParams: ['', '=', ''],
|
||||
alternativesKey: 'label filter',
|
||||
category: LokiVisualQueryOperationCategory.LabelFilters,
|
||||
orderRank: LokiOperationOrder.LabelFilters,
|
||||
renderer: (model, def, innerExpr) =>
|
||||
`${innerExpr} | ${model.params[0]} ${model.params[1]} ip(\`${model.params[2]}\`)`,
|
||||
addOperationHandler: addLokiOperation,
|
||||
explainHandler: (op) => `Return log lines using IP matching of \`${op.params[2]}\` for \`${op.params[0]}\` label`,
|
||||
},
|
||||
{
|
||||
id: LokiOperationId.LabelFilterNoErrors,
|
||||
name: 'No pipeline errors',
|
||||
@ -443,7 +481,7 @@ function labelFilterRenderer(model: QueryBuilderOperation, def: QueryBuilderOper
|
||||
return `${innerExpr} | ${model.params[0]} ${model.params[1]} ${model.params[2]}`;
|
||||
}
|
||||
|
||||
return `${innerExpr} | ${model.params[0]}${model.params[1]}\`${model.params[2]}\``;
|
||||
return `${innerExpr} | ${model.params[0]} ${model.params[1]} \`${model.params[2]}\``;
|
||||
}
|
||||
|
||||
function pipelineRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { buildVisualQueryFromString } from './parsing';
|
||||
import { LokiVisualQuery } from './types';
|
||||
import { LokiOperationId, LokiVisualQuery } from './types';
|
||||
|
||||
describe('buildVisualQueryFromString', () => {
|
||||
it('creates no errors for empty query', () => {
|
||||
@ -77,15 +77,22 @@ describe('buildVisualQueryFromString', () => {
|
||||
});
|
||||
|
||||
it('returns error for query with ip matching line filter', () => {
|
||||
const context = buildVisualQueryFromString('{app="frontend"} |= ip("192.168.4.5/16")');
|
||||
expect(context.errors).toEqual([
|
||||
{
|
||||
text: 'Matching ip addresses not supported in query builder: |= ip("192.168.4.5/16")',
|
||||
from: 17,
|
||||
to: 40,
|
||||
parentType: 'LineFilters',
|
||||
},
|
||||
]);
|
||||
const context = buildVisualQueryFromString('{app="frontend"} |= ip("192.168.4.5/16") | logfmt');
|
||||
expect(context).toEqual(
|
||||
noErrors({
|
||||
labels: [
|
||||
{
|
||||
op: '=',
|
||||
value: 'frontend',
|
||||
label: 'app',
|
||||
},
|
||||
],
|
||||
operations: [
|
||||
{ id: '__line_filter_ip_matches', params: ['|=', '192.168.4.5/16'] },
|
||||
{ id: 'logfmt', params: [] },
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('parses query with matcher label filter', () => {
|
||||
@ -162,14 +169,21 @@ describe('buildVisualQueryFromString', () => {
|
||||
|
||||
it('returns error for query with ip label filter', () => {
|
||||
const context = buildVisualQueryFromString('{app="frontend"} | logfmt | address=ip("192.168.4.5/16")');
|
||||
expect(context.errors).toEqual([
|
||||
{
|
||||
text: 'IpLabelFilter not supported in query builder: address=ip("192.168.4.5/16")',
|
||||
from: 28,
|
||||
to: 56,
|
||||
parentType: 'PipelineStage',
|
||||
},
|
||||
]);
|
||||
expect(context).toEqual(
|
||||
noErrors({
|
||||
labels: [
|
||||
{
|
||||
op: '=',
|
||||
value: 'frontend',
|
||||
label: 'app',
|
||||
},
|
||||
],
|
||||
operations: [
|
||||
{ id: 'logfmt', params: [] },
|
||||
{ id: LokiOperationId.LabelFilterIpMatches, params: ['address', '=', '192.168.4.5/16'] },
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('parses query with with parser', () => {
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
import { QueryBuilderLabelFilter, QueryBuilderOperation } from '../../prometheus/querybuilder/shared/types';
|
||||
|
||||
import { binaryScalarDefs } from './binaryScalarOperations';
|
||||
import { LokiVisualQuery, LokiVisualQueryBinary } from './types';
|
||||
import { LokiOperationId, LokiVisualQuery, LokiVisualQueryBinary } from './types';
|
||||
|
||||
interface Context {
|
||||
query: LokiVisualQuery;
|
||||
@ -182,22 +182,24 @@ function getLabel(expr: string, node: SyntaxNode): QueryBuilderLabelFilter {
|
||||
}
|
||||
|
||||
function getLineFilter(expr: string, node: SyntaxNode): { operation?: QueryBuilderOperation; error?: string } {
|
||||
// Check for nodes not supported in visual builder and return error
|
||||
const ipLineFilter = getAllByType(expr, node, 'Ip');
|
||||
if (ipLineFilter.length > 0) {
|
||||
return {
|
||||
error: 'Matching ip addresses not supported in query builder',
|
||||
};
|
||||
}
|
||||
|
||||
const mapFilter: any = {
|
||||
'|=': '__line_contains',
|
||||
'!=': '__line_contains_not',
|
||||
'|~': '__line_matches_regex',
|
||||
'!~': '"__line_matches_regex"_not',
|
||||
};
|
||||
const filter = getString(expr, node.getChild('Filter'));
|
||||
const filterExpr = handleQuotes(getString(expr, node.getChild('String')));
|
||||
const ipLineFilter = node.getChild('FilterOp')?.getChild('Ip');
|
||||
|
||||
if (ipLineFilter) {
|
||||
return {
|
||||
operation: {
|
||||
id: LokiOperationId.LineFilterIpMatches,
|
||||
params: [filter, filterExpr],
|
||||
},
|
||||
};
|
||||
}
|
||||
const mapFilter: any = {
|
||||
'|=': LokiOperationId.LineContains,
|
||||
'!=': LokiOperationId.LineContainsNot,
|
||||
'|~': LokiOperationId.LineMatchesRegex,
|
||||
'!~': LokiOperationId.LineMatchesRegexNot,
|
||||
};
|
||||
|
||||
return {
|
||||
operation: {
|
||||
@ -238,8 +240,17 @@ function getLabelFilter(expr: string, node: SyntaxNode): { operation?: QueryBuil
|
||||
};
|
||||
}
|
||||
if (node.firstChild!.name === 'IpLabelFilter') {
|
||||
const ipLabelFilter = node.firstChild;
|
||||
const label = ipLabelFilter?.getChild('Identifier');
|
||||
const op = label?.nextSibling;
|
||||
const value = ipLabelFilter?.getChild('String');
|
||||
const valueString = handleQuotes(getString(expr, value));
|
||||
|
||||
return {
|
||||
error: 'IpLabelFilter not supported in query builder',
|
||||
operation: {
|
||||
id: LokiOperationId.LabelFilterIpMatches,
|
||||
params: [getString(expr, label), getString(expr, op), valueString],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -62,8 +62,10 @@ export enum LokiOperationId {
|
||||
LineContainsNot = '__line_contains_not',
|
||||
LineMatchesRegex = '__line_matches_regex',
|
||||
LineMatchesRegexNot = '__line_matches_regex_not',
|
||||
LineFilterIpMatches = '__line_filter_ip_matches',
|
||||
LabelFilter = '__label_filter',
|
||||
LabelFilterNoErrors = '__label_filter_no_errors',
|
||||
LabelFilterIpMatches = '__label_filter_ip_marches',
|
||||
Unwrap = 'unwrap',
|
||||
// Binary ops
|
||||
Addition = '__addition',
|
||||
|
Loading…
Reference in New Issue
Block a user