Loki Monaco Editor: add missing documentation and new autocompletion type (#57186)

* feat(loki-monaco-editor): add documentation and pipe operators

- Added documentation for line filters
- Added documentation for parsers
- Improved parser suggestions
- Introduced new PIPE_OPERATION category
- Added missing label_format pipe operation

* feat(loki-monaco-editor): update tests

* Chore: remove unused completion type

* Chore: remove line format
This commit is contained in:
Matias Chomicki
2022-10-19 10:30:44 -04:00
committed by GitHub
parent 2987734832
commit 93f39b5178
3 changed files with 70 additions and 21 deletions
@@ -35,50 +35,59 @@ const otherLabels: Label[] = [
];
const afterSelectorCompletions = [
{
documentation: 'Log line contains string',
insertText: '|= "$0"',
isSnippet: true,
label: '|= ""',
type: 'LINE_FILTER',
},
{
documentation: 'Log line does not contain string',
insertText: '!= "$0"',
isSnippet: true,
label: '!= ""',
type: 'LINE_FILTER',
},
{
documentation: 'Log line contains a match to the regular expression',
insertText: '|~ "$0"',
isSnippet: true,
label: '|~ ""',
type: 'LINE_FILTER',
},
{
documentation: 'Log line does not contain a match to the regular expression',
insertText: '!~ "$0"',
isSnippet: true,
label: '!~ ""',
type: 'LINE_FILTER',
},
{
documentation: 'Parse and extract labels from the log content.',
insertText: '',
label: '// Placeholder for the detected parser',
type: 'DETECTED_PARSER_PLACEHOLDER',
},
{
documentation: 'Parse and extract labels from the log content.',
insertText: '',
label: '// Placeholder for logfmt or json',
type: 'OPPOSITE_PARSER_PLACEHOLDER',
},
{
documentation: 'Parse and extract labels from the log content.',
insertText: '| pattern',
label: 'pattern',
type: 'PARSER',
},
{
documentation: 'Parse and extract labels from the log content.',
insertText: '| regexp',
label: 'regexp',
type: 'PARSER',
},
{
documentation: 'Parse and extract labels from the log content.',
insertText: '| unpack',
label: 'unpack',
type: 'PARSER',
@@ -96,13 +105,19 @@ const afterSelectorCompletions = [
{
insertText: '| unwrap',
label: 'unwrap',
type: 'LINE_FILTER',
type: 'PIPE_OPERATION',
},
{
insertText: '| line_format "{{.$0}}"',
isSnippet: true,
label: 'line_format',
type: 'LINE_FORMAT',
type: 'PIPE_OPERATION',
},
{
insertText: '| label_format',
isSnippet: true,
label: 'label_format',
type: 'PIPE_OPERATION',
},
];
@@ -14,7 +14,7 @@ export type CompletionType =
| 'PATTERN'
| 'PARSER'
| 'LINE_FILTER'
| 'LINE_FORMAT';
| 'PIPE_OPERATION';
type Completion = {
type: CompletionType;
@@ -64,16 +64,37 @@ const DURATION_COMPLETIONS: Completion[] = ['$__interval', '$__range', '1m', '5m
})
);
function getLineFilterCompletions(afterPipe: boolean): Completion[] {
const lineFilters = afterPipe ? ['=', '~'] : ['|=', '!=', '|~', '!~'];
const prefix = afterPipe ? '|' : '';
const LINE_FILTER_COMPLETIONS = [
{
operator: '|=',
documentation: 'Log line contains string',
afterPipe: true,
},
{
operator: '!=',
documentation: 'Log line does not contain string',
},
{
operator: '|~',
documentation: 'Log line contains a match to the regular expression',
afterPipe: true,
},
{
operator: '!~',
documentation: 'Log line does not contain a match to the regular expression',
},
];
return lineFilters.map((operator) => ({
type: 'LINE_FILTER',
label: `${prefix}${operator} ""`,
insertText: `${operator} "$0"`,
isSnippet: true,
}));
function getLineFilterCompletions(afterPipe: boolean): Completion[] {
return LINE_FILTER_COMPLETIONS.filter((completion) => !afterPipe || completion.afterPipe).map(
({ operator, documentation }) => ({
type: 'LINE_FILTER',
label: `${operator} ""`,
insertText: `${afterPipe ? operator.replace('|', '') : operator} "$0"`,
isSnippet: true,
documentation,
})
);
}
async function getAllHistoryCompletions(dataProvider: CompletionDataProvider): Promise<Completion[]> {
@@ -130,33 +151,38 @@ async function getInGroupingCompletions(
return getLabelNamesForCompletions('', false, true, otherLabels, dataProvider);
}
const PARSERS = ['json', 'logfmt', 'pattern', 'regexp', 'unpack'];
const PARSER_DOCUMENTATION = 'Parse and extract labels from the log content.';
async function getAfterSelectorCompletions(
labels: Label[],
afterPipe: boolean,
dataProvider: CompletionDataProvider
): Promise<Completion[]> {
const { extractedLabelKeys, hasJSON, hasLogfmt } = await dataProvider.getParserAndLabelKeys(labels);
const allParsers = new Set(['json', 'logfmt', 'pattern', 'regexp', 'unpack']);
const allParsers = new Set(PARSERS);
const completions: Completion[] = [];
const prefix = afterPipe ? ' ' : '| ';
const hasLevelInExtractedLabels = extractedLabelKeys.some((key) => key === 'level');
if (hasJSON) {
allParsers.delete('json');
const explanation = hasLevelInExtractedLabels ? 'use to get log-levels in the histogram' : 'detected';
const extra = hasLevelInExtractedLabels ? '' : ' (detected)';
completions.push({
type: 'PARSER',
label: `json (${explanation})`,
label: `json${extra}`,
insertText: `${prefix}json`,
documentation: hasLevelInExtractedLabels ? 'Use it to get log-levels in the histogram' : PARSER_DOCUMENTATION,
});
}
if (hasLogfmt) {
allParsers.delete('logfmt');
const explanation = hasLevelInExtractedLabels ? 'get detected levels in the histogram' : 'detected';
const extra = hasLevelInExtractedLabels ? '' : ' (detected)';
completions.push({
type: 'DURATION',
label: `logfmt (${explanation})`,
label: `logfmt${extra}`,
insertText: `${prefix}logfmt`,
documentation: hasLevelInExtractedLabels ? 'Get detected levels in the histogram' : PARSER_DOCUMENTATION,
});
}
@@ -166,6 +192,7 @@ async function getAfterSelectorCompletions(
type: 'PARSER',
label: parser,
insertText: `${prefix}${parser}`,
documentation: PARSER_DOCUMENTATION,
});
});
@@ -178,18 +205,25 @@ async function getAfterSelectorCompletions(
});
completions.push({
type: 'LINE_FILTER',
type: 'PIPE_OPERATION',
label: 'unwrap',
insertText: `${prefix}unwrap`,
});
completions.push({
type: 'LINE_FORMAT',
type: 'PIPE_OPERATION',
label: 'line_format',
insertText: `${prefix}line_format "{{.$0}}"`,
isSnippet: true,
});
completions.push({
type: 'PIPE_OPERATION',
label: 'label_format',
insertText: `${prefix}label_format`,
isSnippet: true,
});
return [...getLineFilterCompletions(afterPipe), ...completions];
}
@@ -47,8 +47,8 @@ function getMonacoCompletionItemKind(type: CompletionType, monaco: Monaco): mona
return monaco.languages.CompletionItemKind.Class;
case 'LINE_FILTER':
return monaco.languages.CompletionItemKind.TypeParameter;
case 'LINE_FORMAT':
return monaco.languages.CompletionItemKind.Event;
case 'PIPE_OPERATION':
return monaco.languages.CompletionItemKind.Interface;
default:
throw new NeverCaseError(type);
}