Commit 8bd7e5a5 by Torkel Ödegaard Committed by GitHub

Merge pull request #15374 from grafana/explore/dedup-selector

Move deduplication calculation from Logs component to reselect selector
parents 97724973 dd19ec3b
......@@ -151,6 +151,7 @@
"dependencies": {
"@babel/polyfill": "^7.0.0",
"@torkelo/react-select": "2.1.1",
"@types/reselect": "^2.2.0",
"angular": "1.6.6",
"angular-bindonce": "0.3.1",
"angular-native-dragdrop": "1.2.2",
......@@ -187,6 +188,7 @@
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
"remarkable": "^1.7.1",
"reselect": "^4.0.0",
"rst2html": "github:thoward/rst2html#990cb89",
"rxjs": "^6.3.3",
"slate": "^0.33.4",
......
import { memoize } from 'lodash';
import { createSelectorCreator } from 'reselect';
const hashFn = (...args) => args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '');
export const createLodashMemoizedSelector = createSelectorCreator(memoize, hashFn);
......@@ -9,8 +9,6 @@ import {
LogsDedupDescription,
LogsDedupStrategy,
LogsModel,
dedupLogRows,
filterLogLevels,
LogLevel,
LogsMetaKind,
} from 'app/core/logs_model';
......@@ -51,6 +49,7 @@ function renderMetaItem(value: any, kind: LogsMetaKind) {
interface Props {
data?: LogsModel;
dedupedData?: LogsModel;
width: number;
exploreId: string;
highlighterExpressions: string[];
......@@ -59,16 +58,17 @@ interface Props {
scanning?: boolean;
scanRange?: RawTimeRange;
dedupStrategy: LogsDedupStrategy;
hiddenLogLevels: Set<LogLevel>;
onChangeTime?: (range: RawTimeRange) => void;
onClickLabel?: (label: string, value: string) => void;
onStartScanning?: () => void;
onStopScanning?: () => void;
onDedupStrategyChange: (dedupStrategy: LogsDedupStrategy) => void;
onToggleLogLevel: (hiddenLogLevels: Set<LogLevel>) => void;
}
interface State {
deferLogs: boolean;
hiddenLogLevels: Set<LogLevel>;
renderAll: boolean;
showLabels: boolean | null; // Tristate: null means auto
showLocalTime: boolean;
......@@ -81,7 +81,6 @@ export default class Logs extends PureComponent<Props, State> {
state = {
deferLogs: true,
hiddenLogLevels: new Set(),
renderAll: false,
showLabels: null,
showLocalTime: true,
......@@ -142,7 +141,7 @@ export default class Logs extends PureComponent<Props, State> {
onToggleLogLevel = (rawLevel: string, hiddenRawLevels: Set<string>) => {
const hiddenLogLevels: Set<LogLevel> = new Set(Array.from(hiddenRawLevels).map(level => LogLevel[level]));
this.setState({ hiddenLogLevels });
this.props.onToggleLogLevel(hiddenLogLevels);
};
onClickScan = (event: React.SyntheticEvent) => {
......@@ -166,21 +165,18 @@ export default class Logs extends PureComponent<Props, State> {
scanning,
scanRange,
width,
dedupedData,
} = this.props;
if (!data) {
return null;
}
const { deferLogs, hiddenLogLevels, renderAll, showLocalTime, showUtc, } = this.state;
const { deferLogs, renderAll, showLocalTime, showUtc } = this.state;
let { showLabels } = this.state;
const { dedupStrategy } = this.props;
const hasData = data && data.rows && data.rows.length > 0;
const showDuplicates = dedupStrategy !== LogsDedupStrategy.none;
// Filtering
const filteredData = filterLogLevels(data, hiddenLogLevels);
const dedupedData = dedupLogRows(filteredData, dedupStrategy);
const dedupCount = dedupedData.rows.reduce((sum, row) => sum + row.duplicates, 0);
const meta = [...data.meta];
......
......@@ -4,18 +4,21 @@ import { connect } from 'react-redux';
import { RawTimeRange, TimeRange } from '@grafana/ui';
import { ExploreId, ExploreItemState } from 'app/types/explore';
import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
import { LogsModel, LogsDedupStrategy, LogLevel } from 'app/core/logs_model';
import { StoreState } from 'app/types';
import { toggleLogs, changeDedupStrategy } from './state/actions';
import Logs from './Logs';
import Panel from './Panel';
import { toggleLogLevelAction } from 'app/features/explore/state/actionTypes';
import { deduplicatedLogsSelector, exploreItemUIStateSelector } from 'app/features/explore/state/selectors';
interface LogsContainerProps {
exploreId: ExploreId;
loading: boolean;
logsHighlighterExpressions?: string[];
logsResult?: LogsModel;
dedupedResult?: LogsModel;
onChangeTime: (range: TimeRange) => void;
onClickLabel: (key: string, value: string) => void;
onStartScanning: () => void;
......@@ -25,8 +28,10 @@ interface LogsContainerProps {
scanRange?: RawTimeRange;
showingLogs: boolean;
toggleLogs: typeof toggleLogs;
toggleLogLevelAction: typeof toggleLogLevelAction;
changeDedupStrategy: typeof changeDedupStrategy;
dedupStrategy: LogsDedupStrategy;
hiddenLogLevels: Set<LogLevel>;
width: number;
}
......@@ -39,12 +44,21 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
this.props.changeDedupStrategy(this.props.exploreId, dedupStrategy);
};
hangleToggleLogLevel = (hiddenLogLevels: Set<LogLevel>) => {
const { exploreId } = this.props;
this.props.toggleLogLevelAction({
exploreId,
hiddenLogLevels,
});
};
render() {
const {
exploreId,
loading,
logsHighlighterExpressions,
logsResult,
dedupedResult,
onChangeTime,
onClickLabel,
onStartScanning,
......@@ -54,6 +68,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
scanning,
scanRange,
width,
hiddenLogLevels,
} = this.props;
return (
......@@ -61,6 +76,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
<Logs
dedupStrategy={this.props.dedupStrategy || LogsDedupStrategy.none}
data={logsResult}
dedupedData={dedupedResult}
exploreId={exploreId}
key={logsResult && logsResult.id}
highlighterExpressions={logsHighlighterExpressions}
......@@ -70,32 +86,26 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
onStartScanning={onStartScanning}
onStopScanning={onStopScanning}
onDedupStrategyChange={this.handleDedupStrategyChange}
onToggleLogLevel={this.hangleToggleLogLevel}
range={range}
scanning={scanning}
scanRange={scanRange}
width={width}
hiddenLogLevels={hiddenLogLevels}
/>
</Panel>
);
}
}
const selectItemUIState = (itemState: ExploreItemState) => {
const { showingGraph, showingLogs, showingTable, showingStartPage, dedupStrategy } = itemState;
return {
showingGraph,
showingLogs,
showingTable,
showingStartPage,
dedupStrategy,
};
};
function mapStateToProps(state: StoreState, { exploreId }) {
const explore = state.explore;
const item: ExploreItemState = explore[exploreId];
const { logsHighlighterExpressions, logsResult, queryTransactions, scanning, scanRange, range } = item;
const loading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done);
const {showingLogs, dedupStrategy} = selectItemUIState(item);
const { showingLogs, dedupStrategy } = exploreItemUIStateSelector(item);
const hiddenLogLevels = new Set(item.hiddenLogLevels);
const dedupedResult = deduplicatedLogsSelector(item);
return {
loading,
......@@ -106,12 +116,15 @@ function mapStateToProps(state: StoreState, { exploreId }) {
showingLogs,
range,
dedupStrategy,
hiddenLogLevels,
dedupedResult,
};
}
const mapDispatchToProps = {
toggleLogs,
changeDedupStrategy,
toggleLogLevelAction,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LogsContainer));
......@@ -18,6 +18,7 @@ import {
ExploreUIState,
} from 'app/types/explore';
import { actionCreatorFactory, noPayloadActionCreatorFactory, ActionOf } from 'app/core/redux/actionCreatorFactory';
import { LogLevel } from 'app/core/logs_model';
/** Higher order actions
*
......@@ -201,6 +202,11 @@ export interface UpdateDatasourceInstancePayload {
datasourceInstance: DataSourceApi;
}
export interface ToggleLogLevelPayload {
exploreId: ExploreId;
hiddenLogLevels: Set<LogLevel>;
}
export interface QueriesImportedPayload {
exploreId: ExploreId;
queries: DataQuery[];
......@@ -397,6 +403,10 @@ export const updateDatasourceInstanceAction = actionCreatorFactory<UpdateDatasou
'explore/UPDATE_DATASOURCE_INSTANCE'
).create();
export const toggleLogLevelAction = actionCreatorFactory<ToggleLogLevelPayload>(
'explore/TOGGLE_LOG_LEVEL'
).create();
/**
* Resets state for explore.
*/
......@@ -436,4 +446,5 @@ export type Action =
| ActionOf<ToggleGraphPayload>
| ActionOf<ToggleLogsPayload>
| ActionOf<UpdateDatasourceInstancePayload>
| ActionOf<QueriesImportedPayload>;
| ActionOf<QueriesImportedPayload>
| ActionOf<ToggleLogLevelPayload>;
......@@ -38,6 +38,7 @@ import {
toggleTableAction,
queriesImportedAction,
updateUIStateAction,
toggleLogLevelAction,
} from './actionTypes';
export const DEFAULT_RANGE = {
......@@ -467,6 +468,16 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
};
},
})
.addMapper({
filter: toggleLogLevelAction,
mapper: (state, action): ExploreItemState => {
const { hiddenLogLevels } = action.payload;
return {
...state,
hiddenLogLevels: Array.from(hiddenLogLevels)
};
},
})
.create();
/**
......
import { createLodashMemoizedSelector } from 'app/core/utils/reselect';
import { ExploreItemState } from 'app/types';
import { filterLogLevels, dedupLogRows } from 'app/core/logs_model';
export const exploreItemUIStateSelector = (itemState: ExploreItemState) => {
const { showingGraph, showingLogs, showingTable, showingStartPage, dedupStrategy } = itemState;
return {
showingGraph,
showingLogs,
showingTable,
showingStartPage,
dedupStrategy,
};
};
const logsSelector = (state: ExploreItemState) => state.logsResult;
const hiddenLogLevelsSelector = (state: ExploreItemState) => state.hiddenLogLevels;
const dedupStrategySelector = (state: ExploreItemState) => state.dedupStrategy;
export const deduplicatedLogsSelector = createLodashMemoizedSelector(
logsSelector,
hiddenLogLevelsSelector,
dedupStrategySelector,
(logs, hiddenLogLevels, dedupStrategy) => {
if (!logs) {
return null;
}
const filteredData = filterLogLevels(logs, new Set(hiddenLogLevels));
return dedupLogRows(filteredData, dedupStrategy);
}
);
......@@ -11,7 +11,7 @@ import {
} from '@grafana/ui';
import { Emitter } from 'app/core/core';
import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
import { LogsModel, LogsDedupStrategy, LogLevel } from 'app/core/logs_model';
import TableModel from 'app/core/table_model';
export interface CompletionItem {
......@@ -242,6 +242,11 @@ export interface ExploreItemState {
* Current logs deduplication strategy
*/
dedupStrategy?: LogsDedupStrategy;
/**
* Currently hidden log series
*/
hiddenLogLevels?: LogLevel[];
}
export interface ExploreUIState {
......
......@@ -1833,6 +1833,13 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/reselect@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@types/reselect/-/reselect-2.2.0.tgz#c667206cfdc38190e1d379babe08865b2288575f"
integrity sha1-xmcgbP3DgZDh03m6vgiGWyKIV18=
dependencies:
reselect "*"
"@types/storybook__addon-actions@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@types/storybook__addon-actions/-/storybook__addon-actions-3.4.1.tgz#8f90d76b023b58ee794170f2fe774a3fddda2c1d"
......@@ -14823,6 +14830,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
reselect@*, reselect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment