Loki: Don't request stats with invalid query (#65287)

* fix: dont call endpoint if invalid query

* fix: use latest lezer-logql

* refactor: use null instead of undefined

* test: returns null when query is invalid

* update
This commit is contained in:
Gareth Dawson 2023-04-18 15:52:37 +01:00 committed by GitHub
parent 98c695c68f
commit 13c5aadd5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 28 additions and 15 deletions

View File

@ -34,7 +34,7 @@ export const LokiQueryEditor = React.memo<LokiQueryEditorProps>((props) => {
const [queryPatternsModalOpen, setQueryPatternsModalOpen] = useState(false);
const [dataIsStale, setDataIsStale] = useState(false);
const [labelBrowserVisible, setLabelBrowserVisible] = useState(false);
const [queryStats, setQueryStats] = useState<QueryStats>();
const [queryStats, setQueryStats] = useState<QueryStats | null>(null);
const { flag: explain, setFlag: setExplain } = useFlag(lokiQueryEditorExplainKey);
const timerange = datasource.getTimeRange();

View File

@ -9,8 +9,6 @@ import { selectors } from '@grafana/e2e-selectors';
import { languageConfiguration, monarchlanguage } from '@grafana/monaco-logql';
import { useTheme2, ReactMonacoEditor, Monaco, monacoTypes, MonacoEditor } from '@grafana/ui';
import { isValidQuery } from '../../queryUtils';
import { Props } from './MonacoQueryFieldProps';
import { getOverrideServices } from './getOverrideServices';
import { getCompletionProvider, getSuggestOptions } from './monaco-completion-provider';
@ -153,7 +151,7 @@ const MonacoQueryField = ({
};
const onTypeDebounced = debounce(async (query: string) => {
if (!onQueryType || (isValidQuery(query) === false && query !== '')) {
if (!onQueryType) {
return;
}

View File

@ -54,15 +54,20 @@ describe('shouldUpdateStats', () => {
describe('makeStatsRequest', () => {
const datasource = createLokiDatasource();
it('should return undefined if there is no query', () => {
it('should return null if there is no query', () => {
const query = '';
expect(getStats(datasource, query)).resolves.toBe(undefined); // change
expect(getStats(datasource, query)).resolves.toBe(null);
});
it('should return undefined if the response has no data', () => {
it('should return null if the query is invalid', () => {
const query = '{job="grafana",';
expect(getStats(datasource, query)).resolves.toBe(null);
});
it('should return null if the response has no data', () => {
const query = '{job="grafana"}';
datasource.getQueryStats = jest.fn().mockResolvedValue({ streams: 0, chunks: 0, bytes: 0, entries: 0 });
expect(getStats(datasource, query)).resolves.toBe(undefined);
expect(getStats(datasource, query)).resolves.toBe(null);
});
it('should return the stats if the response has data', () => {

View File

@ -3,13 +3,18 @@ import { DateTime, isDateTime, TimeRange } from '@grafana/data';
import { LokiDatasource } from '../datasource';
import { QueryStats } from '../types';
export async function getStats(datasource: LokiDatasource, query: string): Promise<QueryStats | undefined> {
export async function getStats(datasource: LokiDatasource, query: string): Promise<QueryStats | null> {
if (!query) {
return undefined;
return null;
}
const response = await datasource.getQueryStats(query);
return Object.values(response).every((v) => v === 0) ? undefined : response;
if (!response) {
return null;
}
return Object.values(response).every((v) => v === 0) ? null : response;
}
/**

View File

@ -419,7 +419,12 @@ export class LokiDatasource
return res.data ?? (res || []);
}
async getQueryStats(query: string): Promise<QueryStats> {
async getQueryStats(query: string): Promise<QueryStats | undefined> {
// if query is invalid, clear stats, and don't request
if (!isValidQuery(query)) {
return undefined;
}
const { start, end } = this.getTimeRangeParams();
const labelMatchers = getStreamSelectorsFromQuery(query);

View File

@ -18,7 +18,7 @@ export interface Props {
maxLines: number;
app?: CoreApp;
datasource: LokiDatasource;
queryStats: QueryStats | undefined;
queryStats: QueryStats | null;
}
export const LokiQueryBuilderOptions = React.memo<Props>(

View File

@ -14,7 +14,7 @@ import { LokiQueryBuilderExplained } from './LokiQueryBuilderExplained';
type Props = LokiQueryEditorProps & {
showExplain: boolean;
setQueryStats: React.Dispatch<React.SetStateAction<QueryStats | undefined>>;
setQueryStats: React.Dispatch<React.SetStateAction<QueryStats | null>>;
};
export function LokiQueryCodeEditor({

View File

@ -10,7 +10,7 @@ import { QueryStats } from 'app/plugins/datasource/loki/types';
export interface Props {
title: string;
collapsedInfo: string[];
queryStats?: QueryStats;
queryStats?: QueryStats | null;
children: React.ReactNode;
}