diff --git a/src/renderer/components/dock/pod-log-controls.tsx b/src/renderer/components/dock/pod-log-controls.tsx index 5babaa633b..d3ba81e7ab 100644 --- a/src/renderer/components/dock/pod-log-controls.tsx +++ b/src/renderer/components/dock/pod-log-controls.tsx @@ -13,7 +13,7 @@ interface Props { ready: boolean tabId: string tabData: IPodLogsData - logs: [string, string] + logs: string[][] save: (data: Partial) => void reload: () => void } @@ -22,7 +22,7 @@ export const PodLogControls = observer((props: Props) => { if (!props.ready) return null; const { tabData, tabId, save, reload, logs } = props; const { selectedContainer, showTimestamps, previous } = tabData; - const timestamps = podLogsStore.getTimestamps(podLogsStore.logs.get(tabId)); + const since = podLogsStore.getTimestamps(podLogsStore.logs.get(tabId)[0]); const pod = new Pod(tabData.pod); const toggleTimestamps = () => { save({ showTimestamps: !showTimestamps }); @@ -36,7 +36,7 @@ export const PodLogControls = observer((props: Props) => { const downloadLogs = () => { const fileName = selectedContainer ? selectedContainer.name : pod.getName(); const [oldLogs, newLogs] = logs; - downloadFile(fileName + ".log", oldLogs + newLogs, "text/plain"); + downloadFile(fileName + ".log", [...oldLogs, ...newLogs].join("\n"), "text/plain"); } const onContainerChange = (option: SelectOption) => { @@ -85,10 +85,10 @@ export const PodLogControls = observer((props: Props) => { autoConvertOptions={false} />
- {timestamps && ( + {since && ( <> Since{" "} - {new Date(timestamps[0]).toLocaleString()} + {new Date(since[0]).toLocaleString()} )}
diff --git a/src/renderer/components/dock/pod-logs.store.ts b/src/renderer/components/dock/pod-logs.store.ts index cf56213254..ea11b35e6b 100644 --- a/src/renderer/components/dock/pod-logs.store.ts +++ b/src/renderer/components/dock/pod-logs.store.ts @@ -5,7 +5,6 @@ import { DockTabStore } from "./dock-tab.store"; import { dockStore, IDockTab, TabKind } from "./dock.store"; import { t } from "@lingui/macro"; import { _i18n } from "../../i18n"; -import { Notifications } from "../notifications"; import { isDevelopment } from "../../../common/vars"; export interface IPodLogsData { @@ -18,7 +17,7 @@ export interface IPodLogsData { } type TabId = string; -type PodLogs = string; +type PodLogLine = string; // Number for log lines to load export const logRange = isDevelopment ? 100 : 1000; @@ -31,7 +30,7 @@ export class PodLogsStore extends DockTabStore { this.loadMore(id) }); - @observable logs = observable.map(); + @observable logs = observable.map(); @observable newLogSince = observable.map(); // Timestamp after which all logs are considered to be new constructor() { @@ -64,15 +63,14 @@ export class PodLogsStore extends DockTabStore { const logs = await this.loadLogs(tabId, { tailLines: this.lines + logRange }); - if (!this.refresher.isRunning) this.refresher.start(); + this.refresher.start(); this.logs.set(tabId, logs); } catch ({error}) { const message = [ _i18n._(t`Failed to load logs: ${error.message}`), _i18n._(t`Reason: ${error.reason} (${error.code})`) - ].join("\n"); + ]; this.refresher.stop(); - Notifications.error(message); this.logs.set(tabId, message); } } @@ -89,7 +87,7 @@ export class PodLogsStore extends DockTabStore { sinceTime: this.getLastSinceTime(tabId) }); // Add newly received logs to bottom - this.logs.set(tabId, oldLogs + logs); + this.logs.set(tabId, [...oldLogs, ...logs]); } /** @@ -105,11 +103,15 @@ export class PodLogsStore extends DockTabStore { const pod = new Pod(data.pod); const namespace = pod.getNs(); const name = pod.getName(); - return await podsApi.getLogs({ namespace, name }, { + return podsApi.getLogs({ namespace, name }, { ...params, timestamps: true, // Always setting timestampt to separate old logs from new ones container: selectedContainer.name, previous + }).then(result => { + const logs = [...result.split("\n")]; // Transform them into array + logs.pop(); // Remove last empty element + return logs; }); } @@ -131,7 +133,7 @@ export class PodLogsStore extends DockTabStore { get lines() { const id = dockStore.selectedTabId; const logs = this.logs.get(id); - return logs ? logs.split("\n").length : 0; + return logs ? logs.length : 0; } /** @@ -140,12 +142,10 @@ export class PodLogsStore extends DockTabStore { * @param tabId */ getLastSinceTime(tabId: TabId) { - const timestamps = this.getTimestamps(this.logs.get(tabId)); - let stamp = new Date(0); - if (timestamps) { - stamp = new Date(timestamps.slice(-1)[0]); - stamp.setSeconds(stamp.getSeconds() + 1); // avoid duplicates from last second - } + const logs = this.logs.get(tabId); + const timestamps = this.getTimestamps(logs[logs.length - 1]); + const stamp = new Date(timestamps[0]); + stamp.setSeconds(stamp.getSeconds() + 1); // avoid duplicates from last second return stamp.toISOString(); } diff --git a/src/renderer/components/dock/pod-logs.tsx b/src/renderer/components/dock/pod-logs.tsx index 7192677a05..fb4968e371 100644 --- a/src/renderer/components/dock/pod-logs.tsx +++ b/src/renderer/components/dock/pod-logs.tsx @@ -80,7 +80,7 @@ export class PodLogs extends React.Component { * scrolling position * @param scrollHeight previous scrollHeight position before adding new lines */ - preload = async (scrollHeight: number) => { + loadMore = async (scrollHeight: number) => { if (podLogsStore.lines < logRange) return; this.preloading = true; await podLogsStore.load(this.tabId).then(() => this.preloading = false); @@ -93,27 +93,27 @@ export class PodLogs extends React.Component { /** * Computed prop which returns logs with or without timestamps added to each line and * does separation between new and old logs - * @returns {Array} An array with 2 string items - [oldLogs, newLogs] + * @returns {Array} An array with 2 items - [oldLogs, newLogs] */ @computed - get logs(): [string, string] { - if (!podLogsStore.logs.has(this.tabId)) return ["", ""]; + get logs() { + if (!podLogsStore.logs.has(this.tabId)) return []; const logs = podLogsStore.logs.get(this.tabId); const { getData, removeTimestamps, newLogSince } = podLogsStore; const { showTimestamps } = getData(this.tabId); - let oldLogs = logs; - let newLogs = ""; + let oldLogs: string[] = logs; + let newLogs: string[] = []; if (newLogSince.has(this.tabId)) { // Finding separator timestamp in logs - const index = logs.indexOf(newLogSince.get(this.tabId)); + const index = logs.findIndex(item => item.includes(newLogSince.get(this.tabId))); if (index !== -1) { // Splitting logs to old and new ones - oldLogs = logs.substring(0, index); - newLogs = logs.substring(index); + oldLogs = logs.slice(0, index); + newLogs = logs.slice(index); } } if (!showTimestamps) { - return [removeTimestamps(oldLogs), removeTimestamps(newLogs)]; + return [oldLogs, newLogs].map(logs => logs.map(item => removeTimestamps(item))) } return [oldLogs, newLogs]; } @@ -123,7 +123,7 @@ export class PodLogs extends React.Component { const toBottomOffset = 100 * 16; // 100 lines * 16px (height of each line) const { scrollHeight, clientHeight, scrollTop } = logsArea; if (scrollTop === 0) { - this.preload(scrollHeight); + this.loadMore(scrollHeight); } if (scrollHeight - scrollTop > toBottomOffset) { this.showJumpToBottom = true; @@ -158,7 +158,7 @@ export class PodLogs extends React.Component { if (!this.ready) { return ; } - if (!oldLogs && !newLogs) { + if (!oldLogs.length && !newLogs.length) { return (
There are no logs available for container. @@ -172,11 +172,11 @@ export class PodLogs extends React.Component {
)} -
- {newLogs && ( +
+ {newLogs.length > 0 && ( <>

-

+
)}