Răsfoiți Sursa

Implemented refresh logic

jnfrati 4 ani în urmă
părinte
comite
a51c75a0eb

+ 222 - 172
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx

@@ -2,6 +2,7 @@ import React, {
   Component,
   useContext,
   useEffect,
+  useMemo,
   useRef,
   useState,
 } from "react";
@@ -35,18 +36,14 @@ const LogsFC: React.FC<{
   podError: string;
   rawText?: boolean;
 }> = ({ selectedPod, podError, rawText }) => {
-  const currentPodName = useRef<string>();
-
-  const { currentCluster, currentProject } = useContext(Context);
-  const [containers, setContainers] = useState<string[]>([]);
-  const [currentTab, setCurrentTab] = useState("");
-  const [logs, setLogs] = useState<{
-    [key: string]: Anser.AnserJsonEntry[][];
-  }>({});
-
-  const [prevLogs, setPrevLogs] = useState<{
-    [key: string]: Anser.AnserJsonEntry[][];
-  }>({});
+  const {
+    logs,
+    previousLogs,
+    containers,
+    currentContainer,
+    setCurrentContainer,
+    refresh,
+  } = useLogs(selectedPod);
 
   const [showPreviousLogs, setShowPreviousLogs] = useState<boolean>(false);
 
@@ -54,13 +51,6 @@ const LogsFC: React.FC<{
 
   const wrapperRef = useRef<HTMLDivElement>();
 
-  const {
-    newWebsocket,
-    openWebsocket,
-    closeAllWebsockets,
-    getWebsocket,
-  } = useWebsockets();
-
   const scrollToBottom = (smooth: boolean) => {
     if (!wrapperRef.current) {
       return;
@@ -81,147 +71,6 @@ const LogsFC: React.FC<{
     }
   };
 
-  const getSystemLogs = async () => {
-    const events = await api
-      .getPodEvents(
-        "<token>",
-        {},
-        {
-          name: selectedPod?.metadata?.name,
-          namespace: selectedPod?.metadata?.namespace,
-          cluster_id: currentCluster?.id,
-          id: currentProject?.id,
-        }
-      )
-      .then((res) => res.data);
-
-    let processedLogs = [] as Anser.AnserJsonEntry[][];
-
-    events.items.forEach((evt: any) => {
-      let ansiEvtType = evt.type == "Warning" ? "\u001b[31m" : "\u001b[32m";
-      let ansiLog = Anser.ansiToJson(
-        `${ansiEvtType}${evt.type}\u001b[0m \t \u001b[43m\u001b[34m\t${evt.reason} \u001b[0m \t ${evt.message}`
-      );
-      processedLogs.push(ansiLog);
-    });
-
-    // SET LOGS FOR SYSTEM
-    setLogs((prevState) => ({
-      ...prevState,
-      system: processedLogs,
-    }));
-  };
-
-  const getContainerPreviousLogs = async (containerName: string) => {
-    try {
-      const logs = await api
-        .getPreviousLogsForContainer<{ previous_logs: string[] }>(
-          "<token>",
-          {
-            container_name: containerName,
-          },
-          {
-            pod_name: selectedPod?.metadata?.name,
-            namespace: selectedPod?.metadata?.namespace,
-            cluster_id: currentCluster?.id,
-            project_id: currentProject?.id,
-          }
-        )
-        .then((res) => res.data);
-      // Process logs
-      const processedLogs: Anser.AnserJsonEntry[][] = logs.previous_logs.map(
-        (currentLog) => {
-          let ansiLog = Anser.ansiToJson(currentLog);
-          return ansiLog;
-        }
-      );
-
-      setPrevLogs((pl) => ({
-        ...pl,
-        [containerName]: processedLogs,
-      }));
-    } catch (error) {}
-  };
-
-  const setupWebsocket = (containerName: string, websocketKey: string) => {
-    if (!selectedPod?.metadata?.name) return;
-
-    const endpoint = `/api/projects/${currentProject.id}/clusters/${currentCluster.id}/namespaces/${selectedPod?.metadata?.namespace}/pod/${selectedPod?.metadata?.name}/logs?container_name=${containerName}`;
-
-    const config: NewWebsocketOptions = {
-      onopen: () => {
-        console.log("Opened websocket for container:", containerName);
-      },
-      onmessage: (evt: MessageEvent) => {
-        let ansiLog = Anser.ansiToJson(evt.data);
-        setLogs((logs) => {
-          const tmpLogs = { ...logs };
-          let containerLogs = tmpLogs[containerName] || [];
-
-          containerLogs.push(ansiLog);
-          // this is technically not as efficient as things could be
-          // if there are performance issues, a deque can be used in place of a list
-          // for storing logs
-          if (containerLogs.length > MAX_LOGS) {
-            containerLogs.shift();
-          }
-
-          return {
-            ...logs,
-            [containerName]: containerLogs,
-          };
-        });
-      },
-      onclose: () => {
-        console.log("Websocket closed for container:", containerName);
-      },
-    };
-
-    newWebsocket(websocketKey, endpoint, config);
-    openWebsocket(websocketKey);
-  };
-
-  useEffect(() => {
-    console.log("Selected pod updated");
-    if (selectedPod?.metadata?.name === currentPodName.current) {
-      return () => {
-        closeAllWebsockets();
-      };
-    }
-    currentPodName.current = selectedPod?.metadata?.name;
-    const currentContainers =
-      selectedPod?.spec?.containers?.map((container) => container?.name) || [];
-
-    setContainers(currentContainers);
-    setCurrentTab(currentContainers[0]);
-    return () => {
-      closeAllWebsockets();
-    };
-  }, [selectedPod]);
-
-  // Retrieve all previous logs for containers
-  useEffect(() => {
-    closeAllWebsockets();
-
-    setPrevLogs({});
-    setLogs({});
-
-    if (!Array.isArray(containers)) {
-      return;
-    }
-
-    getSystemLogs();
-    containers.forEach((containerName) => {
-      const websocketKey = `${currentPodName.current}-${containerName}-websocket`;
-
-      getContainerPreviousLogs(containerName);
-
-      if (!getWebsocket(websocketKey)) {
-        setupWebsocket(containerName, websocketKey);
-      }
-    });
-  }, [containers]);
-
   useEffect(() => {
     if (isScrollToBottomEnabled) {
       scrollToBottom(true);
@@ -247,10 +96,10 @@ const LogsFC: React.FC<{
 
     if (
       showPreviousLogs &&
-      Array.isArray(prevLogs[currentTab]) &&
-      prevLogs[currentTab].length
+      Array.isArray(previousLogs) &&
+      previousLogs.length
     ) {
-      return prevLogs[currentTab]?.map((log, i) => {
+      return previousLogs?.map((log, i) => {
         return (
           <Log key={i}>
             {log.map((ansi, j) => {
@@ -269,19 +118,19 @@ const LogsFC: React.FC<{
       });
     }
 
-    if (!Array.isArray(logs[currentTab]) || logs[currentTab]?.length === 0) {
+    if (!Array.isArray(logs) || logs?.length === 0) {
       return (
         <Message>
           No logs to display from this pod.
-          {/* <Highlight onClick={this.refreshLogs}>
+          <Highlight onClick={refresh}>
             <i className="material-icons">autorenew</i>
             Refresh
-          </Highlight> */}
+          </Highlight>
         </Message>
       );
     }
 
-    return logs[currentTab]?.map((log, i) => {
+    return logs?.map((log, i) => {
       return (
         <Log key={i}>
           {log.map((ansi, j) => {
@@ -309,9 +158,9 @@ const LogsFC: React.FC<{
             <Tab
               key={containerName}
               onClick={() => {
-                setCurrentTab(containerName);
+                setCurrentContainer(containerName);
               }}
-              clicked={currentTab === containerName}
+              clicked={currentContainer === containerName}
             >
               {arr.length > 1 ? containerName : "Application"}
             </Tab>
@@ -319,9 +168,9 @@ const LogsFC: React.FC<{
         })}
         <Tab
           onClick={() => {
-            setCurrentTab("system");
+            setCurrentContainer("system");
           }}
-          clicked={currentTab == "system"}
+          clicked={currentContainer == "system"}
         >
           System
         </Tab>
@@ -342,7 +191,7 @@ const LogsFC: React.FC<{
           />
           Scroll to Bottom
         </Scroll>
-        {Array.isArray(prevLogs[currentTab]) && prevLogs[currentTab].length && (
+        {Array.isArray(previousLogs) && previousLogs.length > 0 && (
           <Scroll
             onClick={() => {
               setShowPreviousLogs(!showPreviousLogs);
@@ -360,6 +209,7 @@ const LogsFC: React.FC<{
           onClick={() => {
             // this.refreshLogs();
             console.log("Refresh logs");
+            refresh();
           }}
         >
           <i className="material-icons">autorenew</i>
@@ -382,6 +232,206 @@ const LogsFC: React.FC<{
 
 export default LogsFC;
 
+const useLogs = (currentPod: SelectedPodType) => {
+  const currentPodName = useRef<string>();
+
+  const { currentCluster, currentProject } = useContext(Context);
+  const [containers, setContainers] = useState<string[]>([]);
+  const [currentContainer, setCurrentContainer] = useState<string>("");
+  const [logs, setLogs] = useState<{
+    [key: string]: Anser.AnserJsonEntry[][];
+  }>({});
+
+  const [prevLogs, setPrevLogs] = useState<{
+    [key: string]: Anser.AnserJsonEntry[][];
+  }>({});
+
+  const {
+    newWebsocket,
+    openWebsocket,
+    closeAllWebsockets,
+    getWebsocket,
+    closeWebsocket,
+  } = useWebsockets();
+
+  const getSystemLogs = async () => {
+    const events = await api
+      .getPodEvents(
+        "<token>",
+        {},
+        {
+          name: currentPod?.metadata?.name,
+          namespace: currentPod?.metadata?.namespace,
+          cluster_id: currentCluster?.id,
+          id: currentProject?.id,
+        }
+      )
+      .then((res) => res.data);
+
+    let processedLogs = [] as Anser.AnserJsonEntry[][];
+
+    events.items.forEach((evt: any) => {
+      let ansiEvtType = evt.type == "Warning" ? "\u001b[31m" : "\u001b[32m";
+      let ansiLog = Anser.ansiToJson(
+        `${ansiEvtType}${evt.type}\u001b[0m \t \u001b[43m\u001b[34m\t${evt.reason} \u001b[0m \t ${evt.message}`
+      );
+      processedLogs.push(ansiLog);
+    });
+
+    // SET LOGS FOR SYSTEM
+    setLogs((prevState) => ({
+      ...prevState,
+      system: processedLogs,
+    }));
+  };
+
+  const getContainerPreviousLogs = async (containerName: string) => {
+    try {
+      const logs = await api
+        .getPreviousLogsForContainer<{ previous_logs: string[] }>(
+          "<token>",
+          {
+            container_name: containerName,
+          },
+          {
+            pod_name: currentPod?.metadata?.name,
+            namespace: currentPod?.metadata?.namespace,
+            cluster_id: currentCluster?.id,
+            project_id: currentProject?.id,
+          }
+        )
+        .then((res) => res.data);
+      // Process logs
+      const processedLogs: Anser.AnserJsonEntry[][] = logs.previous_logs.map(
+        (currentLog) => {
+          let ansiLog = Anser.ansiToJson(currentLog);
+          return ansiLog;
+        }
+      );
+
+      setPrevLogs((pl) => ({
+        ...pl,
+        [containerName]: processedLogs,
+      }));
+    } catch (error) {}
+  };
+
+  const setupWebsocket = (containerName: string, websocketKey: string) => {
+    if (!currentPod?.metadata?.name) return;
+
+    const endpoint = `/api/projects/${currentProject.id}/clusters/${currentCluster.id}/namespaces/${currentPod?.metadata?.namespace}/pod/${currentPod?.metadata?.name}/logs?container_name=${containerName}`;
+
+    const config: NewWebsocketOptions = {
+      onopen: () => {
+        console.log("Opened websocket:", websocketKey);
+      },
+      onmessage: (evt: MessageEvent) => {
+        let ansiLog = Anser.ansiToJson(evt.data);
+        setLogs((logs) => {
+          const tmpLogs = { ...logs };
+          let containerLogs = tmpLogs[containerName] || [];
+
+          containerLogs.push(ansiLog);
+          // this is technically not as efficient as things could be
+          // if there are performance issues, a deque can be used in place of a list
+          // for storing logs
+          if (containerLogs.length > MAX_LOGS) {
+            containerLogs.shift();
+          }
+
+          return {
+            ...logs,
+            [containerName]: containerLogs,
+          };
+        });
+      },
+      onclose: () => {
+        console.log("Closed websocket:", websocketKey);
+      },
+    };
+
+    newWebsocket(websocketKey, endpoint, config);
+    openWebsocket(websocketKey);
+  };
+
+  const refresh = () => {
+    const websocketKey = `${currentPodName.current}-${currentContainer}-websocket`;
+    closeWebsocket(websocketKey);
+
+    setPrevLogs((prev) => ({ ...prev, [currentContainer]: [] }));
+    setLogs((prev) => ({ ...prev, [currentContainer]: [] }));
+
+    if (!Array.isArray(containers)) {
+      return;
+    }
+
+    if (currentContainer === "system") {
+      getSystemLogs();
+    } else {
+      getContainerPreviousLogs(currentContainer);
+      setupWebsocket(currentContainer, websocketKey);
+    }
+  };
+
+  useEffect(() => {
+    console.log("Selected pod updated");
+    if (currentPod?.metadata?.name === currentPodName.current) {
+      return () => {
+        closeAllWebsockets();
+      };
+    }
+    currentPodName.current = currentPod?.metadata?.name;
+    const currentContainers =
+      currentPod?.spec?.containers?.map((container) => container?.name) || [];
+
+    setContainers(currentContainers);
+    setCurrentContainer(currentContainers[0]);
+    return () => {
+      closeAllWebsockets();
+    };
+  }, [currentPod]);
+
+  // Retrieve all previous logs for containers
+  useEffect(() => {
+    closeAllWebsockets();
+
+    setPrevLogs({});
+    setLogs({});
+
+    if (!Array.isArray(containers)) {
+      return;
+    }
+
+    getSystemLogs();
+    containers.forEach((containerName) => {
+      const websocketKey = `${currentPodName.current}-${containerName}-websocket`;
+
+      getContainerPreviousLogs(containerName);
+
+      if (!getWebsocket(websocketKey)) {
+        setupWebsocket(containerName, websocketKey);
+      }
+    });
+  }, [containers]);
+
+  const currentLogs = useMemo(() => {
+    return logs[currentContainer] || [];
+  }, [currentContainer, logs]);
+
+  const currentPreviousLogs = useMemo(() => {
+    return prevLogs[currentContainer] || [];
+  }, [currentContainer, prevLogs]);
+
+  return {
+    containers,
+    currentContainer,
+    setCurrentContainer,
+    logs: currentLogs,
+    previousLogs: currentPreviousLogs,
+    refresh,
+  };
+};
+
 const Highlight = styled.div`
   display: flex;
   align-items: center;

+ 2 - 1
dashboard/src/shared/hooks/useWebsockets.ts

@@ -99,7 +99,7 @@ export const useWebsockets = () => {
   /**
    * Close specific websocket
    */
-  const closeWebsocket = (id: string, code?: number, reason?: string) => {
+  const closeWebsocket = (id: string, code: number =  4000, reason: string = "User closed the websocket connection") => {
     const ws = websocketMap.current[id];
 
     if (!ws) {
@@ -108,6 +108,7 @@ export const useWebsockets = () => {
     }
 
     ws.close(code, reason);
+    websocketMap.current[id] = null;
   };
 
   /**