mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
Explore: Fix deferred rendering of logs (#20110)
Remove artificial delay before first 100 rows were rendered and defer just the rest.
This commit is contained in:
parent
8b672c8aed
commit
2715d6535f
126
packages/grafana-ui/src/components/Logs/LogRows.test.tsx
Normal file
126
packages/grafana-ui/src/components/Logs/LogRows.test.tsx
Normal file
@ -0,0 +1,126 @@
|
||||
import React from 'react';
|
||||
import { range } from 'lodash';
|
||||
import { LogRows, PREVIEW_LIMIT } from './LogRows';
|
||||
import { mount } from 'enzyme';
|
||||
import { LogLevel, LogRowModel, LogsDedupStrategy } from '@grafana/data';
|
||||
import { LogRow } from './LogRow';
|
||||
|
||||
describe('LogRows', () => {
|
||||
it('renders rows', () => {
|
||||
const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })];
|
||||
const wrapper = mount(
|
||||
<LogRows
|
||||
data={{
|
||||
rows,
|
||||
hasUniqueLabels: false,
|
||||
}}
|
||||
dedupStrategy={LogsDedupStrategy.none}
|
||||
highlighterExpressions={[]}
|
||||
showTime={false}
|
||||
showLabels={false}
|
||||
timeZone={'utc'}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(LogRow).length).toBe(3);
|
||||
expect(wrapper.contains('log message 1')).toBeTruthy();
|
||||
expect(wrapper.contains('log message 2')).toBeTruthy();
|
||||
expect(wrapper.contains('log message 3')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders rows only limited number of rows first', () => {
|
||||
const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })];
|
||||
jest.useFakeTimers();
|
||||
const wrapper = mount(
|
||||
<LogRows
|
||||
data={{
|
||||
rows,
|
||||
hasUniqueLabels: false,
|
||||
}}
|
||||
dedupStrategy={LogsDedupStrategy.none}
|
||||
highlighterExpressions={[]}
|
||||
showTime={false}
|
||||
showLabels={false}
|
||||
timeZone={'utc'}
|
||||
previewLimit={1}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(LogRow).length).toBe(1);
|
||||
expect(wrapper.contains('log message 1')).toBeTruthy();
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find(LogRow).length).toBe(3);
|
||||
expect(wrapper.contains('log message 1')).toBeTruthy();
|
||||
expect(wrapper.contains('log message 2')).toBeTruthy();
|
||||
expect(wrapper.contains('log message 3')).toBeTruthy();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('renders deduped rows if supplied', () => {
|
||||
const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })];
|
||||
const dedupedRows: LogRowModel[] = [makeLog({ uid: '4' }), makeLog({ uid: '5' })];
|
||||
const wrapper = mount(
|
||||
<LogRows
|
||||
data={{
|
||||
rows,
|
||||
hasUniqueLabels: false,
|
||||
}}
|
||||
deduplicatedData={{
|
||||
rows: dedupedRows,
|
||||
hasUniqueLabels: false,
|
||||
}}
|
||||
dedupStrategy={LogsDedupStrategy.none}
|
||||
highlighterExpressions={[]}
|
||||
showTime={false}
|
||||
showLabels={false}
|
||||
timeZone={'utc'}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(LogRow).length).toBe(2);
|
||||
expect(wrapper.contains('log message 4')).toBeTruthy();
|
||||
expect(wrapper.contains('log message 5')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders with default preview limit', () => {
|
||||
// PREVIEW_LIMIT * 2 is there because otherwise we just render all rows
|
||||
const rows: LogRowModel[] = range(PREVIEW_LIMIT * 2 + 1).map(num => makeLog({ uid: num.toString() }));
|
||||
const wrapper = mount(
|
||||
<LogRows
|
||||
data={{
|
||||
rows,
|
||||
hasUniqueLabels: false,
|
||||
}}
|
||||
dedupStrategy={LogsDedupStrategy.none}
|
||||
highlighterExpressions={[]}
|
||||
showTime={false}
|
||||
showLabels={false}
|
||||
timeZone={'utc'}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(LogRow).length).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
const makeLog = (overides: Partial<LogRowModel>): LogRowModel => {
|
||||
const uid = overides.uid || '1';
|
||||
const entry = `log message ${uid}`;
|
||||
return {
|
||||
uid,
|
||||
logLevel: LogLevel.debug,
|
||||
entry,
|
||||
hasAnsi: false,
|
||||
labels: {},
|
||||
raw: entry,
|
||||
timestamp: '',
|
||||
timeFromNow: '',
|
||||
timeEpochMs: 1,
|
||||
timeLocal: '',
|
||||
timeUtc: '',
|
||||
...overides,
|
||||
};
|
||||
};
|
@ -8,8 +8,8 @@ import { withTheme } from '../../themes/index';
|
||||
import { getLogRowStyles } from './getLogRowStyles';
|
||||
import memoizeOne from 'memoize-one';
|
||||
|
||||
const PREVIEW_LIMIT = 100;
|
||||
const RENDER_LIMIT = 500;
|
||||
export const PREVIEW_LIMIT = 100;
|
||||
export const RENDER_LIMIT = 500;
|
||||
|
||||
export interface Props extends Themeable {
|
||||
data: LogsModel;
|
||||
@ -19,48 +19,42 @@ export interface Props extends Themeable {
|
||||
showLabels: boolean;
|
||||
timeZone: TimeZone;
|
||||
deduplicatedData?: LogsModel;
|
||||
rowLimit?: number;
|
||||
onClickLabel?: (label: string, value: string) => void;
|
||||
getRowContext?: (row: LogRowModel, options?: any) => Promise<any>;
|
||||
rowLimit?: number;
|
||||
previewLimit?: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
deferLogs: boolean;
|
||||
renderAll: boolean;
|
||||
}
|
||||
|
||||
class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
deferLogsTimer: number | null = null;
|
||||
renderAllTimer: number | null = null;
|
||||
|
||||
static defaultProps = {
|
||||
previewLimit: PREVIEW_LIMIT,
|
||||
rowLimit: RENDER_LIMIT,
|
||||
};
|
||||
|
||||
state: State = {
|
||||
deferLogs: true,
|
||||
renderAll: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
// Staged rendering
|
||||
if (this.state.deferLogs) {
|
||||
const { data } = this.props;
|
||||
const rowCount = data && data.rows ? data.rows.length : 0;
|
||||
// Render all right away if not too far over the limit
|
||||
const renderAll = rowCount <= PREVIEW_LIMIT * 2;
|
||||
this.deferLogsTimer = window.setTimeout(() => this.setState({ deferLogs: false, renderAll }), rowCount);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
// Staged rendering
|
||||
if (prevState.deferLogs && !this.state.deferLogs && !this.state.renderAll) {
|
||||
const { data, previewLimit } = this.props;
|
||||
const rowCount = data ? data.rows.length : 0;
|
||||
// Render all right away if not too far over the limit
|
||||
const renderAll = rowCount <= previewLimit! * 2;
|
||||
if (renderAll) {
|
||||
this.setState({ renderAll });
|
||||
} else {
|
||||
this.renderAllTimer = window.setTimeout(() => this.setState({ renderAll: true }), 2000);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.deferLogsTimer) {
|
||||
clearTimeout(this.deferLogsTimer);
|
||||
}
|
||||
|
||||
if (this.renderAllTimer) {
|
||||
clearTimeout(this.renderAllTimer);
|
||||
}
|
||||
@ -82,8 +76,9 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
onClickLabel,
|
||||
rowLimit,
|
||||
theme,
|
||||
previewLimit,
|
||||
} = this.props;
|
||||
const { deferLogs, renderAll } = this.state;
|
||||
const { renderAll } = this.state;
|
||||
const dedupedData = deduplicatedData ? deduplicatedData : data;
|
||||
const hasData = data && data.rows && data.rows.length > 0;
|
||||
const hasLabel = hasData && dedupedData && dedupedData.hasUniqueLabels ? true : false;
|
||||
@ -94,10 +89,9 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
|
||||
// Staged rendering
|
||||
const processedRows = dedupedData ? dedupedData.rows : [];
|
||||
const firstRows = processedRows.slice(0, PREVIEW_LIMIT);
|
||||
const renderLimit = rowLimit || RENDER_LIMIT;
|
||||
const rowCount = Math.min(processedRows.length, renderLimit);
|
||||
const lastRows = processedRows.slice(PREVIEW_LIMIT, rowCount);
|
||||
const firstRows = processedRows.slice(0, previewLimit!);
|
||||
const rowCount = Math.min(processedRows.length, rowLimit!);
|
||||
const lastRows = processedRows.slice(previewLimit!, rowCount);
|
||||
|
||||
// React profiler becomes unusable if we pass all rows to all rows and their labels, using getter instead
|
||||
const getRows = this.makeGetRows(processedRows);
|
||||
@ -107,7 +101,6 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div className={cx([logsRows])}>
|
||||
{hasData &&
|
||||
!deferLogs && // Only inject highlighterExpression in the first set for performance reasons
|
||||
firstRows.map((row, index) => (
|
||||
<LogRow
|
||||
key={row.uid}
|
||||
@ -123,7 +116,6 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
/>
|
||||
))}
|
||||
{hasData &&
|
||||
!deferLogs &&
|
||||
renderAll &&
|
||||
lastRows.map((row, index) => (
|
||||
<LogRow
|
||||
@ -138,7 +130,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
||||
onClickLabel={onClickLabel}
|
||||
/>
|
||||
))}
|
||||
{hasData && deferLogs && <span>Rendering {rowCount} rows...</span>}
|
||||
{hasData && !renderAll && <span>Rendering {rowCount - previewLimit!} rows...</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user