mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-10 15:14:09 +00:00
vmui: update render logic for nested component (#2795)
* vmui: update render logic for nested component, avoid rerender, remove local storage usage for tracing flag * docs/url-examples.md: fix various documentation issues there * docs: add Troubleshooting doc This doc contains troubleshooting guides for typical problems with VictoriaMetrics. * docs/Troubleshooting.md: add troubleshooting guide for cluster instability * wip * wip Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
2a70a9296e
commit
67753cc6f0
17 changed files with 74 additions and 107 deletions
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "./static/css/main.7e6d0c89.css",
|
"main.css": "./static/css/main.7e6d0c89.css",
|
||||||
"main.js": "./static/js/main.645fe611.js",
|
"main.js": "./static/js/main.84a0d8f8.js",
|
||||||
"static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js",
|
"static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js",
|
||||||
"index.html": "./index.html"
|
"index.html": "./index.html"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.7e6d0c89.css",
|
"static/css/main.7e6d0c89.css",
|
||||||
"static/js/main.645fe611.js"
|
"static/js/main.84a0d8f8.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script src="./dashboards/index.js" type="module"></script><script defer="defer" src="./static/js/main.645fe611.js"></script><link href="./static/css/main.7e6d0c89.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script src="./dashboards/index.js" type="module"></script><script defer="defer" src="./static/js/main.84a0d8f8.js"></script><link href="./static/css/main.7e6d0c89.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.84a0d8f8.js
Normal file
2
app/vmselect/vmui/static/js/main.84a0d8f8.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -81,7 +81,7 @@ const CardinalityConfigurator: FC<CardinalityConfiguratorProps> = ({
|
||||||
onChange={onFocusLabelChange} />
|
onChange={onFocusLabelChange} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<FormControlLabel label="Enable autocomplete"
|
<FormControlLabel label="Autocomplete"
|
||||||
control={<BasicSwitch checked={autocomplete} onChange={onChangeAutocomplete}/>}
|
control={<BasicSwitch checked={autocomplete} onChange={onChangeAutocomplete}/>}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -32,17 +32,17 @@ const AdditionalSettings: FC = () => {
|
||||||
|
|
||||||
return <Box display="flex" alignItems="center">
|
return <Box display="flex" alignItems="center">
|
||||||
<Box>
|
<Box>
|
||||||
<FormControlLabel label="Enable autocomplete"
|
<FormControlLabel label="Autocomplete"
|
||||||
control={<BasicSwitch checked={autocomplete} onChange={onChangeAutocomplete}/>}
|
control={<BasicSwitch checked={autocomplete} onChange={onChangeAutocomplete}/>}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box ml={2}>
|
<Box ml={2}>
|
||||||
<FormControlLabel label="Enable cache"
|
<FormControlLabel label="Disable cache"
|
||||||
control={<BasicSwitch checked={!nocache} onChange={onChangeCache}/>}
|
control={<BasicSwitch checked={nocache} onChange={onChangeCache}/>}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box ml={2}>
|
<Box ml={2}>
|
||||||
<FormControlLabel label="Enable query tracing"
|
<FormControlLabel label="Trace query"
|
||||||
control={<BasicSwitch checked={isTracingEnabled} onChange={onChangeQueryTracing} />}
|
control={<BasicSwitch checked={isTracingEnabled} onChange={onChangeQueryTracing} />}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -18,7 +18,7 @@ import Trace from "./Trace/Trace";
|
||||||
|
|
||||||
const CustomPanel: FC = () => {
|
const CustomPanel: FC = () => {
|
||||||
|
|
||||||
const [tracingsData, setTracingData] = useState<Trace[]>([]);
|
const [tracesState, setTracesState] = useState<Trace[]>([]);
|
||||||
const {displayType, time: {period}, query, queryControls: {isTracingEnabled}} = useAppState();
|
const {displayType, time: {period}, query, queryControls: {isTracingEnabled}} = useAppState();
|
||||||
const { customStep, yaxis } = useGraphState();
|
const { customStep, yaxis } = useGraphState();
|
||||||
|
|
||||||
|
@ -38,24 +38,24 @@ const CustomPanel: FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const {queryOptions} = useFetchQueryOptions();
|
const {queryOptions} = useFetchQueryOptions();
|
||||||
const {isLoading, liveData, graphData, error, tracingData} = useFetchQuery({
|
const {isLoading, liveData, graphData, error, traces} = useFetchQuery({
|
||||||
visible: true,
|
visible: true,
|
||||||
customStep
|
customStep
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleTraceDelete = (tracingData: Trace) => {
|
const handleTraceDelete = (trace: Trace) => {
|
||||||
const updatedTracings = tracingsData.filter((data) => data.idValue !== tracingData.idValue);
|
const updatedTraces = tracesState.filter((data) => data.idValue !== trace.idValue);
|
||||||
setTracingData([...updatedTracings]);
|
setTracesState([...updatedTraces]);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tracingData) {
|
if (traces) {
|
||||||
setTracingData([...tracingsData, tracingData]);
|
setTracesState([...tracesState, ...traces]);
|
||||||
}
|
}
|
||||||
}, [tracingData]);
|
}, [traces]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTracingData([]);
|
setTracesState([]);
|
||||||
}, [displayType]);
|
}, [displayType]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -78,7 +78,7 @@ const CustomPanel: FC = () => {
|
||||||
{error && <Alert color="error" severity="error" sx={{whiteSpace: "pre-wrap", mt: 2}}>{error}</Alert>}
|
{error && <Alert color="error" severity="error" sx={{whiteSpace: "pre-wrap", mt: 2}}>{error}</Alert>}
|
||||||
{graphData && period && (displayType === "chart") && <>
|
{graphData && period && (displayType === "chart") && <>
|
||||||
{isTracingEnabled && <TracingsView
|
{isTracingEnabled && <TracingsView
|
||||||
tracingsData={tracingsData}
|
traces={tracesState}
|
||||||
onDeleteClick={handleTraceDelete}
|
onDeleteClick={handleTraceDelete}
|
||||||
/>}
|
/>}
|
||||||
<GraphView data={graphData} period={period} customStep={customStep} query={query} yaxis={yaxis}
|
<GraphView data={graphData} period={period} customStep={customStep} query={query} yaxis={yaxis}
|
||||||
|
@ -87,7 +87,7 @@ const CustomPanel: FC = () => {
|
||||||
{liveData && (displayType === "code") && <JsonView data={liveData}/>}
|
{liveData && (displayType === "code") && <JsonView data={liveData}/>}
|
||||||
{liveData && (displayType === "table") && <>
|
{liveData && (displayType === "table") && <>
|
||||||
{isTracingEnabled && <TracingsView
|
{isTracingEnabled && <TracingsView
|
||||||
tracingsData={tracingsData}
|
traces={tracesState}
|
||||||
onDeleteClick={handleTraceDelete}
|
onDeleteClick={handleTraceDelete}
|
||||||
/>}
|
/>}
|
||||||
<TableView data={liveData}/>
|
<TableView data={liveData}/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {FC} from "preact/compat";
|
import React, {FC, useState} from "preact/compat";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import ListItemText from "@mui/material/ListItemText";
|
||||||
|
@ -14,20 +14,28 @@ import Trace from "../Trace/Trace";
|
||||||
interface RecursiveProps {
|
interface RecursiveProps {
|
||||||
trace: Trace;
|
trace: Trace;
|
||||||
totalMsec: number;
|
totalMsec: number;
|
||||||
openLevels: Record<number, boolean>;
|
|
||||||
onChange: (level: number) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NestedNav: FC<RecursiveProps> = ({ trace, openLevels, totalMsec, onChange}) => {
|
interface OpenLevels {
|
||||||
const handleListClick = (traceID: number) => () => onChange(traceID);
|
[x: number]: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec}) => {
|
||||||
|
const [openLevels, setOpenLevels] = useState({} as OpenLevels);
|
||||||
|
|
||||||
|
const handleListClick = (level: number) => () => {
|
||||||
|
setOpenLevels((prevState:OpenLevels) => {
|
||||||
|
return {...prevState, [level]: !prevState[level]};
|
||||||
|
});
|
||||||
|
};
|
||||||
const hasChildren = trace.children && trace.children.length;
|
const hasChildren = trace.children && trace.children.length;
|
||||||
const progress = trace.duration / totalMsec * 100;
|
const progress = trace.duration / totalMsec * 100;
|
||||||
return (
|
return (
|
||||||
<Box sx={{ bgcolor: "rgba(201, 227, 246, 0.4)" }}>
|
<Box sx={{ bgcolor: "rgba(201, 227, 246, 0.4)" }}>
|
||||||
<ListItem onClick={handleListClick(trace.duration)} sx={!hasChildren ? {p:0, pl: 7} : {p:0}}>
|
<ListItem onClick={handleListClick(trace.idValue)} sx={!hasChildren ? {p:0, pl: 7} : {p:0}}>
|
||||||
<ListItemButton alignItems={"flex-start"} sx={{ pt: 0, pb: 0}}>
|
<ListItemButton alignItems={"flex-start"} sx={{ pt: 0, pb: 0}}>
|
||||||
{hasChildren ? <ListItemIcon>
|
{hasChildren ? <ListItemIcon>
|
||||||
{openLevels[trace.duration] ?
|
{openLevels[trace.idValue] ?
|
||||||
<ExpandLess fontSize={"large"} color={"info"} /> :
|
<ExpandLess fontSize={"large"} color={"info"} /> :
|
||||||
<AddCircleRoundedIcon fontSize={"large"} color={"info"} />}
|
<AddCircleRoundedIcon fontSize={"large"} color={"info"} />}
|
||||||
</ListItemIcon>: null}
|
</ListItemIcon>: null}
|
||||||
|
@ -43,15 +51,13 @@ const NestedNav: FC<RecursiveProps> = ({ trace, openLevels, totalMsec, onChange}
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<>
|
<>
|
||||||
<Collapse in={openLevels[trace.duration]} timeout="auto" unmountOnExit>
|
<Collapse in={openLevels[trace.idValue]} timeout="auto" unmountOnExit>
|
||||||
<List component="div" disablePadding sx={{ pl: 4 }}>
|
<List component="div" disablePadding sx={{ pl: 4 }}>
|
||||||
{hasChildren ?
|
{hasChildren ?
|
||||||
trace.children.map((trace) => <NestedNav
|
trace.children.map((trace) => <NestedNav
|
||||||
key={trace.duration}
|
key={trace.duration}
|
||||||
trace={trace}
|
trace={trace}
|
||||||
openLevels={openLevels}
|
|
||||||
totalMsec={totalMsec}
|
totalMsec={totalMsec}
|
||||||
onChange={onChange}
|
|
||||||
/>) : null}
|
/>) : null}
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
|
@ -1,33 +1,18 @@
|
||||||
import {TracingData} from "../../../api/types";
|
import {TracingData} from "../../../api/types";
|
||||||
|
|
||||||
|
let traceId = 0;
|
||||||
|
|
||||||
export default class Trace {
|
export default class Trace {
|
||||||
private readonly tracing: TracingData;
|
private readonly tracing: TracingData;
|
||||||
|
private readonly tracingChildren: Trace[];
|
||||||
private readonly query: string;
|
private readonly query: string;
|
||||||
private readonly id: number;
|
private readonly id: number;
|
||||||
constructor(tracingData: TracingData, query: string) {
|
constructor(tracingData: TracingData, query: string) {
|
||||||
this.tracing = tracingData;
|
this.tracing = tracingData;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.id = new Date().getTime();
|
this.id = traceId++;
|
||||||
}
|
const children = tracingData.children || [];
|
||||||
|
this.tracingChildren = children.map((x: TracingData) => new Trace(x, query));
|
||||||
recursiveMap(oldArray: TracingData[], callback: (tr: TracingData) => Trace, newArray: Trace[]): Trace[] {
|
|
||||||
if (!oldArray) return [];
|
|
||||||
//base case: check if there are any items left in the original array to process
|
|
||||||
if (oldArray && oldArray.length <= 0){
|
|
||||||
//if all items have been processed return the new array
|
|
||||||
return newArray;
|
|
||||||
} else {
|
|
||||||
//destructure the first item from old array and put remaining in a separate array
|
|
||||||
const [item, ...theRest] = oldArray;
|
|
||||||
// create an array of the current new array and the result of the current item and the callback function
|
|
||||||
const interimArray = [...newArray, callback(item)];
|
|
||||||
// return a recursive call to to map to process the next item.
|
|
||||||
return this.recursiveMap(theRest, callback, interimArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createTrace(traceData: TracingData) {
|
|
||||||
return new Trace(traceData, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get queryValue(): string {
|
get queryValue(): string {
|
||||||
|
@ -37,8 +22,7 @@ export default class Trace {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
get children(): Trace[] {
|
get children(): Trace[] {
|
||||||
const arr: Trace[] = [];
|
return this.tracingChildren;
|
||||||
return this.recursiveMap(this.tracing.children, this.createTrace, arr);
|
|
||||||
}
|
}
|
||||||
get message(): string {
|
get message(): string {
|
||||||
return this.tracing.message;
|
return this.tracing.message;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {FC, useState} from "preact/compat";
|
import React, {FC} from "preact/compat";
|
||||||
import List from "@mui/material/List";
|
import List from "@mui/material/List";
|
||||||
import NestedNav from "../NestedNav/NestedNav";
|
import NestedNav from "../NestedNav/NestedNav";
|
||||||
import Trace from "../Trace/Trace";
|
import Trace from "../Trace/Trace";
|
||||||
|
@ -7,23 +7,10 @@ interface TraceViewProps {
|
||||||
trace: Trace;
|
trace: Trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OpenLevels {
|
|
||||||
[x: number]: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const TraceView: FC<TraceViewProps> = ({trace}) => {
|
const TraceView: FC<TraceViewProps> = ({trace}) => {
|
||||||
|
|
||||||
const [openLevels, setOpenLevels] = useState({} as OpenLevels);
|
|
||||||
const handleClick = (level: number) => {
|
|
||||||
setOpenLevels((prevState:OpenLevels) => ({...prevState, [level]: !prevState[level]}));
|
|
||||||
};
|
|
||||||
return (<List sx={{ width: "100%" }} component="nav">
|
return (<List sx={{ width: "100%" }} component="nav">
|
||||||
<NestedNav
|
<NestedNav trace={trace} totalMsec={trace.duration} />
|
||||||
trace={trace}
|
|
||||||
openLevels={openLevels}
|
|
||||||
totalMsec={trace.duration}
|
|
||||||
onChange={handleClick}
|
|
||||||
/>
|
|
||||||
</List>);
|
</List>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,15 @@ import Button from "@mui/material/Button";
|
||||||
import Trace from "../Trace/Trace";
|
import Trace from "../Trace/Trace";
|
||||||
|
|
||||||
interface TraceViewProps {
|
interface TraceViewProps {
|
||||||
tracingsData: Trace[];
|
traces: Trace[];
|
||||||
onDeleteClick: (tracingData: Trace) => void;
|
onDeleteClick: (trace: Trace) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY_MESSAGE = "Please re-run the query to see results of the tracing";
|
const TracingsView: FC<TraceViewProps> = ({traces, onDeleteClick}) => {
|
||||||
|
if (!traces.length) {
|
||||||
const TracingsView: FC<TraceViewProps> = ({tracingsData, onDeleteClick}) => {
|
|
||||||
if (!tracingsData.length) {
|
|
||||||
return (
|
return (
|
||||||
<Alert color={"info"} severity="info" sx={{whiteSpace: "pre-wrap", mt: 2}}>
|
<Alert color={"info"} severity="info" sx={{whiteSpace: "pre-wrap", mt: 2}}>
|
||||||
{EMPTY_MESSAGE}
|
Please re-run the query to see results of the tracing
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -26,14 +24,14 @@ const TracingsView: FC<TraceViewProps> = ({tracingsData, onDeleteClick}) => {
|
||||||
onDeleteClick(tracingData);
|
onDeleteClick(tracingData);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <>{tracingsData.map((tracingData) => <>
|
return <>{traces.map((trace: Trace) => <>
|
||||||
<Typography variant="h4" gutterBottom component="div">
|
<Typography variant="h5" component="div">
|
||||||
{"Tracing for"} {tracingData.queryValue}
|
Trace for <b>{trace.queryValue}</b>
|
||||||
<Button onClick={handleDeleteClick(tracingData)}>
|
<Button onClick={handleDeleteClick(trace)}>
|
||||||
<RemoveCircleIcon fontSize={"large"} color={"error"} />
|
<RemoveCircleIcon fontSize={"medium"} color={"error"} />
|
||||||
</Button>
|
</Button>
|
||||||
</Typography>
|
</Typography>
|
||||||
<TraceView trace={tracingData} />
|
<TraceView trace={trace} />
|
||||||
</>)}</>;
|
</>)}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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, TracingData} from "../api/types";
|
import {InstantMetricResult, MetricBase, MetricResult} from "../api/types";
|
||||||
import {isValidHttpUrl} from "../utils/url";
|
import {isValidHttpUrl} from "../utils/url";
|
||||||
import {ErrorTypes} from "../types";
|
import {ErrorTypes} from "../types";
|
||||||
import {getAppModeEnable, getAppModeParams} from "../utils/app-mode";
|
import {getAppModeEnable, getAppModeParams} from "../utils/app-mode";
|
||||||
|
@ -28,14 +28,14 @@ export const useFetchQuery = ({predefinedQuery, visible, display, customStep}: F
|
||||||
graphData?: MetricResult[],
|
graphData?: MetricResult[],
|
||||||
liveData?: InstantMetricResult[],
|
liveData?: InstantMetricResult[],
|
||||||
error?: ErrorTypes | string,
|
error?: ErrorTypes | string,
|
||||||
tracingData?: Trace,
|
traces?: Trace[],
|
||||||
} => {
|
} => {
|
||||||
const {query, displayType, serverUrl, time: {period}, queryControls: {nocache, isTracingEnabled}} = useAppState();
|
const {query, displayType, serverUrl, time: {period}, queryControls: {nocache, isTracingEnabled}} = useAppState();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [graphData, setGraphData] = useState<MetricResult[]>();
|
const [graphData, setGraphData] = useState<MetricResult[]>();
|
||||||
const [liveData, setLiveData] = useState<InstantMetricResult[]>();
|
const [liveData, setLiveData] = useState<InstantMetricResult[]>();
|
||||||
const [tracingData, setTracingData] = useState<Trace>();
|
const [traces, setTraces] = useState<Trace[]>();
|
||||||
const [error, setError] = useState<ErrorTypes | string>();
|
const [error, setError] = useState<ErrorTypes | string>();
|
||||||
const [fetchQueue, setFetchQueue] = useState<AbortController[]>([]);
|
const [fetchQueue, setFetchQueue] = useState<AbortController[]>([]);
|
||||||
|
|
||||||
|
@ -43,33 +43,26 @@ export const useFetchQuery = ({predefinedQuery, visible, display, customStep}: F
|
||||||
if (error) {
|
if (error) {
|
||||||
setGraphData(undefined);
|
setGraphData(undefined);
|
||||||
setLiveData(undefined);
|
setLiveData(undefined);
|
||||||
setTracingData(undefined);
|
setTraces(undefined);
|
||||||
}
|
}
|
||||||
}, [error]);
|
}, [error]);
|
||||||
|
|
||||||
const updateTracingData = (tracing: TracingData, queries: string[]) => {
|
|
||||||
if (tracing) {
|
|
||||||
queries.forEach((query) => {
|
|
||||||
const {message} = tracing;
|
|
||||||
if (message.includes(query)) {
|
|
||||||
setTracingData(new Trace(tracing, query));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchData = async (fetchUrl: string[], fetchQueue: AbortController[], displayType: DisplayType, query: string[]) => {
|
const fetchData = async (fetchUrl: string[], fetchQueue: AbortController[], displayType: DisplayType, query: string[]) => {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
setFetchQueue([...fetchQueue, controller]);
|
setFetchQueue([...fetchQueue, controller]);
|
||||||
try {
|
try {
|
||||||
const responses = await Promise.all(fetchUrl.map(url => fetch(url, {signal: controller.signal})));
|
const responses = await Promise.all(fetchUrl.map(url => fetch(url, {signal: controller.signal})));
|
||||||
const tempData = [];
|
const tempData = [];
|
||||||
|
const tempTraces: Trace[] = [];
|
||||||
let counter = 1;
|
let counter = 1;
|
||||||
for await (const response of responses) {
|
for await (const response of responses) {
|
||||||
const resp = await response.json();
|
const resp = await response.json();
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
updateTracingData(resp.trace, query);
|
if (resp.trace) {
|
||||||
|
const trace = new Trace(resp.trace, query[counter-1]);
|
||||||
|
tempTraces.push(trace);
|
||||||
|
}
|
||||||
tempData.push(...resp.data.result.map((d: MetricBase) => {
|
tempData.push(...resp.data.result.map((d: MetricBase) => {
|
||||||
d.group = counter;
|
d.group = counter;
|
||||||
return d;
|
return d;
|
||||||
|
@ -80,6 +73,7 @@ export const useFetchQuery = ({predefinedQuery, visible, display, customStep}: F
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayType === "chart" ? setGraphData(tempData) : setLiveData(tempData);
|
displayType === "chart" ? setGraphData(tempData) : setLiveData(tempData);
|
||||||
|
setTraces(tempTraces);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error && e.name !== "AbortError") {
|
if (e instanceof Error && e.name !== "AbortError") {
|
||||||
setError(`${e.name}: ${e.message}`);
|
setError(`${e.name}: ${e.message}`);
|
||||||
|
@ -127,5 +121,5 @@ export const useFetchQuery = ({predefinedQuery, visible, display, customStep}: F
|
||||||
setFetchQueue(fetchQueue.filter(f => !f.signal.aborted));
|
setFetchQueue(fetchQueue.filter(f => !f.signal.aborted));
|
||||||
}, [fetchQueue]);
|
}, [fetchQueue]);
|
||||||
|
|
||||||
return {fetchUrl, isLoading, graphData, liveData, error, tracingData};
|
return {fetchUrl, isLoading, graphData, liveData, error, traces};
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,8 +80,8 @@ export const initialState: AppState = {
|
||||||
queryControls: {
|
queryControls: {
|
||||||
autoRefresh: false,
|
autoRefresh: false,
|
||||||
autocomplete: getFromStorage("AUTOCOMPLETE") as boolean || false,
|
autocomplete: getFromStorage("AUTOCOMPLETE") as boolean || false,
|
||||||
nocache: getFromStorage("NO_CACHE") as boolean || false,
|
nocache: false,
|
||||||
isTracingEnabled: getFromStorage("QUERY_TRACING") as boolean || false,
|
isTracingEnabled: false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ Prometheus doesn't drop data during VictoriaMetrics restart. See [this article](
|
||||||
|
|
||||||
VictoriaMetrics provides UI for query troubleshooting and exploration. The UI is available at `http://victoriametrics:8428/vmui`.
|
VictoriaMetrics provides UI for query troubleshooting and exploration. The UI is available at `http://victoriametrics:8428/vmui`.
|
||||||
The UI allows exploring query results via graphs and tables.
|
The UI allows exploring query results via graphs and tables.
|
||||||
It also provides the ability to [explore cardinality](#cardinality-explorer) and to [investigate query tracec](#query-tracing).
|
It also provides the ability to [explore cardinality](#cardinality-explorer) and to [investigate query traces](#query-tracing).
|
||||||
|
|
||||||
Graphs in vmui support scrolling and zooming:
|
Graphs in vmui support scrolling and zooming:
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ Query history can be navigated by holding `Ctrl` (or `Cmd` on MacOS) and pressin
|
||||||
|
|
||||||
Multi-line queries can be entered by pressing `Shift-Enter` in query input field.
|
Multi-line queries can be entered by pressing `Shift-Enter` in query input field.
|
||||||
|
|
||||||
When querying the [backfilled data](https://docs.victoriametrics.com/#backfilling), it may be useful disabling response cache by clicking `Enable cache` checkbox.
|
When querying the [backfilled data](https://docs.victoriametrics.com/#backfilling), it may be useful disabling response cache by clicking `Disable cache` checkbox.
|
||||||
|
|
||||||
VMUI automatically adjusts the interval between datapoints on the graph depending on the horizontal resolution and on the selected time range. The step value can be customized by clickhing `Override step value` checkbox.
|
VMUI automatically adjusts the interval between datapoints on the graph depending on the horizontal resolution and on the selected time range. The step value can be customized by clickhing `Override step value` checkbox.
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,7 @@ Prometheus doesn't drop data during VictoriaMetrics restart. See [this article](
|
||||||
|
|
||||||
VictoriaMetrics provides UI for query troubleshooting and exploration. The UI is available at `http://victoriametrics:8428/vmui`.
|
VictoriaMetrics provides UI for query troubleshooting and exploration. The UI is available at `http://victoriametrics:8428/vmui`.
|
||||||
The UI allows exploring query results via graphs and tables.
|
The UI allows exploring query results via graphs and tables.
|
||||||
It also provides the ability to [explore cardinality](#cardinality-explorer) and to [investigate query tracec](#query-tracing).
|
It also provides the ability to [explore cardinality](#cardinality-explorer) and to [investigate query traces](#query-tracing).
|
||||||
|
|
||||||
Graphs in vmui support scrolling and zooming:
|
Graphs in vmui support scrolling and zooming:
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ Query history can be navigated by holding `Ctrl` (or `Cmd` on MacOS) and pressin
|
||||||
|
|
||||||
Multi-line queries can be entered by pressing `Shift-Enter` in query input field.
|
Multi-line queries can be entered by pressing `Shift-Enter` in query input field.
|
||||||
|
|
||||||
When querying the [backfilled data](https://docs.victoriametrics.com/#backfilling), it may be useful disabling response cache by clicking `Enable cache` checkbox.
|
When querying the [backfilled data](https://docs.victoriametrics.com/#backfilling), it may be useful disabling response cache by clicking `Disable cache` checkbox.
|
||||||
|
|
||||||
VMUI automatically adjusts the interval between datapoints on the graph depending on the horizontal resolution and on the selected time range. The step value can be customized by clickhing `Override step value` checkbox.
|
VMUI automatically adjusts the interval between datapoints on the graph depending on the horizontal resolution and on the selected time range. The step value can be customized by clickhing `Override step value` checkbox.
|
||||||
|
|
||||||
|
|
|
@ -273,5 +273,3 @@ have enough free resources for graceful processing the increased workload.
|
||||||
See [capacity planning docs](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#capacity-planning)
|
See [capacity planning docs](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#capacity-planning)
|
||||||
and [cluster resizing and scalability docs](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#cluster-resizing-and-scalability)
|
and [cluster resizing and scalability docs](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#cluster-resizing-and-scalability)
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue