1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Merge branch 'preload-logs-on-scroll' into log-controls-more-info

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2020-10-15 15:34:16 +03:00
commit d3f54bd828
3 changed files with 35 additions and 35 deletions

View File

@ -13,7 +13,7 @@ interface Props {
ready: boolean ready: boolean
tabId: string tabId: string
tabData: IPodLogsData tabData: IPodLogsData
logs: [string, string] logs: string[][]
save: (data: Partial<IPodLogsData>) => void save: (data: Partial<IPodLogsData>) => void
reload: () => void reload: () => void
} }
@ -22,7 +22,7 @@ export const PodLogControls = observer((props: Props) => {
if (!props.ready) return null; if (!props.ready) return null;
const { tabData, tabId, save, reload, logs } = props; const { tabData, tabId, save, reload, logs } = props;
const { selectedContainer, showTimestamps, previous } = tabData; 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 pod = new Pod(tabData.pod);
const toggleTimestamps = () => { const toggleTimestamps = () => {
save({ showTimestamps: !showTimestamps }); save({ showTimestamps: !showTimestamps });
@ -36,7 +36,7 @@ export const PodLogControls = observer((props: Props) => {
const downloadLogs = () => { const downloadLogs = () => {
const fileName = selectedContainer ? selectedContainer.name : pod.getName(); const fileName = selectedContainer ? selectedContainer.name : pod.getName();
const [oldLogs, newLogs] = logs; const [oldLogs, newLogs] = logs;
downloadFile(fileName + ".log", oldLogs + newLogs, "text/plain"); downloadFile(fileName + ".log", [...oldLogs, ...newLogs].join("\n"), "text/plain");
} }
const onContainerChange = (option: SelectOption) => { const onContainerChange = (option: SelectOption) => {
@ -85,10 +85,10 @@ export const PodLogControls = observer((props: Props) => {
autoConvertOptions={false} autoConvertOptions={false}
/> />
<div className="time-range"> <div className="time-range">
{timestamps && ( {since && (
<> <>
<Trans>Since</Trans>{" "} <Trans>Since</Trans>{" "}
<b>{new Date(timestamps[0]).toLocaleString()}</b> <b>{new Date(since[0]).toLocaleString()}</b>
</> </>
)} )}
</div> </div>

View File

@ -5,7 +5,6 @@ import { DockTabStore } from "./dock-tab.store";
import { dockStore, IDockTab, TabKind } from "./dock.store"; import { dockStore, IDockTab, TabKind } from "./dock.store";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { _i18n } from "../../i18n"; import { _i18n } from "../../i18n";
import { Notifications } from "../notifications";
import { isDevelopment } from "../../../common/vars"; import { isDevelopment } from "../../../common/vars";
export interface IPodLogsData { export interface IPodLogsData {
@ -18,7 +17,7 @@ export interface IPodLogsData {
} }
type TabId = string; type TabId = string;
type PodLogs = string; type PodLogLine = string;
// Number for log lines to load // Number for log lines to load
export const logRange = isDevelopment ? 100 : 1000; export const logRange = isDevelopment ? 100 : 1000;
@ -31,7 +30,7 @@ export class PodLogsStore extends DockTabStore<IPodLogsData> {
this.loadMore(id) this.loadMore(id)
}); });
@observable logs = observable.map<TabId, PodLogs>(); @observable logs = observable.map<TabId, PodLogLine[]>();
@observable newLogSince = observable.map<TabId, string>(); // Timestamp after which all logs are considered to be new @observable newLogSince = observable.map<TabId, string>(); // Timestamp after which all logs are considered to be new
constructor() { constructor() {
@ -64,15 +63,14 @@ export class PodLogsStore extends DockTabStore<IPodLogsData> {
const logs = await this.loadLogs(tabId, { const logs = await this.loadLogs(tabId, {
tailLines: this.lines + logRange tailLines: this.lines + logRange
}); });
if (!this.refresher.isRunning) this.refresher.start(); this.refresher.start();
this.logs.set(tabId, logs); this.logs.set(tabId, logs);
} catch ({error}) { } catch ({error}) {
const message = [ const message = [
_i18n._(t`Failed to load logs: ${error.message}`), _i18n._(t`Failed to load logs: ${error.message}`),
_i18n._(t`Reason: ${error.reason} (${error.code})`) _i18n._(t`Reason: ${error.reason} (${error.code})`)
].join("\n"); ];
this.refresher.stop(); this.refresher.stop();
Notifications.error(message);
this.logs.set(tabId, message); this.logs.set(tabId, message);
} }
} }
@ -89,7 +87,7 @@ export class PodLogsStore extends DockTabStore<IPodLogsData> {
sinceTime: this.getLastSinceTime(tabId) sinceTime: this.getLastSinceTime(tabId)
}); });
// Add newly received logs to bottom // 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<IPodLogsData> {
const pod = new Pod(data.pod); const pod = new Pod(data.pod);
const namespace = pod.getNs(); const namespace = pod.getNs();
const name = pod.getName(); const name = pod.getName();
return await podsApi.getLogs({ namespace, name }, { return podsApi.getLogs({ namespace, name }, {
...params, ...params,
timestamps: true, // Always setting timestampt to separate old logs from new ones timestamps: true, // Always setting timestampt to separate old logs from new ones
container: selectedContainer.name, container: selectedContainer.name,
previous 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<IPodLogsData> {
get lines() { get lines() {
const id = dockStore.selectedTabId; const id = dockStore.selectedTabId;
const logs = this.logs.get(id); 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<IPodLogsData> {
* @param tabId * @param tabId
*/ */
getLastSinceTime(tabId: TabId) { getLastSinceTime(tabId: TabId) {
const timestamps = this.getTimestamps(this.logs.get(tabId)); const logs = this.logs.get(tabId);
let stamp = new Date(0); const timestamps = this.getTimestamps(logs[logs.length - 1]);
if (timestamps) { const stamp = new Date(timestamps[0]);
stamp = new Date(timestamps.slice(-1)[0]); stamp.setSeconds(stamp.getSeconds() + 1); // avoid duplicates from last second
stamp.setSeconds(stamp.getSeconds() + 1); // avoid duplicates from last second
}
return stamp.toISOString(); return stamp.toISOString();
} }

View File

@ -80,7 +80,7 @@ export class PodLogs extends React.Component<Props> {
* scrolling position * scrolling position
* @param scrollHeight previous scrollHeight position before adding new lines * @param scrollHeight previous scrollHeight position before adding new lines
*/ */
preload = async (scrollHeight: number) => { loadMore = async (scrollHeight: number) => {
if (podLogsStore.lines < logRange) return; if (podLogsStore.lines < logRange) return;
this.preloading = true; this.preloading = true;
await podLogsStore.load(this.tabId).then(() => this.preloading = false); await podLogsStore.load(this.tabId).then(() => this.preloading = false);
@ -93,27 +93,27 @@ export class PodLogs extends React.Component<Props> {
/** /**
* Computed prop which returns logs with or without timestamps added to each line and * Computed prop which returns logs with or without timestamps added to each line and
* does separation between new and old logs * 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 @computed
get logs(): [string, string] { get logs() {
if (!podLogsStore.logs.has(this.tabId)) return ["", ""]; if (!podLogsStore.logs.has(this.tabId)) return [];
const logs = podLogsStore.logs.get(this.tabId); const logs = podLogsStore.logs.get(this.tabId);
const { getData, removeTimestamps, newLogSince } = podLogsStore; const { getData, removeTimestamps, newLogSince } = podLogsStore;
const { showTimestamps } = getData(this.tabId); const { showTimestamps } = getData(this.tabId);
let oldLogs = logs; let oldLogs: string[] = logs;
let newLogs = ""; let newLogs: string[] = [];
if (newLogSince.has(this.tabId)) { if (newLogSince.has(this.tabId)) {
// Finding separator timestamp in logs // 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) { if (index !== -1) {
// Splitting logs to old and new ones // Splitting logs to old and new ones
oldLogs = logs.substring(0, index); oldLogs = logs.slice(0, index);
newLogs = logs.substring(index); newLogs = logs.slice(index);
} }
} }
if (!showTimestamps) { if (!showTimestamps) {
return [removeTimestamps(oldLogs), removeTimestamps(newLogs)]; return [oldLogs, newLogs].map(logs => logs.map(item => removeTimestamps(item)))
} }
return [oldLogs, newLogs]; return [oldLogs, newLogs];
} }
@ -123,7 +123,7 @@ export class PodLogs extends React.Component<Props> {
const toBottomOffset = 100 * 16; // 100 lines * 16px (height of each line) const toBottomOffset = 100 * 16; // 100 lines * 16px (height of each line)
const { scrollHeight, clientHeight, scrollTop } = logsArea; const { scrollHeight, clientHeight, scrollTop } = logsArea;
if (scrollTop === 0) { if (scrollTop === 0) {
this.preload(scrollHeight); this.loadMore(scrollHeight);
} }
if (scrollHeight - scrollTop > toBottomOffset) { if (scrollHeight - scrollTop > toBottomOffset) {
this.showJumpToBottom = true; this.showJumpToBottom = true;
@ -158,7 +158,7 @@ export class PodLogs extends React.Component<Props> {
if (!this.ready) { if (!this.ready) {
return <Spinner center/>; return <Spinner center/>;
} }
if (!oldLogs && !newLogs) { if (!oldLogs.length && !newLogs.length) {
return ( return (
<div className="flex align-center justify-center"> <div className="flex align-center justify-center">
<Trans>There are no logs available for container.</Trans> <Trans>There are no logs available for container.</Trans>
@ -172,11 +172,11 @@ export class PodLogs extends React.Component<Props> {
<Spinner /> <Spinner />
</div> </div>
)} )}
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(oldLogs))}} /> <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(oldLogs.join("\n"))) }} />
{newLogs && ( {newLogs.length > 0 && (
<> <>
<p className="new-logs-sep" title={_i18n._(t`New logs since opening the dialog`)}/> <p className="new-logs-sep" title={_i18n._(t`New logs since opening the dialog`)}/>
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(newLogs))}} /> <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(newLogs.join("\n"))) }} />
</> </>
)} )}
</> </>