diff --git a/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx b/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx index e0cbfa1ae3a..3d92c36c7dc 100644 --- a/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx +++ b/libs/pages/logs/environment/src/lib/feature/pod-logs-feature/pod-logs-feature.tsx @@ -1,5 +1,5 @@ import { Log } from 'qovery-typescript-axios' -import { useCallback, useContext, useEffect, useState } from 'react' +import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import useWebSocket from 'react-use-websocket' @@ -22,11 +22,15 @@ export function PodLogsFeature(props: PodLogsFeatureProps) { const { updateServiceId } = useContext(ServiceStageIdsContext) const [loadingStatus, setLoadingStatus] = useState('not loaded') + const [messageChunks, setMessageChunks] = useState([]) + const [messageNGINXChunks, setMessageNGINXChunks] = useState([]) const [logs, setLogs] = useState([]) - const [pauseLogs, setPauseLogs] = useState([]) const [nginxLogs, setNginxLogs] = useState([]) const [pauseStatusLogs, setPauseStatusLogs] = useState(false) const [enabledNginx, setEnabledNginx] = useState(false) + const chunkSize = 500 + const [debounceTime] = useState(500) + const logCounter = useRef(0) const application = useSelector((state) => selectApplicationById(state, serviceId) @@ -51,34 +55,68 @@ export function PodLogsFeature(props: PodLogsFeatureProps) { return new Promise((resolve) => resolve(url)) }, [organizationId, clusterId, projectId, environmentId, serviceId, getAccessTokenSilently]) - useWebSocket(applicationLogsUrl, { - onMessage: (message) => { - setLoadingStatus('loaded') - - if (pauseStatusLogs) { - setPauseLogs((prev: Log[]) => [...prev, JSON.parse(message?.data)]) + const onMessageHandler = useCallback((message: MessageEvent) => { + setMessageChunks((prevChunks) => { + const lastChunk = prevChunks[prevChunks.length - 1] || [] + if (lastChunk.length < chunkSize) { + return [...prevChunks.slice(0, -1), [...lastChunk, { ...JSON.parse(message?.data), id: logCounter.current++ }]] } else { - setLogs((prev: Log[]) => [...prev, ...pauseLogs, JSON.parse(message?.data)]) - setPauseLogs([]) + return [...prevChunks, [{ ...JSON.parse(message?.data), id: logCounter.current++ }]] } - }, + }) + }, []) + + const onNginxMessageHandler = useCallback((message: MessageEvent) => { + setMessageNGINXChunks((prevChunks) => { + const lastChunk = prevChunks[prevChunks.length - 1] || [] + if (lastChunk.length < chunkSize) { + return [...prevChunks.slice(0, -1), [...lastChunk, { ...JSON.parse(message?.data), id: logCounter.current++ }]] + } else { + return [...prevChunks, [{ ...JSON.parse(message?.data), id: logCounter.current++ }]] + } + }) + }, []) + useWebSocket(applicationLogsUrl, { + onMessage: onMessageHandler, }) useWebSocket( nginxLogsUrl, { - onMessage: (message) => { - if (pauseStatusLogs) { - setPauseLogs((prev: Log[]) => [...prev, JSON.parse(message?.data)]) - } else { - setNginxLogs((prev: Log[]) => [...prev, ...pauseLogs, JSON.parse(message?.data)]) - setPauseLogs([]) - } - }, + onMessage: onNginxMessageHandler, }, enabledNginx ) + useEffect(() => { + if (messageChunks.length === 0 || pauseStatusLogs) return + const timerId = setTimeout(() => { + setLoadingStatus('loaded') + if (!pauseStatusLogs) { + setMessageChunks((prevChunks) => prevChunks.slice(1)) + setLogs((prevLogs) => [...prevLogs, ...messageChunks[0]]) + } + }, debounceTime) + + return () => { + clearTimeout(timerId) + } + }, [messageChunks, pauseStatusLogs, debounceTime]) + + useEffect(() => { + if (messageNGINXChunks.length === 0 || pauseStatusLogs) return + const timerId = setTimeout(() => { + if (!pauseStatusLogs) { + setMessageNGINXChunks((prevChunks) => prevChunks.slice(1)) + setNginxLogs((prevLogs) => [...prevLogs, ...messageNGINXChunks[0]]) + } + }, debounceTime) + + return () => { + clearTimeout(timerId) + } + }, [messageNGINXChunks, pauseStatusLogs, debounceTime]) + // update serviceId useEffect(() => { updateServiceId(serviceId) @@ -87,17 +125,19 @@ export function PodLogsFeature(props: PodLogsFeatureProps) { // reset pod logs useEffect(() => { setLogs([]) - setPauseLogs([]) + setMessageChunks([]) setPauseStatusLogs(false) setLoadingStatus('not loaded') setNginxLogs([]) + setMessageNGINXChunks([]) setEnabledNginx && setEnabledNginx(false) }, [serviceId, setEnabledNginx]) - const logsSorted = - enabledNginx && nginxLogs + const logsSorted = useMemo(() => { + return enabledNginx && nginxLogs ? [...logs, ...nginxLogs].sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()) : logs + }, [enabledNginx, nginxLogs, logs]) return ( ([]) + const chunkSize = 500 + const [debounceTime, setDebounceTime] = useState(1000) const [logs, setLogs] = useState([]) - const [pauseLogs, setPauseLogs] = useState([]) const [pauseStatusLogs, setPauseStatusLogs] = useState(false) const [loadingStatusDeploymentLogs, setLoadingStatusDeploymentLogs] = useState('not loaded') @@ -88,18 +90,39 @@ export function PageEnvironmentLogs() { const newLog = JSON.parse(message?.data) - if (pauseStatusLogs) { - setPauseLogs((prev: EnvironmentLogs[]) => [...prev, ...newLog]) - } else { - setLogs((prev: EnvironmentLogs[]) => { - // return unique log by timestamp - return [...new Map([...prev, ...pauseLogs, ...newLog].map((item) => [item['timestamp'], item])).values()] - }) - setPauseLogs([]) - } + setMessageChunks((prevChunks) => { + const lastChunk = prevChunks[prevChunks.length - 1] || [] + if (lastChunk.length < chunkSize) { + return [...prevChunks.slice(0, -1), [...lastChunk, ...newLog]] + } else { + return [...prevChunks, [...newLog]] + } + }) }, }) + useEffect(() => { + if (messageChunks.length === 0 || pauseStatusLogs) return + + const timerId = setTimeout(() => { + if (!pauseStatusLogs) { + setMessageChunks((prevChunks) => prevChunks.slice(1)) + setLogs((prevLogs) => { + const combinedLogs = [...prevLogs, ...messageChunks[0]] + return [...new Map(combinedLogs.map((item) => [item['timestamp'], item])).values()] + }) + + if (logs.length > 1000) { + setDebounceTime(100) + } + } + }, debounceTime) + + return () => { + clearTimeout(timerId) + } + }, [messageChunks, pauseStatusLogs]) + return (
@@ -129,13 +152,13 @@ export function PageEnvironmentLogs() {
-

+

Please select a service on the left menu to access its deployment logs or live logs.

You can access the deployment logs only for the services recently deployed ( in purple).

-

+
)} diff --git a/libs/pages/logs/environment/src/lib/ui/pod-logs/pod-logs.tsx b/libs/pages/logs/environment/src/lib/ui/pod-logs/pod-logs.tsx index 804f01917d0..9ecec200f5d 100644 --- a/libs/pages/logs/environment/src/lib/ui/pod-logs/pod-logs.tsx +++ b/libs/pages/logs/environment/src/lib/ui/pod-logs/pod-logs.tsx @@ -93,7 +93,10 @@ export function PodLogs(props: PodLogsProps) { ] const memoRow = useMemo( - () => logs?.map((log: Log, index: number) => ), + () => + logs?.map((log: Log, index: number) => { + return + }), [logs, filter] ) diff --git a/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.spec.tsx b/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.spec.tsx index cdb22e2eedc..9d87655b057 100644 --- a/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.spec.tsx +++ b/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.spec.tsx @@ -78,13 +78,13 @@ describe('RowPod', () => { render() const cellVersion = screen.getByTestId('cell-version') - expect(cellVersion?.textContent).toBe('53d...727') + expect(cellVersion?.textContent).toBe('53deb16') }) it('should have function to format version', () => { const { baseElement } = render(
{formatVersion('53deb16f853aef759b8be84fbeec96e9727')}
) - expect(baseElement.textContent).toBe('53d...727') + expect(baseElement.textContent).toBe('53deb16') expect(formatVersion('53deb')).toBe('53deb') }) }) diff --git a/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.tsx b/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.tsx index 8c6dd3894c5..97434d94ca3 100644 --- a/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.tsx +++ b/libs/pages/logs/environment/src/lib/ui/row-pod/row-pod.tsx @@ -1,15 +1,7 @@ import { Log } from 'qovery-typescript-axios' import { useContext } from 'react' import { UpdateTimeContext } from '@qovery/shared/console-shared' -import { - CopyToClipboard, - Icon, - IconAwesomeEnum, - TableFilterProps, - TableRowFilter, - Tooltip, - convertToAnsi, -} from '@qovery/shared/ui' +import { Icon, IconAwesomeEnum, TableFilterProps, TableRowFilter, Tooltip, convertToAnsi } from '@qovery/shared/ui' import { dateFullFormat } from '@qovery/shared/utils' const COLORS = [ @@ -51,9 +43,7 @@ export const formatVersion = (version: string) => { } else { return ( - - {version.substring(0, 3)}...{version.slice(-3)} - + {version.substring(0, 7)} ) } @@ -111,10 +101,6 @@ export function RowPod(props: RowPodProps) {
{convertToAnsi(data.message)} -
diff --git a/libs/pages/logs/environment/src/lib/ui/sidebar-status/sidebar-status.tsx b/libs/pages/logs/environment/src/lib/ui/sidebar-status/sidebar-status.tsx index 10c5e647dea..1fcbd0cfe69 100644 --- a/libs/pages/logs/environment/src/lib/ui/sidebar-status/sidebar-status.tsx +++ b/libs/pages/logs/environment/src/lib/ui/sidebar-status/sidebar-status.tsx @@ -11,10 +11,10 @@ export function SidebarStatus(props: SidebarStatusProps) { return (
-

+

Pipeline deployment status: -

+

Deployment id: diff --git a/libs/shared/console-shared/src/lib/layout-logs/layout-logs.spec.tsx b/libs/shared/console-shared/src/lib/layout-logs/layout-logs.spec.tsx index 810abc38061..4d56776e6d8 100644 --- a/libs/shared/console-shared/src/lib/layout-logs/layout-logs.spec.tsx +++ b/libs/shared/console-shared/src/lib/layout-logs/layout-logs.spec.tsx @@ -44,7 +44,7 @@ describe('LayoutLogs', () => { const loadingScreen = screen.getByTestId('loading-screen') - expect(loadingScreen.querySelector('p')?.textContent).toBe('Logs not available') + expect(loadingScreen.querySelector('div')?.textContent).toBe('Logs not available') }) it('should have text with error line', () => { diff --git a/libs/shared/console-shared/src/lib/layout-logs/layout-logs.tsx b/libs/shared/console-shared/src/lib/layout-logs/layout-logs.tsx index abb18442870..39b2e4fc437 100644 --- a/libs/shared/console-shared/src/lib/layout-logs/layout-logs.tsx +++ b/libs/shared/console-shared/src/lib/layout-logs/layout-logs.tsx @@ -139,7 +139,7 @@ export function LayoutLogs(props: LayoutLogsProps) { src="/assets/images/event-placeholder-dark.svg" alt="Event placeholder" /> -

{placeholderDescription}

+
{placeholderDescription}
)}