Loki Monaco Editor: grab operator documentation from the operations module (#57525)
* feat(loki-operations): add method to resolve operation docs * feat(loki-operations): read operation and strip markdown links * feat(loki-monaco-editor): read parser docs from operations * feat(loki-monaco-editor): grab docs for more operations * Chore: update completions test * Chore: add tests for the operations module * Chore: fix typo Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> * Chore: fix typo Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
This commit is contained in:
co-authored by
Ivana Huckova
parent
e81ce1dae7
commit
c8689fd591
+16
-9
@@ -6,6 +6,10 @@ import { CompletionDataProvider } from './CompletionDataProvider';
|
||||
import { getCompletions } from './completions';
|
||||
import { Label, Situation } from './situation';
|
||||
|
||||
jest.mock('../../../querybuilder/operations', () => ({
|
||||
explainOperator: () => 'Operator docs',
|
||||
}));
|
||||
|
||||
const history = [
|
||||
{
|
||||
ts: 12345678,
|
||||
@@ -35,59 +39,59 @@ const otherLabels: Label[] = [
|
||||
];
|
||||
const afterSelectorCompletions = [
|
||||
{
|
||||
documentation: 'Log line contains string',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '|= "$0"',
|
||||
isSnippet: true,
|
||||
label: '|= ""',
|
||||
type: 'LINE_FILTER',
|
||||
},
|
||||
{
|
||||
documentation: 'Log line does not contain string',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '!= "$0"',
|
||||
isSnippet: true,
|
||||
label: '!= ""',
|
||||
type: 'LINE_FILTER',
|
||||
},
|
||||
{
|
||||
documentation: 'Log line contains a match to the regular expression',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '|~ "$0"',
|
||||
isSnippet: true,
|
||||
label: '|~ ""',
|
||||
type: 'LINE_FILTER',
|
||||
},
|
||||
{
|
||||
documentation: 'Log line does not contain a match to the regular expression',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '!~ "$0"',
|
||||
isSnippet: true,
|
||||
label: '!~ ""',
|
||||
type: 'LINE_FILTER',
|
||||
},
|
||||
{
|
||||
documentation: 'Parse and extract labels from the log content.',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '',
|
||||
label: '// Placeholder for the detected parser',
|
||||
type: 'DETECTED_PARSER_PLACEHOLDER',
|
||||
},
|
||||
{
|
||||
documentation: 'Parse and extract labels from the log content.',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '',
|
||||
label: '// Placeholder for logfmt or json',
|
||||
type: 'OPPOSITE_PARSER_PLACEHOLDER',
|
||||
},
|
||||
{
|
||||
documentation: 'Parse and extract labels from the log content.',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '| pattern',
|
||||
label: 'pattern',
|
||||
type: 'PARSER',
|
||||
},
|
||||
{
|
||||
documentation: 'Parse and extract labels from the log content.',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '| regexp',
|
||||
label: 'regexp',
|
||||
type: 'PARSER',
|
||||
},
|
||||
{
|
||||
documentation: 'Parse and extract labels from the log content.',
|
||||
documentation: 'Operator docs',
|
||||
insertText: '| unpack',
|
||||
label: 'unpack',
|
||||
type: 'PARSER',
|
||||
@@ -106,18 +110,21 @@ const afterSelectorCompletions = [
|
||||
insertText: '| unwrap',
|
||||
label: 'unwrap',
|
||||
type: 'PIPE_OPERATION',
|
||||
documentation: 'Operator docs',
|
||||
},
|
||||
{
|
||||
insertText: '| line_format "{{.$0}}"',
|
||||
isSnippet: true,
|
||||
label: 'line_format',
|
||||
type: 'PIPE_OPERATION',
|
||||
documentation: 'Operator docs',
|
||||
},
|
||||
{
|
||||
insertText: '| label_format',
|
||||
isSnippet: true,
|
||||
label: 'label_format',
|
||||
type: 'PIPE_OPERATION',
|
||||
documentation: 'Operator docs',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
+16
-8
@@ -1,4 +1,6 @@
|
||||
import { escapeLabelValueInExactSelector } from '../../../languageUtils';
|
||||
import { explainOperator } from '../../../querybuilder/operations';
|
||||
import { LokiOperationId } from '../../../querybuilder/types';
|
||||
import { AGGREGATION_OPERATORS, RANGE_VEC_FUNCTIONS } from '../../../syntax';
|
||||
|
||||
import { CompletionDataProvider } from './CompletionDataProvider';
|
||||
@@ -67,21 +69,21 @@ const DURATION_COMPLETIONS: Completion[] = ['$__interval', '$__range', '1m', '5m
|
||||
const LINE_FILTER_COMPLETIONS = [
|
||||
{
|
||||
operator: '|=',
|
||||
documentation: 'Log line contains string',
|
||||
documentation: explainOperator(LokiOperationId.LineContains),
|
||||
afterPipe: true,
|
||||
},
|
||||
{
|
||||
operator: '!=',
|
||||
documentation: 'Log line does not contain string',
|
||||
documentation: explainOperator(LokiOperationId.LineContainsNot),
|
||||
},
|
||||
{
|
||||
operator: '|~',
|
||||
documentation: 'Log line contains a match to the regular expression',
|
||||
documentation: explainOperator(LokiOperationId.LineMatchesRegex),
|
||||
afterPipe: true,
|
||||
},
|
||||
{
|
||||
operator: '!~',
|
||||
documentation: 'Log line does not contain a match to the regular expression',
|
||||
documentation: explainOperator(LokiOperationId.LineMatchesRegexNot),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -152,7 +154,6 @@ async function getInGroupingCompletions(
|
||||
}
|
||||
|
||||
const PARSERS = ['json', 'logfmt', 'pattern', 'regexp', 'unpack'];
|
||||
const PARSER_DOCUMENTATION = 'Parse and extract labels from the log content.';
|
||||
|
||||
async function getAfterSelectorCompletions(
|
||||
labels: Label[],
|
||||
@@ -171,7 +172,9 @@ async function getAfterSelectorCompletions(
|
||||
type: 'PARSER',
|
||||
label: `json${extra}`,
|
||||
insertText: `${prefix}json`,
|
||||
documentation: hasLevelInExtractedLabels ? 'Use it to get log-levels in the histogram' : PARSER_DOCUMENTATION,
|
||||
documentation: hasLevelInExtractedLabels
|
||||
? 'Use it to get log-levels in the histogram'
|
||||
: explainOperator(LokiOperationId.Json),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,7 +185,9 @@ async function getAfterSelectorCompletions(
|
||||
type: 'DURATION',
|
||||
label: `logfmt${extra}`,
|
||||
insertText: `${prefix}logfmt`,
|
||||
documentation: hasLevelInExtractedLabels ? 'Get detected levels in the histogram' : PARSER_DOCUMENTATION,
|
||||
documentation: hasLevelInExtractedLabels
|
||||
? 'Get detected levels in the histogram'
|
||||
: explainOperator(LokiOperationId.Logfmt),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,7 +197,7 @@ async function getAfterSelectorCompletions(
|
||||
type: 'PARSER',
|
||||
label: parser,
|
||||
insertText: `${prefix}${parser}`,
|
||||
documentation: PARSER_DOCUMENTATION,
|
||||
documentation: explainOperator(parser),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -208,6 +213,7 @@ async function getAfterSelectorCompletions(
|
||||
type: 'PIPE_OPERATION',
|
||||
label: 'unwrap',
|
||||
insertText: `${prefix}unwrap`,
|
||||
documentation: explainOperator(LokiOperationId.Unwrap),
|
||||
});
|
||||
|
||||
completions.push({
|
||||
@@ -215,6 +221,7 @@ async function getAfterSelectorCompletions(
|
||||
label: 'line_format',
|
||||
insertText: `${prefix}line_format "{{.$0}}"`,
|
||||
isSnippet: true,
|
||||
documentation: explainOperator(LokiOperationId.LineFormat),
|
||||
});
|
||||
|
||||
completions.push({
|
||||
@@ -222,6 +229,7 @@ async function getAfterSelectorCompletions(
|
||||
label: 'label_format',
|
||||
insertText: `${prefix}label_format`,
|
||||
isSnippet: true,
|
||||
documentation: explainOperator(LokiOperationId.LabelFormat),
|
||||
});
|
||||
|
||||
return [...getLineFilterCompletions(afterPipe), ...completions];
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { explainOperator, getOperationDefinitions } from './operations';
|
||||
import { LokiOperationId } from './types';
|
||||
|
||||
const undocumentedOperationsIds: string[] = [
|
||||
LokiOperationId.Addition,
|
||||
LokiOperationId.Subtraction,
|
||||
LokiOperationId.MultiplyBy,
|
||||
LokiOperationId.DivideBy,
|
||||
LokiOperationId.Modulo,
|
||||
LokiOperationId.Exponent,
|
||||
LokiOperationId.NestedQuery,
|
||||
LokiOperationId.EqualTo,
|
||||
LokiOperationId.NotEqualTo,
|
||||
LokiOperationId.GreaterThan,
|
||||
LokiOperationId.LessThan,
|
||||
LokiOperationId.GreaterOrEqual,
|
||||
LokiOperationId.LessOrEqual,
|
||||
];
|
||||
|
||||
describe('explainOperator', () => {
|
||||
let operations = [];
|
||||
let undocumentedOperations = [];
|
||||
|
||||
const definitions = getOperationDefinitions();
|
||||
for (const definition of definitions) {
|
||||
if (!undocumentedOperationsIds.includes(definition.id)) {
|
||||
operations.push(definition.id);
|
||||
} else {
|
||||
undocumentedOperations.push(definition.id);
|
||||
}
|
||||
}
|
||||
|
||||
test('Resolves operation definitions', () => {
|
||||
expect(definitions.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test.each(operations)('Returns docs for the %s operation', (operation) => {
|
||||
const explain = explainOperator(operation);
|
||||
|
||||
expect(explain).toBeDefined();
|
||||
expect(explain).not.toBe('');
|
||||
});
|
||||
|
||||
test.each(undocumentedOperations)('Returns empty docs for the %s operation', (operation) => {
|
||||
const explain = explainOperator(operation);
|
||||
|
||||
expect(explain).toBeDefined();
|
||||
expect(explain).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -420,3 +420,19 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Keeping a local copy as an optimization measure.
|
||||
const definitions = getOperationDefinitions();
|
||||
|
||||
/**
|
||||
* Given an operator, return the corresponding explain.
|
||||
* For usage within the Query Editor.
|
||||
*/
|
||||
export function explainOperator(id: LokiOperationId | string): string {
|
||||
const definition = definitions.find((operation) => operation.id === id);
|
||||
|
||||
const explain = definition?.explainHandler?.({ id: '', params: ['<value>'] }) || '';
|
||||
|
||||
// Strip markdown links
|
||||
return explain.replace(/\[(.*)\]\(.*\)/g, '$1');
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export type QueryBuilderAddOperationHandler<T> = (
|
||||
modeller: VisualQueryModeller
|
||||
) => T;
|
||||
|
||||
export type QueryBuilderExplainOperationHandler = (op: QueryBuilderOperation, def: QueryBuilderOperationDef) => string;
|
||||
export type QueryBuilderExplainOperationHandler = (op: QueryBuilderOperation, def?: QueryBuilderOperationDef) => string;
|
||||
|
||||
export type QueryBuilderOnParamChangedHandler = (
|
||||
index: number,
|
||||
|
||||
Reference in New Issue
Block a user