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

Adding old/new logs separator

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2020-10-13 14:36:13 +03:00
parent f467ebfa4e
commit 725cd8fc48
2 changed files with 50 additions and 17 deletions

View File

@ -81,14 +81,8 @@ export class PodLogsStore extends DockTabStore<IPodLogsData> {
*/ */
loadMore = async (tabId: TabId) => { loadMore = async (tabId: TabId) => {
const oldLogs = this.logs.get(tabId); const oldLogs = this.logs.get(tabId);
const timestamps = this.getTimestamps(oldLogs);
let sinceTime = new Date(0);
if (timestamps) {
sinceTime = new Date(timestamps.slice(-1)[0]);
sinceTime.setSeconds(sinceTime.getSeconds() + 1); // avoid duplicates from last second
}
const logs = await this.loadLogs(tabId, { const logs = await this.loadLogs(tabId, {
sinceTime: sinceTime.toISOString() sinceTime: this.getLastSinceTime(tabId)
}); });
// Add newly received logs to bottom // Add newly received logs to bottom
// TODO: set a new log separator here // TODO: set a new log separator here
@ -127,6 +121,21 @@ export class PodLogsStore extends DockTabStore<IPodLogsData> {
return logs ? logs.split("\n").length : 0; return logs ? logs.split("\n").length : 0;
} }
/**
* It gets timestamps from all logs then returns last one + 1 second
* (this allows to avoid getting the last stamp in the selection)
* @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
}
return stamp.toISOString();
}
getTimestamps(logs: string) { getTimestamps(logs: string) {
return logs.match(/^\d+\S+/gm); return logs.match(/^\d+\S+/gm);
} }

View File

@ -25,21 +25,28 @@ export class PodLogs extends React.Component<Props> {
@observable ready = false; @observable ready = false;
@observable preloading = false; // Indicator for setting Spinner (loader) at the top of the logs @observable preloading = false; // Indicator for setting Spinner (loader) at the top of the logs
@observable showJumpToBottom = false; @observable showJumpToBottom = false;
@observable newLogsSince = ""; // The time after which the logs are considered to be new
private logsElement: HTMLDivElement; private logsElement: HTMLDivElement;
private lastLineIsShown = true; // used for proper auto-scroll content after refresh private lastLineIsShown = true; // used for proper auto-scroll content after refresh
private colorConverter = new AnsiUp(); private colorConverter = new AnsiUp();
componentDidMount() { componentDidMount() {
disposeOnUnmount(this, disposeOnUnmount(this, [
reaction(() => this.props.tab.id, async () => { reaction(() => this.props.tab.id, async () => {
if (podLogsStore.logs.has(this.tabId)) { if (podLogsStore.logs.has(this.tabId)) {
this.ready = true; this.ready = true;
return; return;
} }
await this.load(); await this.load();
}, { fireImmediately: true }) }, { fireImmediately: true }),
); // Setting newLogSince separator timestamp to split old logs from new ones
reaction(() => podLogsStore.logs.get(this.tabId), () => {
if (this.newLogsSince) return;
const timestamp = podLogsStore.getLastSinceTime(this.tabId);
this.newLogsSince = timestamp.split(".")[0]; // Removing milliseconds from string
})
]);
} }
componentDidUpdate() { componentDidUpdate() {
@ -91,15 +98,31 @@ export class PodLogs extends React.Component<Props> {
} }
/** /**
* Computed prop which returns logs with or without timestamps added to each line * 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]
*/ */
@computed @computed
get logs() { 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 } = podLogsStore; const { getData, removeTimestamps } = podLogsStore;
const { showTimestamps } = getData(this.tabId); const { showTimestamps } = getData(this.tabId);
return showTimestamps ? logs : removeTimestamps(logs); let oldLogs = logs;
let newLogs = "";
if (this.newLogsSince) {
// Finding separator timestamp in logs
const index = logs.indexOf(this.newLogsSince);
if (index !== -1) {
// Splitting logs to old and new ones
oldLogs = logs.substring(0, index);
newLogs = logs.substring(index);
}
}
if (!showTimestamps) {
return [removeTimestamps(oldLogs), removeTimestamps(newLogs)];
}
return [oldLogs, newLogs];
} }
toggleTimestamps = () => { toggleTimestamps = () => {
@ -132,7 +155,8 @@ export class PodLogs extends React.Component<Props> {
downloadLogs = () => { downloadLogs = () => {
const { pod, selectedContainer } = this.tabData; const { pod, selectedContainer } = this.tabData;
const fileName = selectedContainer ? selectedContainer.name : pod.getName(); const fileName = selectedContainer ? selectedContainer.name : pod.getName();
downloadFile(fileName + ".log", this.logs, "text/plain"); const [oldLogs, newLogs] = this.logs;
downloadFile(fileName + ".log", oldLogs + newLogs, "text/plain");
} }
onContainerChange = (option: SelectOption) => { onContainerChange = (option: SelectOption) => {
@ -234,11 +258,11 @@ export class PodLogs extends React.Component<Props> {
} }
renderLogs() { renderLogs() {
const newLogs = false // TODO: set new logs separator and generate new logs const [oldLogs, newLogs] = this.logs;
if (!this.ready) { if (!this.ready) {
return <Spinner center/>; return <Spinner center/>;
} }
if (!this.logs) { if (!oldLogs && !newLogs) {
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>
@ -252,7 +276,7 @@ export class PodLogs extends React.Component<Props> {
<Spinner /> <Spinner />
</div> </div>
)} )}
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(this.logs))}} /> <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(this.colorConverter.ansi_to_html(oldLogs))}} />
{newLogs && ( {newLogs && (
<> <>
<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`)}/>