diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index e61cb73150b..292290b1f0a 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -1362,13 +1362,14 @@ describe('LokiDatasource', () => { expect(ds.getSupplementaryRequest(SupplementaryQueryType.LogsVolume, options)).toBeDefined(); }); - it('does not create provider if there is only an instant logs query', () => { + it('does create provider if there is only an instant logs query', () => { + // we changed logic to automatically run logs queries as range queries, thus there's a provider now const options: DataQueryRequest = { ...baseRequestOptions, targets: [{ expr: '{label="value"', refId: 'A', queryType: LokiQueryType.Instant }], }; - expect(ds.getSupplementaryRequest(SupplementaryQueryType.LogsVolume, options)).not.toBeDefined(); + expect(ds.getSupplementaryRequest(SupplementaryQueryType.LogsVolume, options)).toBeDefined(); }); }); @@ -1454,7 +1455,8 @@ describe('LokiDatasource', () => { }); }); - it('does not return logs volume query for instant log query', () => { + it('does return logs volume query for instant log query', () => { + // we changed logic to automatically run logs queries as range queries, thus there's a volume query now expect( ds.getSupplementaryQuery( { type: SupplementaryQueryType.LogsVolume }, @@ -1464,7 +1466,13 @@ describe('LokiDatasource', () => { refId: 'A', } ) - ).toEqual(undefined); + ).toEqual({ + expr: 'sum by (level) (count_over_time({label="value"} | drop __error__[$__auto]))', + legendFormat: '{{ level }}', + queryType: 'range', + refId: 'log-volume-A', + supportingQueryType: 'logsVolume', + }); }); it('does not return logs volume query for metric query', () => { diff --git a/public/app/plugins/datasource/loki/module.test.ts b/public/app/plugins/datasource/loki/module.test.ts index 644bfd8818b..634a1a352fa 100644 --- a/public/app/plugins/datasource/loki/module.test.ts +++ b/public/app/plugins/datasource/loki/module.test.ts @@ -27,8 +27,7 @@ jest.mock('@grafana/runtime', () => { { datasource: { type: 'loki', uid: 'abc' }, editorMode: 'builder', - expr: '{place="$place"} |= `error`', - maxLines: 60, + expr: 'count_over_time({place="$place"} [5m])', queryType: 'instant', refId: 'A', }, @@ -77,11 +76,11 @@ describe('queriesOnInitDashboard', () => { org_id: 1, code_mode_queries_count: 2, instant_queries_count: 1, - logs_queries_count: 2, - metric_queries_count: 3, + logs_queries_count: 1, + metric_queries_count: 4, queries_count: 5, queries_with_changed_legend_count: 3, - queries_with_changed_line_limit_count: 2, + queries_with_changed_line_limit_count: 1, queries_with_changed_resolution_count: 0, queries_with_template_variables_count: 2, range_queries_count: 4, diff --git a/public/app/plugins/datasource/loki/queryUtils.test.ts b/public/app/plugins/datasource/loki/queryUtils.test.ts index 59512e3ba41..a4e09ff2bab 100644 --- a/public/app/plugins/datasource/loki/queryUtils.test.ts +++ b/public/app/plugins/datasource/loki/queryUtils.test.ts @@ -133,7 +133,7 @@ describe('getNormalizedLokiQuery', () => { it('removes deprecated instant property', () => { const input: LokiQuery = { refId: 'A', expr: 'test1', instant: true }; const output = getNormalizedLokiQuery(input); - expect(output).toStrictEqual({ refId: 'A', expr: 'test1', queryType: LokiQueryType.Instant }); + expect(output).toStrictEqual({ refId: 'A', expr: 'test1', queryType: LokiQueryType.Range }); }); it('removes deprecated range property', () => { diff --git a/public/app/plugins/datasource/loki/queryUtils.ts b/public/app/plugins/datasource/loki/queryUtils.ts index cf4320b19cb..45bb0870104 100644 --- a/public/app/plugins/datasource/loki/queryUtils.ts +++ b/public/app/plugins/datasource/loki/queryUtils.ts @@ -91,9 +91,16 @@ export function getStringsFromLineFilter(filter: SyntaxNode): SyntaxNode[] { } export function getNormalizedLokiQuery(query: LokiQuery): LokiQuery { - const queryType = getLokiQueryType(query); + let queryType = getLokiQueryType(query); // instant and range are deprecated, we want to remove them const { instant, range, ...rest } = query; + + // if `query.expr` is not parsable this might throw an error + try { + if (isLogsQuery(query.expr) && queryType === LokiQueryType.Instant) { + queryType = LokiQueryType.Range; + } + } catch (e) {} return { ...rest, queryType }; } @@ -200,7 +207,8 @@ export function isQueryWithError(query: string): boolean { } export function isLogsQuery(query: string): boolean { - return !isQueryWithNode(query, MetricExpr); + // As a safeguard we are checking for a length of 2, because at least the query should be `{}` + return query.trim().length > 2 && !isQueryWithNode(query, MetricExpr); } export function isQueryWithParser(query: string): { queryWithParser: boolean; parserCount: number } { diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx index fff5a79e352..e1154b21eef 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx @@ -151,6 +151,17 @@ describe('LokiQueryBuilderOptions', () => { await userEvent.click(screen.getByRole('button', { name: /Options/ })); expect(screen.queryByText(/Invalid step/)).not.toBeInTheDocument(); }); + + it('does not show instant type when using a log query', async () => { + setup({ expr: '{foo="bar"}', queryType: LokiQueryType.Instant }); + expect(screen.queryByText(/Instant/)).not.toBeInTheDocument(); + }); + + it('does not show instant type in the options when using a log query', async () => { + setup({ expr: '{foo="bar"}', step: '1m' }); + await userEvent.click(screen.getByRole('button', { name: /Options/ })); + expect(screen.queryByText(/Instant/)).not.toBeInTheDocument(); + }); }); function setup(queryOverrides: Partial = {}) { diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx index ec5ed3a8569..e7a974cd964 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx @@ -67,8 +67,17 @@ export const LokiQueryBuilderOptions = React.memo( onRunQuery(); } - const queryType = getLokiQueryType(query); + let queryType = getLokiQueryType(query); const isLogQuery = isLogsQuery(query.expr); + const filteredQueryTypeOptions = isLogQuery + ? queryTypeOptions.filter((o) => o.value !== LokiQueryType.Instant) + : queryTypeOptions; + + // if the state's queryType is still Instant, trigger a change to range for log queries + if (isLogQuery && queryType === LokiQueryType.Instant) { + onChange({ ...query, queryType: LokiQueryType.Range }); + queryType = LokiQueryType.Range; + } const isValidStep = useMemo(() => { if (!query.step || isValidGrafanaDuration(query.step) || !isNaN(Number(query.step))) { @@ -96,9 +105,11 @@ export const LokiQueryBuilderOptions = React.memo( onCommitChange={onLegendFormatChanged} /> - - - + {filteredQueryTypeOptions.length > 1 && ( + + + + )} {isLogQuery && (