|
|
@@ -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;
|