mirror of https://github.com/grafana/grafana
Explore: Memory leak fix due to dedup selector (#20107)
Change custom hashing and lodash.memoize based selector for standard reselect.pull/20052/head
parent
fe584efc70
commit
dca872f75f
@ -1,5 +0,0 @@ |
||||
import { memoize } from 'lodash'; |
||||
import { createSelectorCreator } from 'reselect'; |
||||
|
||||
const hashFn = (...args: any[]) => args.reduce((acc, val) => acc + '-' + JSON.stringify(val), ''); |
||||
export const createLodashMemoizedSelector = createSelectorCreator(memoize as any, hashFn); |
@ -0,0 +1,77 @@ |
||||
import React from 'react'; |
||||
import { LogLevel, LogRowModel } from '@grafana/data'; |
||||
import { mount } from 'enzyme'; |
||||
import { LiveLogsWithTheme } from './LiveLogs'; |
||||
|
||||
describe('LiveLogs', () => { |
||||
it('renders logs', () => { |
||||
const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]; |
||||
const wrapper = mount( |
||||
<LiveLogsWithTheme |
||||
logRows={rows} |
||||
timeZone={'utc'} |
||||
stopLive={() => {}} |
||||
onPause={() => {}} |
||||
onResume={() => {}} |
||||
isPaused={true} |
||||
/> |
||||
); |
||||
|
||||
expect(wrapper.contains('log message 1')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 2')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 3')).toBeTruthy(); |
||||
}); |
||||
|
||||
it('renders new logs only when not paused', () => { |
||||
const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]; |
||||
const wrapper = mount( |
||||
<LiveLogsWithTheme |
||||
logRows={rows} |
||||
timeZone={'utc'} |
||||
stopLive={() => {}} |
||||
onPause={() => {}} |
||||
onResume={() => {}} |
||||
isPaused={true} |
||||
/> |
||||
); |
||||
|
||||
wrapper.setProps({ |
||||
...wrapper.props(), |
||||
logRows: [makeLog({ uid: '4' }), makeLog({ uid: '5' }), makeLog({ uid: '6' })], |
||||
}); |
||||
|
||||
expect(wrapper.contains('log message 1')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 2')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 3')).toBeTruthy(); |
||||
|
||||
(wrapper.find('LiveLogs').instance() as any).liveEndDiv.scrollIntoView = () => {}; |
||||
|
||||
wrapper.setProps({ |
||||
...wrapper.props(), |
||||
isPaused: false, |
||||
}); |
||||
|
||||
expect(wrapper.contains('log message 4')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 5')).toBeTruthy(); |
||||
expect(wrapper.contains('log message 6')).toBeTruthy(); |
||||
}); |
||||
}); |
||||
|
||||
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, |
||||
}; |
||||
}; |
@ -1,29 +1,19 @@ |
||||
import { createLodashMemoizedSelector } from 'app/core/utils/reselect'; |
||||
import { createSelector } from 'reselect'; |
||||
import { ExploreItemState } from 'app/types'; |
||||
import { filterLogLevels, dedupLogRows } from 'app/core/logs_model'; |
||||
|
||||
export const exploreItemUIStateSelector = (itemState: ExploreItemState) => { |
||||
const { showingGraph, showingTable, showingStartPage, dedupStrategy } = itemState; |
||||
return { |
||||
showingGraph, |
||||
showingTable, |
||||
showingStartPage, |
||||
dedupStrategy, |
||||
}; |
||||
}; |
||||
|
||||
const logsSelector = (state: ExploreItemState) => state.logsResult; |
||||
const logsRowsSelector = (state: ExploreItemState) => state.logsResult && state.logsResult.rows; |
||||
const hiddenLogLevelsSelector = (state: ExploreItemState) => state.hiddenLogLevels; |
||||
const dedupStrategySelector = (state: ExploreItemState) => state.dedupStrategy; |
||||
export const deduplicatedLogsSelector = createLodashMemoizedSelector( |
||||
logsSelector, |
||||
export const deduplicatedRowsSelector = createSelector( |
||||
logsRowsSelector, |
||||
hiddenLogLevelsSelector, |
||||
dedupStrategySelector, |
||||
(logs, hiddenLogLevels, dedupStrategy) => { |
||||
if (!logs) { |
||||
return null; |
||||
function dedupRows(rows, hiddenLogLevels, dedupStrategy) { |
||||
if (!(rows && rows.length)) { |
||||
return rows; |
||||
} |
||||
const filteredData = filterLogLevels(logs, new Set(hiddenLogLevels)); |
||||
return dedupLogRows(filteredData, dedupStrategy); |
||||
const filteredRows = filterLogLevels(rows, new Set(hiddenLogLevels)); |
||||
return dedupLogRows(filteredRows, dedupStrategy); |
||||
} |
||||
); |
||||
|
Loading…
Reference in new issue