vmui: add notification for non-matching queries (#4301)

vmui: add notification for non-matching queries (#4211)

https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4211
This commit is contained in:
Yury Molodov 2023-05-12 13:55:47 +02:00 committed by Aliaksandr Valialkin
parent ddc3f0c5c5
commit ff39df74d3
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
7 changed files with 64 additions and 3 deletions

View file

@ -20,3 +20,8 @@ export interface TracingData {
duration_msec: number; duration_msec: number;
children: TracingData[]; children: TracingData[];
} }
export interface QueryStats {
seriesFetched?: string;
resultLength?: number;
}

View file

@ -4,6 +4,9 @@ import { ErrorTypes } from "../../../types";
import TextField from "../../Main/TextField/TextField"; import TextField from "../../Main/TextField/TextField";
import Autocomplete from "../../Main/Autocomplete/Autocomplete"; import Autocomplete from "../../Main/Autocomplete/Autocomplete";
import "./style.scss"; import "./style.scss";
import { QueryStats } from "../../../api/types";
import Tooltip from "../../Main/Tooltip/Tooltip";
import { WarningIcon } from "../../Main/Icons";
export interface QueryEditorProps { export interface QueryEditorProps {
onChange: (query: string) => void; onChange: (query: string) => void;
@ -14,6 +17,7 @@ export interface QueryEditorProps {
oneLiner?: boolean; oneLiner?: boolean;
autocomplete: boolean; autocomplete: boolean;
error?: ErrorTypes | string; error?: ErrorTypes | string;
stats?: QueryStats;
options: string[]; options: string[];
label: string; label: string;
disabled?: boolean disabled?: boolean
@ -27,6 +31,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
onArrowDown, onArrowDown,
autocomplete, autocomplete,
error, error,
stats,
options, options,
label, label,
disabled = false disabled = false
@ -34,6 +39,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
const [openAutocomplete, setOpenAutocomplete] = useState(false); const [openAutocomplete, setOpenAutocomplete] = useState(false);
const autocompleteAnchorEl = useRef<HTMLDivElement>(null); const autocompleteAnchorEl = useRef<HTMLDivElement>(null);
const showSeriesFetchedWarning = stats?.seriesFetched === "0" && !stats.resultLength;
const handleSelect = (val: string) => { const handleSelect = (val: string) => {
onChange(val); onChange(val);
@ -90,6 +96,23 @@ const QueryEditor: FC<QueryEditorProps> = ({
onOpenAutocomplete={setOpenAutocomplete} onOpenAutocomplete={setOpenAutocomplete}
/> />
)} )}
{showSeriesFetchedWarning && (
<div className="vm-query-editor-warning">
<Tooltip
placement="bottom-right"
title={(
<span className="vm-query-editor-warning__tooltip">
{`No match!
This query hasn't selected any time series from database.
Either the requested metrics are missing in the database,
or there is a typo in series selector.`}
</span>
)}
>
<WarningIcon/>
</Tooltip>
</div>
)}
</div>; </div>;
}; };

View file

@ -1,9 +1,27 @@
@use "src/styles/variables" as *; @use "src/styles/variables" as *;
.vm-query-editor { .vm-query-editor {
position: relative;
&-autocomplete { &-autocomplete {
max-height: 300px; max-height: 300px;
overflow: auto; overflow: auto;
} }
&-warning {
position: absolute;
top: 50%;
right: $padding-global;
transform: translateY(-50%);
display: grid;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
color: $color-warning;
&__tooltip {
white-space: pre-line;
}
}
} }

View file

@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from "preact/compat"; import { useCallback, useEffect, useMemo, useState } from "preact/compat";
import { getQueryRangeUrl, getQueryUrl } from "../api/query-range"; import { getQueryRangeUrl, getQueryUrl } from "../api/query-range";
import { useAppState } from "../state/common/StateContext"; import { useAppState } from "../state/common/StateContext";
import { InstantMetricResult, MetricBase, MetricResult } from "../api/types"; import { InstantMetricResult, MetricBase, MetricResult, QueryStats } from "../api/types";
import { isValidHttpUrl } from "../utils/url"; import { isValidHttpUrl } from "../utils/url";
import { ErrorTypes, SeriesLimits } from "../types"; import { ErrorTypes, SeriesLimits } from "../types";
import debounce from "lodash.debounce"; import debounce from "lodash.debounce";
@ -28,9 +28,10 @@ interface FetchQueryReturn {
liveData?: InstantMetricResult[], liveData?: InstantMetricResult[],
error?: ErrorTypes | string, error?: ErrorTypes | string,
queryErrors: (ErrorTypes | string)[], queryErrors: (ErrorTypes | string)[],
queryStats: QueryStats[],
warning?: string, warning?: string,
traces?: Trace[], traces?: Trace[],
isHistogram: boolean, isHistogram: boolean
} }
interface FetchDataParams { interface FetchDataParams {
@ -62,6 +63,7 @@ export const useFetchQuery = ({
const [traces, setTraces] = useState<Trace[]>(); const [traces, setTraces] = useState<Trace[]>();
const [error, setError] = useState<ErrorTypes | string>(); const [error, setError] = useState<ErrorTypes | string>();
const [queryErrors, setQueryErrors] = useState<(ErrorTypes | string)[]>([]); const [queryErrors, setQueryErrors] = useState<(ErrorTypes | string)[]>([]);
const [queryStats, setQueryStats] = useState<QueryStats[]>([]);
const [warning, setWarning] = useState<string>(); const [warning, setWarning] = useState<string>();
const [fetchQueue, setFetchQueue] = useState<AbortController[]>([]); const [fetchQueue, setFetchQueue] = useState<AbortController[]>([]);
const [isHistogram, setIsHistogram] = useState(false); const [isHistogram, setIsHistogram] = useState(false);
@ -90,6 +92,7 @@ export const useFetchQuery = ({
const isHideQuery = hideQuery?.includes(counter - 1); const isHideQuery = hideQuery?.includes(counter - 1);
if (isHideQuery) { if (isHideQuery) {
setQueryErrors(prev => [...prev, ""]); setQueryErrors(prev => [...prev, ""]);
setQueryStats(prev => [...prev, {}]);
counter++; counter++;
continue; continue;
} }
@ -98,6 +101,10 @@ export const useFetchQuery = ({
const resp = await response.json(); const resp = await response.json();
if (response.ok) { if (response.ok) {
setQueryStats(prev => [...prev, {
...resp?.stats,
resultLength: resp.data.result.length,
}]);
setQueryErrors(prev => [...prev, ""]); setQueryErrors(prev => [...prev, ""]);
if (resp.trace) { if (resp.trace) {
@ -139,6 +146,7 @@ export const useFetchQuery = ({
const fetchUrl = useMemo(() => { const fetchUrl = useMemo(() => {
setError(""); setError("");
setQueryErrors([]); setQueryErrors([]);
setQueryStats([]);
const expr = predefinedQuery ?? query; const expr = predefinedQuery ?? query;
const displayChart = (display || displayType) === "chart"; const displayChart = (display || displayType) === "chart";
if (!period) return; if (!period) return;
@ -184,5 +192,5 @@ export const useFetchQuery = ({
setFetchQueue(fetchQueue.filter(f => !f.signal.aborted)); setFetchQueue(fetchQueue.filter(f => !f.signal.aborted));
}, [fetchQueue]); }, [fetchQueue]);
return { fetchUrl, isLoading, graphData, liveData, error, queryErrors, warning, traces, isHistogram }; return { fetchUrl, isLoading, graphData, liveData, error, queryErrors, queryStats, warning, traces, isHistogram };
}; };

View file

@ -14,9 +14,11 @@ import classNames from "classnames";
import { MouseEvent as ReactMouseEvent } from "react"; import { MouseEvent as ReactMouseEvent } from "react";
import { arrayEquals } from "../../../utils/array"; import { arrayEquals } from "../../../utils/array";
import useDeviceDetect from "../../../hooks/useDeviceDetect"; import useDeviceDetect from "../../../hooks/useDeviceDetect";
import { QueryStats } from "../../../api/types";
export interface QueryConfiguratorProps { export interface QueryConfiguratorProps {
errors: (ErrorTypes | string)[]; errors: (ErrorTypes | string)[];
stats: QueryStats[];
queryOptions: string[] queryOptions: string[]
onHideQuery: (queries: number[]) => void onHideQuery: (queries: number[]) => void
onRunQuery: () => void onRunQuery: () => void
@ -24,6 +26,7 @@ export interface QueryConfiguratorProps {
const QueryConfigurator: FC<QueryConfiguratorProps> = ({ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
errors, errors,
stats,
queryOptions, queryOptions,
onHideQuery, onHideQuery,
onRunQuery onRunQuery
@ -142,6 +145,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
autocomplete={autocomplete} autocomplete={autocomplete}
options={queryOptions} options={queryOptions}
error={errors[i]} error={errors[i]}
stats={stats[i]}
onArrowUp={createHandlerArrow(-1, i)} onArrowUp={createHandlerArrow(-1, i)}
onArrowDown={createHandlerArrow(1, i)} onArrowDown={createHandlerArrow(1, i)}
onEnter={handleRunQuery} onEnter={handleRunQuery}

View file

@ -49,6 +49,7 @@ const CustomPanel: FC = () => {
graphData, graphData,
error, error,
queryErrors, queryErrors,
queryStats,
warning, warning,
traces, traces,
isHistogram isHistogram
@ -115,6 +116,7 @@ const CustomPanel: FC = () => {
> >
<QueryConfigurator <QueryConfigurator
errors={!hideError ? queryErrors : []} errors={!hideError ? queryErrors : []}
stats={queryStats}
queryOptions={queryOptions} queryOptions={queryOptions}
onHideQuery={handleHideQuery} onHideQuery={handleHideQuery}
onRunQuery={handleRunQuery} onRunQuery={handleRunQuery}

View file

@ -48,6 +48,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add an ability to copy and execute queries listed at [top queries](https://docs.victoriametrics.com/#top-queries) page. Also make more human readable the query duration column. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4292) and [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4299). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add an ability to copy and execute queries listed at [top queries](https://docs.victoriametrics.com/#top-queries) page. Also make more human readable the query duration column. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4292) and [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4299).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): increase default font size for better readability. * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): increase default font size for better readability.
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): [cardinality explorer](https://docs.victoriametrics.com/#cardinality-explorer): return back a table with labels containing the highest number of unique label values. See [issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4213). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): [cardinality explorer](https://docs.victoriametrics.com/#cardinality-explorer): return back a table with labels containing the highest number of unique label values. See [issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4213).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add notification icon for queries that do not match any time series. A warning icon appears next to the query field when the executed query does not match any time series. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4211).
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): add `-s3StorageClass` command-line flag for setting the storage class for AWS S3 backups. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4164). Thanks to @justcompile for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4166). * FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): add `-s3StorageClass` command-line flag for setting the storage class for AWS S3 backups. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4164). Thanks to @justcompile for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4166).
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): store backup creation and completion time in `backup_complete.ignore` file of backup contents. This allows determining the exact timestamp when the backup was created and completed. * FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): store backup creation and completion time in `backup_complete.ignore` file of backup contents. This allows determining the exact timestamp when the backup was created and completed.
* FEATURE: [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager.html): add `created_at` field to the output of `/api/v1/backups` API and `vmbackupmanager backup list` command. See this [doc](https://docs.victoriametrics.com/vmbackupmanager.html#api-methods) for data format details. * FEATURE: [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager.html): add `created_at` field to the output of `/api/v1/backups` API and `vmbackupmanager backup list` command. See this [doc](https://docs.victoriametrics.com/vmbackupmanager.html#api-methods) for data format details.