Skip to content

Commit 50a36dc

Browse files
Merge pull request #13298 from cyril-ui-developer/add-show-full-log-chkbx-log-viewers
CONSOLE-3732: Add option to enable/disable tailing to Pod log viewer
2 parents 70a927c + 98ae227 commit 50a36dc

7 files changed

Lines changed: 116 additions & 16 deletions

File tree

frontend/packages/console-shared/src/constants/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const COLUMN_MANAGEMENT_LOCAL_STORAGE_KEY = `${STORAGE_PREFIX}/table-colu
4747
export const LOG_WRAP_LINES_USERSETTINGS_KEY = `${USERSETTINGS_PREFIX}.log.wrapLines`;
4848
export const SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY = `${USERSETTINGS_PREFIX}.showYAMLEditorTooltips`;
4949
export const SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY = `${STORAGE_PREFIX}/showYAMLEditorTooltips`;
50+
export const SHOW_FULL_LOG_USERSETTINGS_KEY = `${USERSETTINGS_PREFIX}.show.full.log`;
5051
// Bootstrap user for OpenShift 4.0 clusters (kube:admin)
5152
export const KUBE_ADMIN_USERNAMES = ['kube:admin'];
5253

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { checkErrors } from '../../support';
2+
import { detailsPage } from '../../views/details-page';
3+
import { listPage, listPage } from '../../views/list-page';
4+
5+
describe('Pod log viewer tab', () => {
6+
before(() => {
7+
cy.login();
8+
});
9+
10+
afterEach(() => {
11+
checkErrors();
12+
});
13+
14+
it('Open logs from pod details page tab and verify the log buffer sizes', () => {
15+
cy.visit(
16+
`/k8s/ns/openshift-kube-apiserver/core~v1~Pod?name=kube-apiserver-ip-&rowFilter-pod-status=Running&orderBy=desc&sortBy=Owner`,
17+
);
18+
listPage.rows.clickFirstLinkInFirstRow();
19+
detailsPage.isLoaded();
20+
detailsPage.selectTab('Logs');
21+
detailsPage.isLoaded();
22+
// Verify the default log buffer size
23+
cy.byTestID('no-log-lines').contains('1000 lines');
24+
// Verify the log exceeds the default log buffer size
25+
cy.byTestID('show-full-log').check();
26+
// eslint-disable-next-line cypress/no-unnecessary-waiting
27+
cy.wait(5000);
28+
cy.byTestID('no-log-lines').should('not.contain', '1000 lines');
29+
});
30+
});

frontend/packages/pipelines-plugin/src/components/pipelineruns/logs/logs-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export const getDownloadAllLogsCallback = (
160160
);
161161
}
162162
}
163-
const buffer = new LineBuffer();
163+
const buffer = new LineBuffer(null);
164164
buffer.ingest(allLogs);
165165
const blob = buffer.getBlob({
166166
type: 'text/plain;charset=utf-8',

frontend/public/components/utils/line-buffer.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ export class LineBuffer {
66
private _buffer: string[];
77
private _tail: string;
88
private _hasTruncated: boolean;
9+
private _maxSize?: number;
910

10-
constructor() {
11+
constructor(maxSize) {
1112
this._buffer = [];
1213
this._tail = '';
1314
this._hasTruncated = false;
15+
this._maxSize = maxSize;
1416
}
1517

1618
ingest(text): number {
@@ -22,6 +24,9 @@ export class LineBuffer {
2224
this._hasTruncated = true;
2325
}
2426
if (/\n$/.test(line)) {
27+
if (this._buffer.length === this._maxSize) {
28+
this._buffer.shift();
29+
}
2530
this._buffer.push(_.truncate(next, { length: TRUNCATE_LENGTH }).trimEnd());
2631
lineCount++;
2732
this._tail = '';

frontend/public/components/utils/resource-log.tsx

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,32 @@ import * as React from 'react';
44
// @ts-ignore
55
import { useSelector } from 'react-redux';
66
import { Base64 } from 'js-base64';
7+
import * as _ from 'lodash-es';
8+
import { Trans, useTranslation } from 'react-i18next';
79
import { Alert, AlertActionLink, Button, Checkbox, Divider, Tooltip } from '@patternfly/react-core';
810
import {
911
Select as SelectDeprecated,
1012
SelectOption as SelectOptionDeprecated,
1113
SelectVariant as SelectVariantDeprecated,
1214
} from '@patternfly/react-core/deprecated';
1315
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
14-
15-
import * as _ from 'lodash-es';
16-
import { Trans, useTranslation } from 'react-i18next';
17-
import { CompressIcon } from '@patternfly/react-icons/dist/esm/icons/compress-icon';
18-
import { ExpandIcon } from '@patternfly/react-icons/dist/esm/icons/expand-icon';
19-
import { DownloadIcon } from '@patternfly/react-icons/dist/esm/icons/download-icon';
20-
import { OutlinedWindowRestoreIcon } from '@patternfly/react-icons/dist/esm/icons/outlined-window-restore-icon';
21-
import { OutlinedPlayCircleIcon } from '@patternfly/react-icons/dist/esm/icons/outlined-play-circle-icon';
16+
import {
17+
CompressIcon,
18+
ExpandIcon,
19+
DownloadIcon,
20+
OutlinedWindowRestoreIcon,
21+
OutlinedPlayCircleIcon,
22+
} from '@patternfly/react-icons';
2223
import * as classNames from 'classnames';
23-
import { FLAGS, LOG_WRAP_LINES_USERSETTINGS_KEY } from '@console/shared/src/constants';
24+
import {
25+
FLAGS,
26+
LOG_WRAP_LINES_USERSETTINGS_KEY,
27+
SHOW_FULL_LOG_USERSETTINGS_KEY,
28+
} from '@console/shared/src/constants';
2429
import { useUserSettings } from '@console/shared';
2530
import { LoadingInline, TogglePlay, ExternalLink } from './';
2631
import { modelFor, resourceURL } from '../../module/k8s';
2732
import { WSFactory } from '../../module/ws-factory';
28-
import { LineBuffer } from './line-buffer';
2933
import * as screenfull from 'screenfull';
3034
import { RootState } from '@console/internal/redux';
3135
import { k8sGet, k8sList, K8sResourceKind, PodKind } from '@console/internal/module/k8s';
@@ -36,6 +40,7 @@ import { Link } from 'react-router-dom';
3640
import { resourcePath } from './resource-link';
3741
import { isWindowsPod } from '../../module/k8s/pods';
3842
import { getImpersonate } from '@console/dynamic-plugin-sdk';
43+
import useToggleLineBuffer from './useToggleLineBuffer';
3944

4045
export const STREAM_EOF = 'eof';
4146
export const STREAM_LOADING = 'loading';
@@ -50,6 +55,8 @@ export const LOG_SOURCE_WAITING = 'waiting';
5055
const LOG_TYPE_CURRENT = 'current';
5156
const LOG_TYPE_PREVIOUS = 'previous';
5257

58+
const DEFAULT_BUFFER_SIZE = 1000;
59+
5360
// Messages to display for corresponding log status
5461
const streamStatusMessages = {
5562
// t('public~Log stream ended.')
@@ -161,6 +168,8 @@ export const LogControls: React.FC<LogControlsProps> = ({
161168
hasPreviousLog,
162169
logType,
163170
showLogTypeSelect,
171+
isShowFullLog,
172+
toggleShowFullLog,
164173
}) => {
165174
const { t } = useTranslation();
166175
const [isLogTypeOpen, setLogTypeOpen] = React.useState(false);
@@ -234,7 +243,9 @@ export const LogControls: React.FC<LogControlsProps> = ({
234243
</Tooltip>
235244
);
236245
};
246+
237247
const label = t('public~Debug container');
248+
238249
return (
239250
<div className="co-toolbar">
240251
<div className="co-toolbar__group co-toolbar__group--left">
@@ -314,6 +325,29 @@ export const LogControls: React.FC<LogControlsProps> = ({
314325
</React.Fragment>
315326
);
316327
})}
328+
<div>
329+
<Tooltip
330+
content={t(
331+
'public~Select to view the entire log. Default view is the last 1,000 lines.',
332+
)}
333+
>
334+
<Checkbox
335+
label={t('public~Show full log')}
336+
id="showFullLog"
337+
data-test="show-full-log"
338+
isChecked={isShowFullLog}
339+
data-checked-state={isShowFullLog}
340+
onChange={(_event, checked: boolean) => {
341+
toggleShowFullLog(checked);
342+
}}
343+
/>
344+
</Tooltip>
345+
</div>
346+
<Divider
347+
orientation={{
348+
default: 'vertical',
349+
}}
350+
/>
317351
<Checkbox
318352
label={t('public~Wrap lines')}
319353
id="wrapLogLines"
@@ -371,13 +405,20 @@ export const LogControls: React.FC<LogControlsProps> = ({
371405

372406
// Resource agnostic log component
373407
export const ResourceLog: React.FC<ResourceLogProps> = ({
408+
bufferSize = DEFAULT_BUFFER_SIZE,
374409
containerName,
375410
dropdown,
376411
resource,
377412
resourceStatus,
378413
}) => {
379414
const { t } = useTranslation();
380-
const buffer = React.useRef(new LineBuffer()); // TODO Make this a hook
415+
const [showFullLog, setShowFullLog] = useUserSettings<boolean>(
416+
SHOW_FULL_LOG_USERSETTINGS_KEY,
417+
false,
418+
true,
419+
);
420+
const [showFullLogCheckbox, setShowFullLogCheckbox] = React.useState(showFullLog);
421+
const buffer = useToggleLineBuffer(showFullLogCheckbox ? null : bufferSize);
381422
const ws = React.useRef<any>(); // TODO Make this a hook
382423
const resourceLogRef = React.useRef();
383424
const logViewerRef = React.useRef(null);
@@ -415,14 +456,17 @@ export const ResourceLog: React.FC<ResourceLogProps> = ({
415456

416457
const [wrapLinesCheckbox, setWrapLinesCheckbox] = React.useState(wrapLines || hasWrapAnnotation);
417458
const firstRender = React.useRef(true);
459+
const handleShowFullLogCheckbox = () => setShowFullLogCheckbox(!showFullLogCheckbox);
418460

419461
React.useEffect(() => {
420462
if (firstRender.current) {
421463
firstRender.current = false;
422464
return;
423465
}
466+
424467
setWrapLines(wrapLinesCheckbox);
425-
}, [wrapLinesCheckbox, setWrapLines]);
468+
setShowFullLog(showFullLogCheckbox);
469+
}, [wrapLinesCheckbox, showFullLogCheckbox, setWrapLines, setShowFullLog]);
426470

427471
const timeoutIdRef = React.useRef(null);
428472
const countRef = React.useRef(0);
@@ -532,7 +576,7 @@ export const ResourceLog: React.FC<ResourceLogProps> = ({
532576
startWebSocket();
533577
}
534578
return () => ws.current?.destroy();
535-
}, [error, resourceStatus, stale, startWebSocket]);
579+
}, [error, resourceStatus, stale, startWebSocket, showFullLogCheckbox]);
536580

537581
// Toggle currently displayed log content to/from fullscreen
538582
const toggleFullscreen = () => {
@@ -613,10 +657,12 @@ export const ResourceLog: React.FC<ResourceLogProps> = ({
613657
namespaceUID={namespaceUID}
614658
toggleWrapLines={setWrapLinesCheckbox}
615659
isWrapLines={wrapLinesCheckbox}
660+
isShowFullLog={showFullLogCheckbox}
616661
hasPreviousLog={hasPreviousLogs}
617662
changeLogType={setLogType}
618663
logType={logType}
619664
showLogTypeSelect={resource.kind === 'Pod'}
665+
toggleShowFullLog={handleShowFullLogCheckbox}
620666
/>
621667
);
622668

@@ -676,7 +722,7 @@ export const ResourceLog: React.FC<ResourceLogProps> = ({
676722
<div className={classNames('resource-log__log-viewer-wrapper')}>
677723
<LogViewer
678724
header={
679-
<div className="log-window__header">
725+
<div className="log-window__header" data-test="no-log-lines">
680726
<HeaderBanner lines={lines} />
681727
</div>
682728
}
@@ -721,13 +767,16 @@ type LogControlsProps = {
721767
hasPreviousLog?: boolean;
722768
logType: LogTypeStatus;
723769
showLogTypeSelect: boolean;
770+
toggleShowFullLog: (showFullLogCheckbox: boolean) => void;
771+
isShowFullLog: boolean;
724772
};
725773

726774
type ResourceLogProps = {
727775
containerName?: string;
728776
dropdown?: React.ReactNode;
729777
resource: any;
730778
resourceStatus: string;
779+
bufferSize?: number;
731780
};
732781

733782
type LogTypeStatus = typeof LOG_TYPE_CURRENT | typeof LOG_TYPE_PREVIOUS;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from 'react';
2+
import { LineBuffer } from './line-buffer';
3+
4+
const useToggleLineBuffer = (bufferSize: number | null) => {
5+
const buffer = React.useRef(null);
6+
React.useEffect(() => {
7+
buffer.current = new LineBuffer(bufferSize);
8+
}, [bufferSize]);
9+
10+
return buffer;
11+
};
12+
13+
export default useToggleLineBuffer;

frontend/public/locales/en/public.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,8 @@
17451745
"Previous log": "Previous log",
17461746
"Only the current log is available for this container.": "Only the current log is available for this container.",
17471747
"Debug in terminal is not currently available for windows containers.": "Debug in terminal is not currently available for windows containers.",
1748+
"Select to view the entire log. Default view is the last 1,000 lines.": "Select to view the entire log. Default view is the last 1,000 lines.",
1749+
"Show full log": "Show full log",
17481750
"Wrap lines": "Wrap lines",
17491751
"Raw": "Raw",
17501752
"An error occurred while retrieving the requested logs.": "An error occurred while retrieving the requested logs.",

0 commit comments

Comments
 (0)