mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Improve getLogQueryFromMetricsQuery (#75492)
* Query utils: fix bug in getLogQueryFromMetricsQuery function * Query utils: implement getLogQueryFromMetricsQueryAtPosition * Loki autocomplete situation: use getLogQueryFromMetricsQueryAtPosition * Fix typo * getLogQueryFromMetricsQueryAtPosition: use find instead of filter
This commit is contained in:
@@ -30,7 +30,7 @@ import {
|
|||||||
LabelExtractionExpressionList,
|
LabelExtractionExpressionList,
|
||||||
} from '@grafana/lezer-logql';
|
} from '@grafana/lezer-logql';
|
||||||
|
|
||||||
import { getLogQueryFromMetricsQuery, getNodesFromQuery } from '../../../queryUtils';
|
import { getLogQueryFromMetricsQueryAtPosition, getNodesFromQuery } from '../../../queryUtils';
|
||||||
|
|
||||||
type Direction = 'parent' | 'firstChild' | 'lastChild' | 'nextSibling';
|
type Direction = 'parent' | 'firstChild' | 'lastChild' | 'nextSibling';
|
||||||
type NodeType = number;
|
type NodeType = number;
|
||||||
@@ -303,7 +303,7 @@ function getLabels(selectorNode: SyntaxNode, text: string): Label[] {
|
|||||||
function resolveAfterUnwrap(node: SyntaxNode, text: string, pos: number): Situation | null {
|
function resolveAfterUnwrap(node: SyntaxNode, text: string, pos: number): Situation | null {
|
||||||
return {
|
return {
|
||||||
type: 'AFTER_UNWRAP',
|
type: 'AFTER_UNWRAP',
|
||||||
logQuery: getLogQueryFromMetricsQuery(text).trim(),
|
logQuery: getLogQueryFromMetricsQueryAtPosition(text, pos).trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'IN_GROUPING',
|
type: 'IN_GROUPING',
|
||||||
logQuery: getLogQueryFromMetricsQuery(text).trim(),
|
logQuery: getLogQueryFromMetricsQueryAtPosition(text, pos).trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +465,7 @@ function resolveLogfmtParser(_: SyntaxNode, text: string, cursorPosition: number
|
|||||||
type: 'IN_LOGFMT',
|
type: 'IN_LOGFMT',
|
||||||
otherLabels,
|
otherLabels,
|
||||||
flags,
|
flags,
|
||||||
logQuery: getLogQueryFromMetricsQuery(text).trim(),
|
logQuery: getLogQueryFromMetricsQueryAtPosition(text, position).trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ function resolveLogOrLogRange(node: SyntaxNode, text: string, pos: number, after
|
|||||||
type: 'AFTER_SELECTOR',
|
type: 'AFTER_SELECTOR',
|
||||||
afterPipe,
|
afterPipe,
|
||||||
hasSpace: text.charAt(pos - 1) === ' ',
|
hasSpace: text.charAt(pos - 1) === ' ',
|
||||||
logQuery: getLogQueryFromMetricsQuery(text).trim(),
|
logQuery: getLogQueryFromMetricsQueryAtPosition(text, pos).trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,7 +582,7 @@ function resolveSelector(node: SyntaxNode, text: string, pos: number): Situation
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveAfterKeepAndDrop(node: SyntaxNode, text: string, pos: number): Situation | null {
|
function resolveAfterKeepAndDrop(node: SyntaxNode, text: string, pos: number): Situation | null {
|
||||||
let logQuery = getLogQueryFromMetricsQuery(text).trim();
|
let logQuery = getLogQueryFromMetricsQueryAtPosition(text, pos).trim();
|
||||||
let keepAndDropParent: SyntaxNode | null = null;
|
let keepAndDropParent: SyntaxNode | null = null;
|
||||||
let parent = node.parent;
|
let parent = node.parent;
|
||||||
while (parent !== null) {
|
while (parent !== null) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
getNormalizedLokiQuery,
|
getNormalizedLokiQuery,
|
||||||
getNodePositionsFromQuery,
|
getNodePositionsFromQuery,
|
||||||
formatLogqlQuery,
|
formatLogqlQuery,
|
||||||
|
getLogQueryFromMetricsQueryAtPosition,
|
||||||
} from './queryUtils';
|
} from './queryUtils';
|
||||||
import { LokiQuery, LokiQueryType } from './types';
|
import { LokiQuery, LokiQueryType } from './types';
|
||||||
|
|
||||||
@@ -427,6 +428,39 @@ describe('getLogQueryFromMetricsQuery', () => {
|
|||||||
)
|
)
|
||||||
).toBe('{label="$var"} | logfmt | __error__=``');
|
).toBe('{label="$var"} | logfmt | __error__=``');
|
||||||
});
|
});
|
||||||
|
it('does not return a query when there is no log query', () => {
|
||||||
|
expect(getLogQueryFromMetricsQuery('1+1')).toBe('');
|
||||||
|
expect(getLogQueryFromMetricsQuery('count_over_time([1s])')).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getLogQueryFromMetricsQueryAtPosition', () => {
|
||||||
|
it('works like getLogQueryFromMetricsQuery for simple queries', () => {
|
||||||
|
expect(
|
||||||
|
getLogQueryFromMetricsQueryAtPosition('count_over_time({job="grafana"} | logfmt | label="value" [1m])', 57)
|
||||||
|
).toBe('{job="grafana"} | logfmt | label="value"');
|
||||||
|
expect(getLogQueryFromMetricsQueryAtPosition('count_over_time({job="grafana"} [1m])', 37)).toBe('{job="grafana"}');
|
||||||
|
expect(
|
||||||
|
getLogQueryFromMetricsQueryAtPosition(
|
||||||
|
'sum(quantile_over_time(0.5, {label="$var"} | logfmt | __error__=`` | unwrap latency | __error__=`` [$__interval]))',
|
||||||
|
45
|
||||||
|
)
|
||||||
|
).toBe('{label="$var"} | logfmt | __error__=``');
|
||||||
|
});
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
'count_over_time({place="moon"} | json test="test" [1m]) + avg_over_time({place="luna"} | logfmt test="test" [1m])',
|
||||||
|
'{place="moon"} | json test="test"',
|
||||||
|
49,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'count_over_time({place="moon"} | json test="test" [1m]) + avg_over_time({place="luna"} | logfmt test="test" [1m])',
|
||||||
|
'{place="luna"} | logfmt test="test"',
|
||||||
|
107,
|
||||||
|
],
|
||||||
|
])('gets the right query for complex queries', (metric: string, log: string, position: number) => {
|
||||||
|
expect(getLogQueryFromMetricsQueryAtPosition(metric, position)).toBe(log);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getNodePositionsFromQuery', () => {
|
describe('getNodePositionsFromQuery', () => {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ export function getLogQueryFromMetricsQuery(query: string): string {
|
|||||||
// Log query in metrics query composes of Selector & PipelineExpr
|
// Log query in metrics query composes of Selector & PipelineExpr
|
||||||
const selectorNode = getNodeFromQuery(query, Selector);
|
const selectorNode = getNodeFromQuery(query, Selector);
|
||||||
if (!selectorNode) {
|
if (!selectorNode) {
|
||||||
return query;
|
return '';
|
||||||
}
|
}
|
||||||
const selector = query.substring(selectorNode.from, selectorNode.to);
|
const selector = query.substring(selectorNode.from, selectorNode.to);
|
||||||
|
|
||||||
@@ -241,6 +241,20 @@ export function getLogQueryFromMetricsQuery(query: string): string {
|
|||||||
return `${selector} ${pipelineExpr}`.trim();
|
return `${selector} ${pipelineExpr}`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLogQueryFromMetricsQueryAtPosition(query: string, position: number): string {
|
||||||
|
if (isLogsQuery(query)) {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metricQuery = getNodesFromQuery(query, [MetricExpr])
|
||||||
|
.reverse() // So we don't get the root metric node
|
||||||
|
.find((node) => node.from <= position && node.to >= position);
|
||||||
|
if (!metricQuery) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return getLogQueryFromMetricsQuery(query.substring(metricQuery.from, metricQuery.to));
|
||||||
|
}
|
||||||
|
|
||||||
export function isQueryWithLabelFilter(query: string): boolean {
|
export function isQueryWithLabelFilter(query: string): boolean {
|
||||||
return isQueryWithNode(query, LabelFilter);
|
return isQueryWithNode(query, LabelFilter);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user