From 843d363d09c281ce7437b3f45da40ecd324767a4 Mon Sep 17 00:00:00 2001 From: Yury Molodov Date: Mon, 18 Nov 2024 16:43:55 +0100 Subject: [PATCH] vmui: fix rendering of raw data on the graph --- app/vmui/packages/vmui/src/api/types.ts | 2 +- .../components/Views/GraphView/GraphView.tsx | 2 +- .../RawQueryPage/hooks/useFetchExport.ts | 34 ++++++++++--------- .../vmui/src/pages/RawQueryPage/index.tsx | 6 +++- .../packages/vmui/src/utils/uplot/series.ts | 22 +++++++++++- docs/changelog/CHANGELOG.md | 1 + 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/app/vmui/packages/vmui/src/api/types.ts b/app/vmui/packages/vmui/src/api/types.ts index c495c829e7..1a7cdb27ca 100644 --- a/app/vmui/packages/vmui/src/api/types.ts +++ b/app/vmui/packages/vmui/src/api/types.ts @@ -15,7 +15,7 @@ export interface InstantMetricResult extends MetricBase { values?: [number, string][] } -export interface RawMetricResult extends MetricBase { +export interface ExportMetricResult extends MetricBase { values: number[]; timestamps: number[]; } diff --git a/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx b/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx index 05006a58e8..a7e5aa3095 100644 --- a/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx +++ b/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx @@ -180,7 +180,7 @@ const GraphView: FC = ({ if (isAnomalyView) { setHideSeries(legend.map(s => s.label || "").slice(1)); } - }, [data, timezone, isHistogram]); + }, [data, timezone, isHistogram, currentStep]); useEffect(() => { const tempLegend: LegendItemType[] = []; diff --git a/app/vmui/packages/vmui/src/pages/RawQueryPage/hooks/useFetchExport.ts b/app/vmui/packages/vmui/src/pages/RawQueryPage/hooks/useFetchExport.ts index d0f694dc78..8d9c61eb2d 100644 --- a/app/vmui/packages/vmui/src/pages/RawQueryPage/hooks/useFetchExport.ts +++ b/app/vmui/packages/vmui/src/pages/RawQueryPage/hooks/useFetchExport.ts @@ -1,5 +1,5 @@ import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from "preact/compat"; -import { MetricBase, MetricResult, RawMetricResult } from "../../../api/types"; +import { MetricBase, MetricResult, ExportMetricResult } from "../../../api/types"; import { ErrorTypes, SeriesLimits } from "../../../types"; import { useQueryState } from "../../../state/query/QueryStateContext"; import { useTimeState } from "../../../state/time/TimeStateContext"; @@ -24,7 +24,7 @@ interface FetchQueryReturn { abortFetch: () => void } -const parseLineToJSON = (line: string): RawMetricResult | null => { +const parseLineToJSON = (line: string): ExportMetricResult | null => { try { return JSON.parse(line); } catch (e) { @@ -74,6 +74,7 @@ export const useFetchExport = ({ hideQuery, showAllSeries }: FetchQueryParams): try { const tempData: MetricBase[] = []; const seriesLimit = showAllSeries ? Infinity : +stateSeriesLimits[displayType] || Infinity; + console.log(+stateSeriesLimits[displayType]); let counter = 1; let totalLength = 0; @@ -97,14 +98,16 @@ export const useFetchExport = ({ hideQuery, showAllSeries }: FetchQueryParams): setQueryErrors(prev => [...prev, ""]); const freeTempSize = seriesLimit - tempData.length; const lines = text.split("\n").filter(line => line); - const linesLimited = lines.slice(0, freeTempSize); - const responseData = linesLimited.map(parseLineToJSON).filter(line => line) as RawMetricResult[]; - const metricResult = responseData.map((d: RawMetricResult) => ({ - group: counter, - metric: d.metric, - values: d.values.map((value, index) => [(d.timestamps[index]/1000), value]), - })); - tempData.push(...metricResult); + const lineLimited = lines.slice(0, freeTempSize).sort(); + lineLimited.forEach((line: string) => { + const jsonLine = parseLineToJSON(line); + if (!jsonLine) return; + tempData.push({ + group: counter, + metric: jsonLine.metric, + values: jsonLine.values.map((value, index) => [(jsonLine.timestamps[index]/1000), value]), + } as MetricBase); + }); totalLength += lines.length; } @@ -130,12 +133,11 @@ export const useFetchExport = ({ hideQuery, showAllSeries }: FetchQueryParams): useEffect(() => { if (!fetchUrl?.length) return; - fetchData({ - fetchUrl, - stateSeriesLimits, - showAllSeries, - }); - return () => abortControllerRef.current?.abort(); + const timer = setTimeout(fetchData, 400, { fetchUrl, stateSeriesLimits, showAllSeries }); + return () => { + abortControllerRef.current?.abort(); + clearTimeout(timer); + }; }, [fetchUrl, stateSeriesLimits, showAllSeries]); return { diff --git a/app/vmui/packages/vmui/src/pages/RawQueryPage/index.tsx b/app/vmui/packages/vmui/src/pages/RawQueryPage/index.tsx index d9c5412090..9328adc245 100644 --- a/app/vmui/packages/vmui/src/pages/RawQueryPage/index.tsx +++ b/app/vmui/packages/vmui/src/pages/RawQueryPage/index.tsx @@ -81,9 +81,13 @@ const RawQueryPage: FC = () => {

This page provides a dedicated view for querying and displaying raw data directly from VictoriaMetrics. - Users often assume that the Query + Users often assume that the Query API returns data exactly as stored, but data samples and timestamps may be modified by the API. For more details, see How to export data in JSON line format diff --git a/app/vmui/packages/vmui/src/utils/uplot/series.ts b/app/vmui/packages/vmui/src/utils/uplot/series.ts index f28bde4fa7..c1f2489f96 100644 --- a/app/vmui/packages/vmui/src/utils/uplot/series.ts +++ b/app/vmui/packages/vmui/src/utils/uplot/series.ts @@ -185,7 +185,27 @@ const getPointsSeries = (metricInfo: ForecastMetricInfo | null): uPlotSeries.Poi if (isAnomalyMetric) { return { size: 8, width: 4, space: 0 }; } - return { size: 4.2, width: 1.4 }; + return { + size: 4, + width: 0, + show: true, + filter: filterPoints, + }; +}; + +const filterPoints = (self: uPlot, seriesIdx: number): number[] | null => { + const data = self.data[seriesIdx]; + const indices = []; + + for (let i = 0; i < data.length; i++) { + const prev = data[i - 1]; + const next = data[i + 1]; + if (prev === null && next === null) { + indices.push(i); + } + } + + return indices.length > 0 ? indices : null; }; type GetStrokeSeriesArgs = { diff --git a/docs/changelog/CHANGELOG.md b/docs/changelog/CHANGELOG.md index 8af46cf729..d42a6fca44 100644 --- a/docs/changelog/CHANGELOG.md +++ b/docs/changelog/CHANGELOG.md @@ -27,6 +27,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/). * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert): properly set `group_name` and `file` fields for recording rules in `/api/v1/rules`. * BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): prevent panic when ingesting samples which are outisde of configured [retention filters](https://docs.victoriametrics.com/#retention-filters). This could happen when backfilling data with retention filters which exclude samples from the backfill range. * BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): fix issue with series matching for `vmctl vm-native` with `--vm-native-disable-per-metric-migration` flag enabled. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7309). +* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix rendering of isolated data points on the graph that are not connected to other points. ## [v1.105.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.105.0)