Loki Query Editor: Interpolate query before evaluating type and add variables support to ranged aggregation (#104035)
* LokiQueryBuilderOptions: interpolate query before evaluating * Query builder: parse variables in vector aggregation * Fix imports * Update public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com> * Add comment --------- Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
This commit is contained in:
co-authored by
Sven Grossmann
parent
b3b92e2471
commit
b2847f3b4d
@@ -213,8 +213,8 @@ export const LokiQueryEditor = memo<LokiQueryEditorProps>((props) => {
|
||||
onChange={onChange}
|
||||
onRunQuery={onRunQuery}
|
||||
app={app}
|
||||
maxLines={datasource.maxLines}
|
||||
queryStats={queryStats}
|
||||
datasource={props.datasource}
|
||||
/>
|
||||
</EditorRows>
|
||||
</>
|
||||
|
||||
+5
-1
@@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event';
|
||||
import { CoreApp, LogSortOrderChangeEvent, LogsSortOrder, store } from '@grafana/data';
|
||||
import { config, getAppEvents } from '@grafana/runtime';
|
||||
|
||||
import { createLokiDatasource } from '../../__mocks__/datasource';
|
||||
import { LokiQuery, LokiQueryDirection, LokiQueryType } from '../../types';
|
||||
|
||||
import { LokiQueryBuilderOptions, Props } from './LokiQueryBuilderOptions';
|
||||
@@ -275,6 +276,9 @@ describe('LokiQueryBuilderOptions', () => {
|
||||
});
|
||||
|
||||
function setup(queryOverrides: Partial<LokiQuery> = {}, onChange = jest.fn(), propOverrides: Partial<Props> = {}) {
|
||||
const datasource = createLokiDatasource();
|
||||
datasource.maxLines = 20;
|
||||
|
||||
const props = {
|
||||
query: {
|
||||
refId: 'A',
|
||||
@@ -283,7 +287,7 @@ function setup(queryOverrides: Partial<LokiQuery> = {}, onChange = jest.fn(), pr
|
||||
},
|
||||
onRunQuery: jest.fn(),
|
||||
onChange,
|
||||
maxLines: 20,
|
||||
datasource,
|
||||
queryStats: { streams: 0, chunks: 0, bytes: 0, entries: 0 },
|
||||
...propOverrides,
|
||||
};
|
||||
|
||||
+7
-3
@@ -20,6 +20,8 @@ import {
|
||||
queryDirections,
|
||||
queryTypeOptions,
|
||||
} from '../../components/LokiOptionFields';
|
||||
import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation';
|
||||
import { LokiDatasource } from '../../datasource';
|
||||
import { getLokiQueryType, isLogsQuery } from '../../queryUtils';
|
||||
import { LokiQuery, LokiQueryDirection, LokiQueryType, QueryStats } from '../../types';
|
||||
|
||||
@@ -27,14 +29,15 @@ export interface Props {
|
||||
query: LokiQuery;
|
||||
onChange: (update: LokiQuery) => void;
|
||||
onRunQuery: () => void;
|
||||
maxLines: number;
|
||||
app?: CoreApp;
|
||||
queryStats: QueryStats | null;
|
||||
datasource: LokiDatasource;
|
||||
}
|
||||
|
||||
export const LokiQueryBuilderOptions = React.memo<Props>(
|
||||
({ app, query, onChange, onRunQuery, maxLines, queryStats }) => {
|
||||
({ app, query, onChange, onRunQuery, queryStats, datasource }) => {
|
||||
const [splitDurationValid, setSplitDurationValid] = useState(true);
|
||||
const maxLines = datasource.maxLines;
|
||||
|
||||
useEffect(() => {
|
||||
if (app !== CoreApp.Explore && app !== CoreApp.Dashboard && app !== CoreApp.PanelEditor) {
|
||||
@@ -119,7 +122,8 @@ export const LokiQueryBuilderOptions = React.memo<Props>(
|
||||
}, [app, onQueryDirectionChange, query.direction]);
|
||||
|
||||
let queryType = getLokiQueryType(query);
|
||||
const isLogQuery = isLogsQuery(query.expr);
|
||||
const interpolatedQueries = datasource.interpolateVariablesInQueries([query], placeHolderScopedVars);
|
||||
const isLogQuery = isLogsQuery(interpolatedQueries[0]?.expr ?? '');
|
||||
const filteredQueryTypeOptions = isLogQuery
|
||||
? queryTypeOptions.filter((o) => o.value !== LokiQueryType.Instant)
|
||||
: queryTypeOptions;
|
||||
|
||||
@@ -634,6 +634,27 @@ describe('buildVisualQueryFromString', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('parses metrics query with vector aggregation with variable', () => {
|
||||
expect(
|
||||
buildVisualQueryFromString('topk($variable, sum by(unit) (count_over_time({app="frontend"}[$__auto])))')
|
||||
).toEqual(
|
||||
noErrors({
|
||||
labels: [
|
||||
{
|
||||
op: '=',
|
||||
value: 'frontend',
|
||||
label: 'app',
|
||||
},
|
||||
],
|
||||
operations: [
|
||||
{ id: LokiOperationId.CountOverTime, params: ['$__auto'] },
|
||||
{ id: LokiOperationId.SumBy, params: ['unit'] },
|
||||
{ id: LokiOperationId.TopK, params: ['$variable'] },
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('parses template variables in strings', () => {
|
||||
expect(buildVisualQueryFromString('{instance="$label_variable"}')).toEqual(
|
||||
noErrors({
|
||||
|
||||
@@ -526,9 +526,13 @@ function handleVectorAggregation(expr: string, node: SyntaxNode, context: Contex
|
||||
const params = [];
|
||||
|
||||
const numberNode = node.getChild(NumberLezer);
|
||||
const errorNode = node.getChild(ErrorId)?.getChild(Identifier);
|
||||
|
||||
if (numberNode) {
|
||||
params.push(Number(getString(expr, numberNode)));
|
||||
} else if (errorNode) {
|
||||
// Variables get parsed as errors, so the value us an identifier within an error node.
|
||||
params.push(getString(expr, errorNode));
|
||||
}
|
||||
|
||||
if (grouping) {
|
||||
|
||||
Reference in New Issue
Block a user