mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Add all supported parsers to query builder (#47304)
* Loki: Add all supported parsers to query builderr * Update test * Add tests for new parsers
This commit is contained in:
parent
fea4d1f57a
commit
c5ac19d499
@ -31,6 +31,33 @@ describe('LokiQueryModeller', () => {
|
|||||||
).toBe('{app="grafana"} | logfmt');
|
).toBe('{app="grafana"} | logfmt');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can query with pipeline operation regexp', () => {
|
||||||
|
expect(
|
||||||
|
modeller.renderQuery({
|
||||||
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
|
operations: [{ id: LokiOperationId.Regexp, params: ['re'] }],
|
||||||
|
})
|
||||||
|
).toBe('{app="grafana"} | regexp `re`');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can query with pipeline operation pattern', () => {
|
||||||
|
expect(
|
||||||
|
modeller.renderQuery({
|
||||||
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
|
operations: [{ id: LokiOperationId.Pattern, params: ['<pattern>'] }],
|
||||||
|
})
|
||||||
|
).toBe('{app="grafana"} | pattern `<pattern>`');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can query with pipeline operation unpack', () => {
|
||||||
|
expect(
|
||||||
|
modeller.renderQuery({
|
||||||
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
|
operations: [{ id: LokiOperationId.Unpack, params: [] }],
|
||||||
|
})
|
||||||
|
).toBe('{app="grafana"} | unpack');
|
||||||
|
});
|
||||||
|
|
||||||
it('Can query with line filter contains operation', () => {
|
it('Can query with line filter contains operation', () => {
|
||||||
expect(
|
expect(
|
||||||
modeller.renderQuery({
|
modeller.renderQuery({
|
||||||
@ -82,7 +109,7 @@ describe('LokiQueryModeller', () => {
|
|||||||
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
operations: [{ id: LokiOperationId.LabelFilter, params: ['__error__', '=', 'value'] }],
|
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', () => {
|
it('Can query with label filter expression using greater than operator', () => {
|
||||||
@ -100,7 +127,7 @@ describe('LokiQueryModeller', () => {
|
|||||||
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
operations: [{ id: LokiOperationId.LabelFilterNoErrors, params: [] }],
|
operations: [{ id: LokiOperationId.LabelFilterNoErrors, params: [] }],
|
||||||
})
|
})
|
||||||
).toBe('{app="grafana"} | __error__=""');
|
).toBe('{app="grafana"} | __error__=``');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can query with unwrap operation', () => {
|
it('Can query with unwrap operation', () => {
|
||||||
@ -118,7 +145,7 @@ describe('LokiQueryModeller', () => {
|
|||||||
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
labels: [{ label: 'app', op: '=', value: 'grafana' }],
|
||||||
operations: [{ id: LokiOperationId.LineFormat, params: ['{{.status_code}}'] }],
|
operations: [{ id: LokiOperationId.LineFormat, params: ['{{.status_code}}'] }],
|
||||||
})
|
})
|
||||||
).toBe('{app="grafana"} | line_format "{{.status_code}}"');
|
).toBe('{app="grafana"} | line_format `{{.status_code}}`');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can render with label_format operation', () => {
|
it('Can render with label_format operation', () => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { LokiAndPromQueryModellerBase } from '../../prometheus/querybuilder/shared/LokiAndPromQueryModellerBase';
|
import { LokiAndPromQueryModellerBase } from '../../prometheus/querybuilder/shared/LokiAndPromQueryModellerBase';
|
||||||
import { QueryBuilderLabelFilter } from '../../prometheus/querybuilder/shared/types';
|
import { QueryBuilderLabelFilter } from '../../prometheus/querybuilder/shared/types';
|
||||||
import { getOperationDefintions } from './operations';
|
import { getOperationDefinitions } from './operations';
|
||||||
import { LokiOperationId, LokiQueryPattern, LokiVisualQueryOperationCategory } from './types';
|
import { LokiOperationId, LokiQueryPattern, LokiVisualQueryOperationCategory } from './types';
|
||||||
|
|
||||||
export class LokiQueryModeller extends LokiAndPromQueryModellerBase {
|
export class LokiQueryModeller extends LokiAndPromQueryModellerBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(getOperationDefintions);
|
super(getOperationDefinitions);
|
||||||
|
|
||||||
this.setOperationCategories([
|
this.setOperationCategories([
|
||||||
LokiVisualQueryOperationCategory.Aggregations,
|
LokiVisualQueryOperationCategory.Aggregations,
|
||||||
|
@ -10,7 +10,7 @@ import { FUNCTIONS } from '../syntax';
|
|||||||
import { binaryScalarOperations } from './binaryScalarOperations';
|
import { binaryScalarOperations } from './binaryScalarOperations';
|
||||||
import { LokiOperationId, LokiOperationOrder, LokiVisualQuery, LokiVisualQueryOperationCategory } from './types';
|
import { LokiOperationId, LokiOperationOrder, LokiVisualQuery, LokiVisualQueryOperationCategory } from './types';
|
||||||
|
|
||||||
export function getOperationDefintions(): QueryBuilderOperationDef[] {
|
export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||||
const aggregations = [
|
const aggregations = [
|
||||||
LokiOperationId.Sum,
|
LokiOperationId.Sum,
|
||||||
LokiOperationId.Min,
|
LokiOperationId.Min,
|
||||||
@ -55,7 +55,64 @@ export function getOperationDefintions(): QueryBuilderOperationDef[] {
|
|||||||
renderer: pipelineRenderer,
|
renderer: pipelineRenderer,
|
||||||
addOperationHandler: addLokiOperation,
|
addOperationHandler: addLokiOperation,
|
||||||
explainHandler: () =>
|
explainHandler: () =>
|
||||||
`This will extract all keys and values from a [logfmt](https://grafana.com/docs/loki/latest/logql/log_queries/#logfmt) formatted log line as labels. The extracted lables can be used in label filter expressions and used as values for a range aggregation via the unwrap operation. `,
|
`This will extract all keys and values from a [logfmt](https://grafana.com/docs/loki/latest/logql/log_queries/#logfmt) formatted log line as labels. The extracted labels can be used in label filter expressions and used as values for a range aggregation via the unwrap operation.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: LokiOperationId.Regexp,
|
||||||
|
name: 'Regexp',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'String',
|
||||||
|
type: 'string',
|
||||||
|
hideName: true,
|
||||||
|
placeholder: '<re>',
|
||||||
|
description: 'The regexp expression that matches the structure of a log line.',
|
||||||
|
minWidth: 20,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: [''],
|
||||||
|
alternativesKey: 'format',
|
||||||
|
category: LokiVisualQueryOperationCategory.Formats,
|
||||||
|
orderRank: LokiOperationOrder.LineFormats,
|
||||||
|
renderer: (model, def, innerExpr) => `${innerExpr} | regexp \`${model.params[0]}\``,
|
||||||
|
addOperationHandler: addLokiOperation,
|
||||||
|
explainHandler: () =>
|
||||||
|
`The [regexp parser](https://grafana.com/docs/loki/latest/logql/log_queries/#regular-expression) takes a single parameter | regexp "<re>" which is the regular expression using the Golang RE2 syntax. The regular expression must contain a least one named sub-match (e.g (?P<name>re)), each sub-match will extract a different label. The expression matches the structure of a log line. The extracted labels can be used in label filter expressions and used as values for a range aggregation via the unwrap operation.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: LokiOperationId.Pattern,
|
||||||
|
name: 'Pattern',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'String',
|
||||||
|
type: 'string',
|
||||||
|
hideName: true,
|
||||||
|
placeholder: '<pattern-expression>',
|
||||||
|
description: 'The expression that matches the structure of a log line.',
|
||||||
|
minWidth: 20,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: [''],
|
||||||
|
alternativesKey: 'format',
|
||||||
|
category: LokiVisualQueryOperationCategory.Formats,
|
||||||
|
orderRank: LokiOperationOrder.LineFormats,
|
||||||
|
renderer: (model, def, innerExpr) => `${innerExpr} | pattern \`${model.params[0]}\``,
|
||||||
|
addOperationHandler: addLokiOperation,
|
||||||
|
explainHandler: () =>
|
||||||
|
`The [pattern parser](https://grafana.com/docs/loki/latest/logql/log_queries/#pattern) allows the explicit extraction of fields from log lines by defining a pattern expression (| pattern \`<pattern-expression>\`). The expression matches the structure of a log line. The extracted labels can be used in label filter expressions and used as values for a range aggregation via the unwrap operation.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: LokiOperationId.Unpack,
|
||||||
|
name: 'Unpack',
|
||||||
|
params: [],
|
||||||
|
defaultParams: [],
|
||||||
|
alternativesKey: 'format',
|
||||||
|
category: LokiVisualQueryOperationCategory.Formats,
|
||||||
|
orderRank: LokiOperationOrder.LineFormats,
|
||||||
|
renderer: pipelineRenderer,
|
||||||
|
addOperationHandler: addLokiOperation,
|
||||||
|
explainHandler: () =>
|
||||||
|
`This will extract all keys and values from a JSON log line, [unpacking](https://grafana.com/docs/loki/latest/logql/log_queries/#unpack) all embedded labels in the pack stage. The extracted labels can be used in label filter expressions and used as values for a range aggregation via the unwrap operation.`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: LokiOperationId.LineFormat,
|
id: LokiOperationId.LineFormat,
|
||||||
@ -74,7 +131,7 @@ export function getOperationDefintions(): QueryBuilderOperationDef[] {
|
|||||||
alternativesKey: 'format',
|
alternativesKey: 'format',
|
||||||
category: LokiVisualQueryOperationCategory.Formats,
|
category: LokiVisualQueryOperationCategory.Formats,
|
||||||
orderRank: LokiOperationOrder.LineFormats,
|
orderRank: LokiOperationOrder.LineFormats,
|
||||||
renderer: (model, def, innerExpr) => `${innerExpr} | line_format "${model.params[0]}"`,
|
renderer: (model, def, innerExpr) => `${innerExpr} | line_format \`${model.params[0]}\``,
|
||||||
addOperationHandler: addLokiOperation,
|
addOperationHandler: addLokiOperation,
|
||||||
explainHandler: () =>
|
explainHandler: () =>
|
||||||
`This will replace log line using a specified template. The template can refer to stream labels and extracted labels.
|
`This will replace log line using a specified template. The template can refer to stream labels and extracted labels.
|
||||||
@ -212,7 +269,7 @@ export function getOperationDefintions(): QueryBuilderOperationDef[] {
|
|||||||
defaultParams: [],
|
defaultParams: [],
|
||||||
category: LokiVisualQueryOperationCategory.LabelFilters,
|
category: LokiVisualQueryOperationCategory.LabelFilters,
|
||||||
orderRank: LokiOperationOrder.NoErrors,
|
orderRank: LokiOperationOrder.NoErrors,
|
||||||
renderer: (model, def, innerExpr) => `${innerExpr} | __error__=""`,
|
renderer: (model, def, innerExpr) => `${innerExpr} | __error__=\`\``,
|
||||||
addOperationHandler: addLokiOperation,
|
addOperationHandler: addLokiOperation,
|
||||||
explainHandler: () => `Filter out all formatting and parsing errors.`,
|
explainHandler: () => `Filter out all formatting and parsing errors.`,
|
||||||
},
|
},
|
||||||
@ -303,7 +360,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]}"`;
|
return `${innerExpr} | ${model.params[0]}${model.params[1]}\`${model.params[2]}\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pipelineRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
function pipelineRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
@ -205,8 +205,7 @@ function getLabelFilter(expr: string, node: SyntaxNode): QueryBuilderOperation {
|
|||||||
const label = filter!.firstChild;
|
const label = filter!.firstChild;
|
||||||
const op = label!.nextSibling;
|
const op = label!.nextSibling;
|
||||||
const value = op!.nextSibling;
|
const value = op!.nextSibling;
|
||||||
const params = [getString(expr, label), getString(expr, op), getString(expr, value).replace(/"/g, '')];
|
const params = [getString(expr, label), getString(expr, op), handleQuotes(getString(expr, value))];
|
||||||
|
|
||||||
//Special case of pipe filtering - no errors
|
//Special case of pipe filtering - no errors
|
||||||
if (params.join('') === `__error__=`) {
|
if (params.join('') === `__error__=`) {
|
||||||
return {
|
return {
|
||||||
|
@ -30,6 +30,9 @@ export enum LokiVisualQueryOperationCategory {
|
|||||||
export enum LokiOperationId {
|
export enum LokiOperationId {
|
||||||
Json = 'json',
|
Json = 'json',
|
||||||
Logfmt = 'logfmt',
|
Logfmt = 'logfmt',
|
||||||
|
Regexp = 'regexp',
|
||||||
|
Pattern = 'pattern',
|
||||||
|
Unpack = 'unpack',
|
||||||
LineFormat = 'line_format',
|
LineFormat = 'line_format',
|
||||||
LabelFormat = 'label_format',
|
LabelFormat = 'label_format',
|
||||||
Rate = 'rate',
|
Rate = 'rate',
|
||||||
|
Loading…
Reference in New Issue
Block a user