mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
vmui/logs: fix display of hits chart (#7167)
### Describe Your Changes Fixed the display of hits chart in VictoriaLogs. See #7133 ### Checklist The following checks are **mandatory**: - [ ] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/).
This commit is contained in:
parent
064b9a6314
commit
36a86c3aaf
4 changed files with 48 additions and 20 deletions
|
@ -1,4 +1,4 @@
|
||||||
import React, { FC, useMemo } from "preact/compat";
|
import React, { FC, useCallback, useMemo } from "preact/compat";
|
||||||
import "./style.scss";
|
import "./style.scss";
|
||||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -10,6 +10,7 @@ import BarHitsChart from "../../../components/Chart/BarHitsChart/BarHitsChart";
|
||||||
import Alert from "../../../components/Main/Alert/Alert";
|
import Alert from "../../../components/Main/Alert/Alert";
|
||||||
import { TimeParams } from "../../../types";
|
import { TimeParams } from "../../../types";
|
||||||
import LineLoader from "../../../components/Main/LineLoader/LineLoader";
|
import LineLoader from "../../../components/Main/LineLoader/LineLoader";
|
||||||
|
import { getHitsTimeParams } from "../../../utils/logs";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
query: string;
|
query: string;
|
||||||
|
@ -24,26 +25,43 @@ const ExploreLogsBarChart: FC<Props> = ({ logHits, period, error, isLoading, onA
|
||||||
const { isMobile } = useDeviceDetect();
|
const { isMobile } = useDeviceDetect();
|
||||||
const timeDispatch = useTimeDispatch();
|
const timeDispatch = useTimeDispatch();
|
||||||
|
|
||||||
const getXAxis = (timestamps: string[]): number[] => {
|
const getYAxes = (logHits: LogHits[], timestamps: number[]) => {
|
||||||
return (timestamps.map(t => t ? dayjs(t).unix() : null)
|
|
||||||
.filter(Boolean) as number[])
|
|
||||||
.sort((a, b) => a - b);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getYAxes = (logHits: LogHits[], timestamps: string[]) => {
|
|
||||||
return logHits.map(hits => {
|
return logHits.map(hits => {
|
||||||
return timestamps.map(t => {
|
const timestampValueMap = new Map();
|
||||||
const index = hits.timestamps.findIndex(ts => ts === t);
|
hits.timestamps.forEach((ts, idx) => {
|
||||||
return index === -1 ? null : hits.values[index] || null;
|
const unixTime = dayjs(ts).unix();
|
||||||
|
timestampValueMap.set(unixTime, hits.values[idx] || null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return timestamps.map(t => timestampValueMap.get(t) || null);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateTimestamps = useCallback((date: dayjs.Dayjs) => {
|
||||||
|
const result: number[] = [];
|
||||||
|
const { start, end, step } = getHitsTimeParams(period);
|
||||||
|
const stepsToFirstTimestamp = Math.ceil(start.diff(date, "milliseconds") / step);
|
||||||
|
let firstTimestamp = date.add(stepsToFirstTimestamp * step, "milliseconds");
|
||||||
|
|
||||||
|
// If the first timestamp is before 'start', set it to 'start'
|
||||||
|
if (firstTimestamp.isBefore(start)) {
|
||||||
|
firstTimestamp = start.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the total number of steps from 'firstTimestamp' to 'end'
|
||||||
|
const totalSteps = Math.floor(end.diff(firstTimestamp, "milliseconds") / step);
|
||||||
|
|
||||||
|
for (let i = 0; i <= totalSteps; i++) {
|
||||||
|
result.push(firstTimestamp.add(i * step, "milliseconds").unix());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, [period]);
|
||||||
|
|
||||||
const data = useMemo(() => {
|
const data = useMemo(() => {
|
||||||
if (!logHits.length) return [[], []] as AlignedData;
|
if (!logHits.length) return [[], []] as AlignedData;
|
||||||
const timestamps = Array.from(new Set(logHits.map(l => l.timestamps).flat()));
|
const xAxis = generateTimestamps(dayjs(logHits[0].timestamps[0]));
|
||||||
const xAxis = getXAxis(timestamps);
|
const yAxes = getYAxes(logHits, xAxis);
|
||||||
const yAxes = getYAxes(logHits, timestamps);
|
|
||||||
return [xAxis, ...yAxes] as AlignedData;
|
return [xAxis, ...yAxes] as AlignedData;
|
||||||
}, [logHits]);
|
}, [logHits]);
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,8 @@ import { useCallback, useMemo, useRef, useState } from "preact/compat";
|
||||||
import { getLogHitsUrl } from "../../../api/logs";
|
import { getLogHitsUrl } from "../../../api/logs";
|
||||||
import { ErrorTypes, TimeParams } from "../../../types";
|
import { ErrorTypes, TimeParams } from "../../../types";
|
||||||
import { LogHits } from "../../../api/types";
|
import { LogHits } from "../../../api/types";
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { LOGS_BARS_VIEW } from "../../../constants/logs";
|
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
|
import { getHitsTimeParams } from "../../../utils/logs";
|
||||||
|
|
||||||
export const useFetchLogHits = (server: string, query: string) => {
|
export const useFetchLogHits = (server: string, query: string) => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
@ -17,10 +16,7 @@ export const useFetchLogHits = (server: string, query: string) => {
|
||||||
const url = useMemo(() => getLogHitsUrl(server), [server]);
|
const url = useMemo(() => getLogHitsUrl(server), [server]);
|
||||||
|
|
||||||
const getOptions = (query: string, period: TimeParams, signal: AbortSignal) => {
|
const getOptions = (query: string, period: TimeParams, signal: AbortSignal) => {
|
||||||
const start = dayjs(period.start * 1000);
|
const { start, end, step } = getHitsTimeParams(period);
|
||||||
const end = dayjs(period.end * 1000);
|
|
||||||
const totalSeconds = end.diff(start, "milliseconds");
|
|
||||||
const step = Math.ceil(totalSeconds / LOGS_BARS_VIEW) || 1;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
signal,
|
signal,
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
|
import { TimeParams } from "../types";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { LOGS_BARS_VIEW } from "../constants/logs";
|
||||||
|
|
||||||
export const getStreamPairs = (value: string): string[] => {
|
export const getStreamPairs = (value: string): string[] => {
|
||||||
const pairs = /^{.+}$/.test(value) ? value.slice(1, -1).split(",") : [value];
|
const pairs = /^{.+}$/.test(value) ? value.slice(1, -1).split(",") : [value];
|
||||||
return pairs.filter(Boolean);
|
return pairs.filter(Boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getHitsTimeParams = (period: TimeParams) => {
|
||||||
|
const start = dayjs(period.start * 1000);
|
||||||
|
const end = dayjs(period.end * 1000);
|
||||||
|
const totalSeconds = end.diff(start, "milliseconds");
|
||||||
|
const step = Math.ceil(totalSeconds / LOGS_BARS_VIEW) || 1;
|
||||||
|
return { start, end, step };
|
||||||
|
};
|
||||||
|
|
|
@ -20,6 +20,8 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
|
||||||
* FEATURE: improve performance for [`top`](https://docs.victoriametrics.com/victorialogs/logsql/#top-pipe), [`uniq`](https://docs.victoriametrics.com/victorialogs/logsql/#uniq-pipe) and [`field_values`](https://docs.victoriametrics.com/victorialogs/logsql/#field_values-pipe) pipes on systems with many CPU cores when it is applied to [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) with big number of unique values. For example, `_time:1d | top 5 (user_id)` should be executed much faster when `user_id` field contains millions of unique values.
|
* FEATURE: improve performance for [`top`](https://docs.victoriametrics.com/victorialogs/logsql/#top-pipe), [`uniq`](https://docs.victoriametrics.com/victorialogs/logsql/#uniq-pipe) and [`field_values`](https://docs.victoriametrics.com/victorialogs/logsql/#field_values-pipe) pipes on systems with many CPU cores when it is applied to [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) with big number of unique values. For example, `_time:1d | top 5 (user_id)` should be executed much faster when `user_id` field contains millions of unique values.
|
||||||
* FEATURE: improve performance for [`field_names` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#field_names-pipe) when it is applied to logs with hundreds of [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
* FEATURE: improve performance for [`field_names` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#field_names-pipe) when it is applied to logs with hundreds of [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||||
|
|
||||||
|
* BUGFIX: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): fix display of hits chart. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7133).
|
||||||
|
|
||||||
## [v0.36.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v0.36.0-victorialogs)
|
## [v0.36.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v0.36.0-victorialogs)
|
||||||
|
|
||||||
Released at 2024-10-16
|
Released at 2024-10-16
|
||||||
|
|
Loading…
Reference in a new issue