diff --git a/web-app/package.json b/web-app/package.json
index c258abdebc..f0793238ef 100644
--- a/web-app/package.json
+++ b/web-app/package.json
@@ -22,6 +22,7 @@
"react-pdf": "7.7.1",
"react-redux": "^8.1.3",
"react-router-dom": "6.22.3",
+ "react-use-websocket": "^4.8.1",
"react-virtualized": "^9.22.5",
"react-window": "^1.8.10",
"react-window-infinite-loader": "^1.0.9",
diff --git a/web-app/src/screens/Console/Trace/Trace.tsx b/web-app/src/screens/Console/Trace/Trace.tsx
index 4bc7528f7c..1bcf83d96e 100644
--- a/web-app/src/screens/Console/Trace/Trace.tsx
+++ b/web-app/src/screens/Console/Trace/Trace.tsx
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { Fragment, useEffect, useState } from "react";
+import { Fragment, useEffect, useState } from "react";
import { DateTime } from "luxon";
import { useSelector } from "react-redux";
import {
@@ -41,8 +41,7 @@ import { setHelpName } from "../../../systemSlice";
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
import HelpMenu from "../HelpMenu";
-
-var socket: any = null;
+import useWebSocket, { ReadyState } from "react-use-websocket";
const Trace = () => {
const dispatch = useAppDispatch();
@@ -65,68 +64,82 @@ const Trace = () => {
const [errors, setErrors] = useState(false);
const [toggleFilter, setToggleFilter] = useState(false);
+ const [logActive, setLogActive] = useState(false);
+ const [wsUrl, setWsUrl] = useState("");
- const startTrace = () => {
- dispatch(traceResetMessages());
+ useEffect(() => {
const url = new URL(window.location.toString());
- const isDev = process.env.NODE_ENV === "development";
- const port = isDev ? "9090" : url.port;
-
- let calls = `${s3 ? "s3," : ""}${internal ? "internal," : ""}${
- storage ? "storage," : ""
- }${os ? "os," : ""}`;
+ const wsProt = wsProtocol(url.protocol);
+ const port = process.env.NODE_ENV === "development" ? "9090" : url.port;
+ const calls = all
+ ? "all"
+ : (() => {
+ const c = [];
+ if (s3) c.push("s3");
+ if (internal) c.push("internal");
+ if (storage) c.push("storage");
+ if (os) c.push("os");
+ return c.join(",");
+ })();
- if (all) {
- calls = "all";
- }
// check if we are using base path, if not this always is `/`
- const baseLocation = new URL(document.baseURI);
- const baseUrl = baseLocation.pathname;
+ const baseLocation = new URL(document.baseURI).pathname;
- const wsProt = wsProtocol(url.protocol);
- socket = new WebSocket(
- `${wsProt}://${
- url.hostname
- }:${port}${baseUrl}ws/trace?calls=${calls}&threshold=${threshold}&onlyErrors=${
- errors ? "yes" : "no"
- }&statusCode=${statusCode}&method=${method}&funcname=${func}&path=${path}`,
+ const wsUrl = new URL(
+ `${wsProt}://${url.hostname}:${port}${baseLocation}ws/trace`,
);
+ wsUrl.searchParams.append("calls", calls);
+ wsUrl.searchParams.append("threshold", threshold.toString());
+ wsUrl.searchParams.append("onlyErrors", errors ? "yes" : "no");
+ wsUrl.searchParams.append("statusCode", statusCode);
+ wsUrl.searchParams.append("method", method);
+ wsUrl.searchParams.append("funcname", func);
+ wsUrl.searchParams.append("path", path);
+ setWsUrl(wsUrl.href);
+ }, [
+ all,
+ s3,
+ internal,
+ storage,
+ os,
+ threshold,
+ errors,
+ statusCode,
+ method,
+ func,
+ path,
+ ]);
- let interval: any | null = null;
- if (socket !== null) {
- socket.onopen = () => {
- console.log("WebSocket Client Connected");
- dispatch(setTraceStarted(true));
- socket.send("ok");
- interval = setInterval(() => {
- socket.send("ok");
- }, 10 * 1000);
- };
- socket.onmessage = (message: MessageEvent) => {
- let m: TraceMessage = JSON.parse(message.data.toString());
+ const { sendMessage, lastJsonMessage, readyState } =
+ useWebSocket(
+ wsUrl,
+ {
+ heartbeat: {
+ message: "ok",
+ interval: 10 * 1000, // send ok every 10 seconds
+ timeout: 365 * 24 * 60 * 60 * 1000, // disconnect after 365 days (workaround, because heartbeat gets no response)
+ },
+ },
+ logActive,
+ );
- m.ptime = DateTime.fromISO(m.time).toJSDate();
- m.key = Math.random();
- dispatch(traceMessageReceived(m));
- };
- socket.onclose = () => {
- clearInterval(interval);
- console.log("connection closed by server");
- dispatch(setTraceStarted(false));
- };
- return () => {
- socket.close(1000);
- clearInterval(interval);
- console.log("closing websockets");
- setTraceStarted(false);
- };
+ useEffect(() => {
+ if (readyState === ReadyState.CONNECTING) {
+ dispatch(traceResetMessages());
+ } else if (readyState === ReadyState.OPEN) {
+ dispatch(setTraceStarted(true));
+ } else if (readyState === ReadyState.CLOSED) {
+ dispatch(setTraceStarted(false));
}
- };
+ }, [readyState, dispatch, sendMessage]);
- const stopTrace = () => {
- socket.close(1000);
- dispatch(setTraceStarted(false));
- };
+ useEffect(() => {
+ if (lastJsonMessage) {
+ lastJsonMessage.ptime = DateTime.fromISO(lastJsonMessage.time).toJSDate();
+ lastJsonMessage.key = Math.random();
+ dispatch(traceMessageReceived(lastJsonMessage));
+ }
+ }, [lastJsonMessage, dispatch]);
useEffect(() => {
dispatch(setHelpName("trace"));
@@ -187,9 +200,7 @@ const Trace = () => {
id={"all_calls"}
name={"all_calls"}
label={"All"}
- onChange={() => {
- setAll(!all);
- }}
+ onChange={() => setAll(!all)}
value={"all"}
disabled={traceStarted}
/>
@@ -198,9 +209,7 @@ const Trace = () => {
id={"s3_calls"}
name={"s3_calls"}
label={"S3"}
- onChange={() => {
- setS3(!s3);
- }}
+ onChange={() => setS3(!s3)}
value={"s3"}
disabled={all || traceStarted}
/>
@@ -209,9 +218,7 @@ const Trace = () => {
id={"internal_calls"}
name={"internal_calls"}
label={"Internal"}
- onChange={() => {
- setInternal(!internal);
- }}
+ onChange={() => setInternal(!internal)}
value={"internal"}
disabled={all || traceStarted}
/>
@@ -220,9 +227,7 @@ const Trace = () => {
id={"storage_calls"}
name={"storage_calls"}
label={"Storage"}
- onChange={() => {
- setStorage(!storage);
- }}
+ onChange={() => setStorage(!storage)}
value={"storage"}
disabled={all || traceStarted}
/>
@@ -231,9 +236,7 @@ const Trace = () => {
id={"os_calls"}
name={"os_calls"}
label={"OS"}
- onChange={() => {
- setOS(!os);
- }}
+ onChange={() => setOS(!os)}
value={"os"}
disabled={all || traceStarted}
/>
@@ -249,9 +252,7 @@ const Trace = () => {