Logs: Allow collapsing the logs volume histogram (#52808)

* logs: Allow disabling the logs volume histogram

* removed unnecessary code

* refactor: adjusted prop-name

* refactor: simplified code

* refactor: more readable code

* refactor: better naming

* refactor: better naming

* only unsubscribe when disabling the UI

* revert visual change

* re-apply visual change

This reverts commit 7fda5c197f.

* smoother transition

* adjusted visual

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* logs: top-gap reduced

* added feature tracking

* removed not-working feature-tracking property

* lint fix

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
This commit is contained in:
Gábor Farkas 2022-09-26 14:28:12 +02:00 committed by GitHub
parent 2efd7fa481
commit d8b4f776aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 316 additions and 207 deletions

View File

@ -18,6 +18,8 @@ describe('Logs', () => {
<Logs
exploreId={ExploreId.left}
splitOpen={() => undefined}
logsVolumeEnabled={true}
onSetLogsVolumeEnabled={() => null}
logsVolumeData={undefined}
loadLogsVolumeData={() => undefined}
logRows={rows}

View File

@ -32,6 +32,7 @@ import {
InlineSwitch,
withTheme2,
Themeable2,
Collapse,
} from '@grafana/ui';
import { dedupLogRows, filterLogLevels } from 'app/core/logsModel';
import store from 'app/core/store';
@ -43,14 +44,7 @@ import { LogRows } from '../logs/components/LogRows';
import { LogsMetaRow } from './LogsMetaRow';
import LogsNavigation from './LogsNavigation';
import { LogsVolumePanel } from './LogsVolumePanel';
const SETTINGS_KEYS = {
showLabels: 'grafana.explore.logs.showLabels',
showTime: 'grafana.explore.logs.showTime',
wrapLogMessage: 'grafana.explore.logs.wrapLogMessage',
prettifyLogMessage: 'grafana.explore.logs.prettifyLogMessage',
logsSortOrder: 'grafana.explore.logs.sortOrder',
};
import { SETTINGS_KEYS } from './utils/logs';
interface Props extends Themeable2 {
width: number;
@ -69,7 +63,9 @@ interface Props extends Themeable2 {
scanRange?: RawTimeRange;
exploreId: ExploreId;
datasourceType?: string;
logsVolumeEnabled: boolean;
logsVolumeData: DataQueryResponse | undefined;
onSetLogsVolumeEnabled: (enabled: boolean) => void;
loadLogsVolumeData: (exploreId: ExploreId) => void;
showContextToggle?: (row?: LogRowModel) => boolean;
onChangeTime: (range: AbsoluteTimeRange) => void;
@ -96,6 +92,16 @@ interface State {
forceEscape: boolean;
}
// We need to override css overflow of divs in Collapse element to enable sticky Logs navigation
const styleOverridesForStickyNavigation = css`
& > div {
overflow: visible;
& > div {
overflow: visible;
}
}
`;
class UnthemedLogs extends PureComponent<Props, State> {
flipOrderTimer?: number;
cancelFlippingTimer?: number;
@ -201,6 +207,14 @@ class UnthemedLogs extends PureComponent<Props, State> {
this.setState({ hiddenLogLevels });
};
onToggleLogsVolumeCollapse = (isOpen: boolean) => {
this.props.onSetLogsVolumeEnabled(isOpen);
reportInteraction('grafana_explore_logs_histogram_toggle_clicked', {
datasourceType: this.props.datasourceType,
type: isOpen ? 'open' : 'close',
});
};
onClickScan = (event: React.SyntheticEvent) => {
event.preventDefault();
if (this.props.onStartScanning) {
@ -284,6 +298,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
logsMeta,
logsSeries,
visibleRange,
logsVolumeEnabled,
logsVolumeData,
loadLogsVolumeData,
loading = false,
@ -329,163 +344,169 @@ class UnthemedLogs extends PureComponent<Props, State> {
return (
<>
<LogsVolumePanel
absoluteRange={absoluteRange}
width={width}
logsVolumeData={logsVolumeData}
logLinesBasedData={
logsSeries
? {
data: logsSeries,
state: loadingState,
}
: undefined
}
logLinesBasedDataVisibleRange={visibleRange}
onUpdateTimeRange={onChangeTime}
timeZone={timeZone}
splitOpen={splitOpen}
onLoadLogsVolume={() => loadLogsVolumeData(exploreId)}
onHiddenSeriesChanged={this.onToggleLogLevel}
/>
<div className={styles.logOptions} ref={this.topLogsRef}>
<InlineFieldRow>
<InlineField label="Time" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={showTime}
onChange={this.onChangeTime}
className={styles.horizontalInlineSwitch}
transparent
id={`show-time_${exploreId}`}
/>
</InlineField>
<InlineField label="Unique labels" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={showLabels}
onChange={this.onChangeLabels}
className={styles.horizontalInlineSwitch}
transparent
id={`unique-labels_${exploreId}`}
/>
</InlineField>
<InlineField label="Wrap lines" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={wrapLogMessage}
onChange={this.onChangeWrapLogMessage}
className={styles.horizontalInlineSwitch}
transparent
id={`wrap-lines_${exploreId}`}
/>
</InlineField>
<InlineField label="Prettify JSON" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={prettifyLogMessage}
onChange={this.onChangePrettifyLogMessage}
className={styles.horizontalInlineSwitch}
transparent
id={`prettify_${exploreId}`}
/>
</InlineField>
<InlineField label="Dedup" className={styles.horizontalInlineLabel} transparent>
<RadioButtonGroup
options={Object.values(LogsDedupStrategy).map((dedupType) => ({
label: capitalize(dedupType),
value: dedupType,
description: LogsDedupDescription[dedupType],
}))}
value={dedupStrategy}
onChange={this.onChangeDedup}
className={styles.radioButtons}
/>
</InlineField>
</InlineFieldRow>
<div>
<InlineField label="Display results" className={styles.horizontalInlineLabel} transparent>
<RadioButtonGroup
disabled={isFlipping}
options={[
{
label: 'Newest first',
value: LogsSortOrder.Descending,
description: 'Show results newest to oldest',
},
{
label: 'Oldest first',
value: LogsSortOrder.Ascending,
description: 'Show results oldest to newest',
},
]}
value={logsSortOrder}
onChange={this.onChangeLogsSortOrder}
className={styles.radioButtons}
/>
</InlineField>
</div>
</div>
<LogsMetaRow
logRows={logRows}
meta={logsMeta || []}
dedupStrategy={dedupStrategy}
dedupCount={dedupCount}
hasUnescapedContent={hasUnescapedContent}
forceEscape={forceEscape}
showDetectedFields={showDetectedFields}
onEscapeNewlines={this.onEscapeNewlines}
clearDetectedFields={this.clearDetectedFields}
/>
<div className={styles.logsSection}>
<div className={styles.logRows} data-testid="logRows">
<LogRows
logRows={logRows}
deduplicatedRows={dedupedRows}
dedupStrategy={dedupStrategy}
getRowContext={this.props.getRowContext}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
showContextToggle={showContextToggle}
showLabels={showLabels}
showTime={showTime}
enableLogDetails={true}
forceEscape={forceEscape}
wrapLogMessage={wrapLogMessage}
prettifyLogMessage={prettifyLogMessage}
<Collapse label="Logs volume" collapsible isOpen={logsVolumeEnabled} onToggle={this.onToggleLogsVolumeCollapse}>
{logsVolumeEnabled && (
<LogsVolumePanel
absoluteRange={absoluteRange}
width={width}
logsVolumeData={logsVolumeData}
logLinesBasedData={
logsSeries
? {
data: logsSeries,
state: loadingState,
}
: undefined
}
logLinesBasedDataVisibleRange={visibleRange}
onUpdateTimeRange={onChangeTime}
timeZone={timeZone}
getFieldLinks={getFieldLinks}
splitOpen={splitOpen}
onLoadLogsVolume={() => loadLogsVolumeData(exploreId)}
onHiddenSeriesChanged={this.onToggleLogLevel}
/>
)}
</Collapse>
<Collapse label="Logs" loading={loading} isOpen className={styleOverridesForStickyNavigation}>
<div className={styles.logOptions} ref={this.topLogsRef}>
<InlineFieldRow>
<InlineField label="Time" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={showTime}
onChange={this.onChangeTime}
className={styles.horizontalInlineSwitch}
transparent
id={`show-time_${exploreId}`}
/>
</InlineField>
<InlineField label="Unique labels" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={showLabels}
onChange={this.onChangeLabels}
className={styles.horizontalInlineSwitch}
transparent
id={`unique-labels_${exploreId}`}
/>
</InlineField>
<InlineField label="Wrap lines" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={wrapLogMessage}
onChange={this.onChangeWrapLogMessage}
className={styles.horizontalInlineSwitch}
transparent
id={`wrap-lines_${exploreId}`}
/>
</InlineField>
<InlineField label="Prettify JSON" className={styles.horizontalInlineLabel} transparent>
<InlineSwitch
value={prettifyLogMessage}
onChange={this.onChangePrettifyLogMessage}
className={styles.horizontalInlineSwitch}
transparent
id={`prettify_${exploreId}`}
/>
</InlineField>
<InlineField label="Dedup" className={styles.horizontalInlineLabel} transparent>
<RadioButtonGroup
options={Object.values(LogsDedupStrategy).map((dedupType) => ({
label: capitalize(dedupType),
value: dedupType,
description: LogsDedupDescription[dedupType],
}))}
value={dedupStrategy}
onChange={this.onChangeDedup}
className={styles.radioButtons}
/>
</InlineField>
</InlineFieldRow>
<div>
<InlineField label="Display results" className={styles.horizontalInlineLabel} transparent>
<RadioButtonGroup
disabled={isFlipping}
options={[
{
label: 'Newest first',
value: LogsSortOrder.Descending,
description: 'Show results newest to oldest',
},
{
label: 'Oldest first',
value: LogsSortOrder.Ascending,
description: 'Show results oldest to newest',
},
]}
value={logsSortOrder}
onChange={this.onChangeLogsSortOrder}
className={styles.radioButtons}
/>
</InlineField>
</div>
</div>
<LogsMetaRow
logRows={logRows}
meta={logsMeta || []}
dedupStrategy={dedupStrategy}
dedupCount={dedupCount}
hasUnescapedContent={hasUnescapedContent}
forceEscape={forceEscape}
showDetectedFields={showDetectedFields}
onEscapeNewlines={this.onEscapeNewlines}
clearDetectedFields={this.clearDetectedFields}
/>
<div className={styles.logsSection}>
<div className={styles.logRows} data-testid="logRows">
<LogRows
logRows={logRows}
deduplicatedRows={dedupedRows}
dedupStrategy={dedupStrategy}
getRowContext={this.props.getRowContext}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
showContextToggle={showContextToggle}
showLabels={showLabels}
showTime={showTime}
enableLogDetails={true}
forceEscape={forceEscape}
wrapLogMessage={wrapLogMessage}
prettifyLogMessage={prettifyLogMessage}
timeZone={timeZone}
getFieldLinks={getFieldLinks}
logsSortOrder={logsSortOrder}
showDetectedFields={showDetectedFields}
onClickShowDetectedField={this.showDetectedField}
onClickHideDetectedField={this.hideDetectedField}
/>
</div>
<LogsNavigation
logsSortOrder={logsSortOrder}
showDetectedFields={showDetectedFields}
onClickShowDetectedField={this.showDetectedField}
onClickHideDetectedField={this.hideDetectedField}
visibleRange={navigationRange ?? absoluteRange}
absoluteRange={absoluteRange}
timeZone={timeZone}
onChangeTime={onChangeTime}
loading={loading}
queries={logsQueries ?? []}
scrollToTopLogs={this.scrollToTopLogs}
addResultsToCache={addResultsToCache}
clearCache={clearCache}
/>
</div>
<LogsNavigation
logsSortOrder={logsSortOrder}
visibleRange={navigationRange ?? absoluteRange}
absoluteRange={absoluteRange}
timeZone={timeZone}
onChangeTime={onChangeTime}
loading={loading}
queries={logsQueries ?? []}
scrollToTopLogs={this.scrollToTopLogs}
addResultsToCache={addResultsToCache}
clearCache={clearCache}
/>
</div>
{!loading && !hasData && !scanning && (
<div className={styles.noData}>
No logs found.
<Button size="xs" fill="text" onClick={this.onClickScan}>
Scan for older logs
</Button>
</div>
)}
{scanning && (
<div className={styles.noData}>
<span>{scanText}</span>
<Button size="xs" fill="text" onClick={this.onClickStopScan}>
Stop scan
</Button>
</div>
)}
{!loading && !hasData && !scanning && (
<div className={styles.noData}>
No logs found.
<Button size="xs" fill="text" onClick={this.onClickScan}>
Scan for older logs
</Button>
</div>
)}
{scanning && (
<div className={styles.noData}>
<span>{scanText}</span>
<Button size="xs" fill="text" onClick={this.onClickStopScan}>
Stop scan
</Button>
</div>
)}
</Collapse>
</>
);
}
@ -508,7 +529,7 @@ const getStyles = (theme: GrafanaTheme2, wrapLogMessage: boolean) => {
background-color: ${theme.colors.background.primary};
padding: ${theme.spacing(1, 2)};
border-radius: ${theme.shape.borderRadius()};
margin: ${theme.spacing(2, 0, 1)};
margin: ${theme.spacing(0, 0, 1)};
border: 1px solid ${theme.colors.border.medium};
`,
headerButton: css`

View File

@ -1,4 +1,3 @@
import { css } from '@emotion/css';
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
@ -19,7 +18,7 @@ import { getTimeZone } from '../profile/state/selectors';
import { LiveLogsWithTheme } from './LiveLogs';
import { Logs } from './Logs';
import { splitOpen } from './state/main';
import { addResultsToCache, clearCache, loadLogsVolumeData } from './state/query';
import { addResultsToCache, clearCache, loadLogsVolumeData, setLogsVolumeEnabled } from './state/query';
import { updateTimeRange } from './state/time';
import { LiveTailControls } from './useLiveTailControls';
import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition';
@ -104,16 +103,6 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
return null;
}
// We need to override css overflow of divs in Collapse element to enable sticky Logs navigation
const styleOverridesForStickyNavigation = css`
& > div {
overflow: visible;
& > div {
overflow: visible;
}
}
`;
return (
<>
<LogsCrossFadeTransition visible={isLive}>
@ -133,37 +122,37 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
</Collapse>
</LogsCrossFadeTransition>
<LogsCrossFadeTransition visible={!isLive}>
<Collapse label="Logs" loading={loading} isOpen className={styleOverridesForStickyNavigation}>
<Logs
exploreId={exploreId}
datasourceType={this.props.datasourceInstance?.type}
logRows={logRows}
logsMeta={logsMeta}
logsSeries={logsSeries}
logsVolumeData={logsVolumeData}
logsQueries={logsQueries}
width={width}
splitOpen={splitOpen}
loading={loading}
loadingState={loadingState}
loadLogsVolumeData={loadLogsVolumeData}
onChangeTime={this.onChangeTime}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
onStartScanning={onStartScanning}
onStopScanning={onStopScanning}
absoluteRange={absoluteRange}
visibleRange={visibleRange}
timeZone={timeZone}
scanning={scanning}
scanRange={range.raw}
showContextToggle={this.showContextToggle}
getRowContext={this.getLogRowContext}
getFieldLinks={this.getFieldLinks}
addResultsToCache={() => addResultsToCache(exploreId)}
clearCache={() => clearCache(exploreId)}
/>
</Collapse>
<Logs
exploreId={exploreId}
datasourceType={this.props.datasourceInstance?.type}
logRows={logRows}
logsMeta={logsMeta}
logsSeries={logsSeries}
logsVolumeEnabled={this.props.logsVolumeEnabled}
onSetLogsVolumeEnabled={(enabled) => this.props.setLogsVolumeEnabled(exploreId, enabled)}
logsVolumeData={logsVolumeData}
logsQueries={logsQueries}
width={width}
splitOpen={splitOpen}
loading={loading}
loadingState={loadingState}
loadLogsVolumeData={loadLogsVolumeData}
onChangeTime={this.onChangeTime}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
onStartScanning={onStartScanning}
onStopScanning={onStopScanning}
absoluteRange={absoluteRange}
visibleRange={visibleRange}
timeZone={timeZone}
scanning={scanning}
scanRange={range.raw}
showContextToggle={this.showContextToggle}
getRowContext={this.getLogRowContext}
getFieldLinks={this.getFieldLinks}
addResultsToCache={() => addResultsToCache(exploreId)}
clearCache={() => clearCache(exploreId)}
/>
</LogsCrossFadeTransition>
</>
);
@ -183,6 +172,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
isPaused,
range,
absoluteRange,
logsVolumeEnabled,
logsVolumeDataProvider,
logsVolumeData,
} = item;
@ -202,6 +192,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
isPaused,
range,
absoluteRange,
logsVolumeEnabled,
logsVolumeDataProvider,
logsVolumeData,
};
@ -213,6 +204,7 @@ const mapDispatchToProps = {
addResultsToCache,
clearCache,
loadLogsVolumeData,
setLogsVolumeEnabled,
};
const connector = connect(mapStateToProps, mapDispatchToProps);

View File

@ -40,6 +40,7 @@ export const createDefaultInitialState = () => {
},
cache: [],
richHistory: [],
logsVolumeEnabled: true,
},
},
};

View File

@ -35,6 +35,7 @@ import {
scanStartAction,
scanStopAction,
storeLogsVolumeDataProviderAction,
setLogsVolumeEnabled,
} from './query';
import { makeExplorePaneState } from './utils';
@ -465,5 +466,34 @@ describe('reducer', () => {
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Done);
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
});
it('do not load logsVolume data when disabled', async () => {
// turn logsvolume off
dispatch(setLogsVolumeEnabled(ExploreId.left, false));
expect(getState().explore[ExploreId.left].logsVolumeEnabled).toBe(false);
// verify that if we run a query, it will not do logsvolume, but the Provider will still be set
await dispatch(runQueries(ExploreId.left));
expect(getState().explore[ExploreId.left].logsVolumeData).toBeUndefined();
expect(getState().explore[ExploreId.left].logsVolumeDataSubscription).toBeUndefined();
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
});
it('load logsVolume data when it gets enabled', async () => {
// first it is disabled
dispatch(setLogsVolumeEnabled(ExploreId.left, false));
// runQueries sets up the logsVolume query, but does not run it
await dispatch(runQueries(ExploreId.left));
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
// we turn logsvolume on
await dispatch(setLogsVolumeEnabled(ExploreId.left, true));
// verify it was turned on
expect(getState().explore[ExploreId.left].logsVolumeEnabled).toBe(true);
expect(getState().explore[ExploreId.left].logsVolumeDataSubscription).toBeDefined();
});
});
});

View File

@ -45,7 +45,7 @@ import { decorateData } from '../utils/decorators';
import { addHistoryItem, historyUpdatedAction, loadRichHistory } from './history';
import { stateSave } from './main';
import { updateTime } from './time';
import { createCacheKey, getResultsFromCache } from './utils';
import { createCacheKey, getResultsFromCache, storeLogsVolumeEnabled } from './utils';
//
// Actions and Payloads
@ -109,6 +109,10 @@ export const queryStoreSubscriptionAction = createAction<QueryStoreSubscriptionP
'explore/queryStoreSubscription'
);
const setLogsVolumeEnabledAction = createAction<{ exploreId: ExploreId; enabled: boolean }>(
'explore/setLogsVolumeEnabledAction'
);
export interface StoreLogsVolumeDataProvider {
exploreId: ExploreId;
logsVolumeDataProvider?: Observable<DataQueryResponse>;
@ -415,6 +419,7 @@ export const runQueries = (
refreshInterval,
absoluteRange,
cache,
logsVolumeEnabled,
} = exploreItemState;
let newQuerySub;
@ -550,6 +555,12 @@ export const runQueries = (
);
dispatch(cleanLogsVolumeAction({ exploreId }));
} else if (hasLogsVolumeSupport(datasourceInstance)) {
// we always prepare the logsVolumeProvider,
// but we only load it, if the logs-volume-histogram is enabled.
// (we need to have the logsVolumeProvider always actual,
// even when the visuals are disabled, because when the user
// enables the visuals again, we need to load the histogram,
// so we need the provider)
const sourceRequest = {
...transaction.request,
requestId: transaction.request.requestId + '_log_volume',
@ -564,7 +575,9 @@ export const runQueries = (
const { logsVolumeData, absoluteRange } = getState().explore[exploreId]!;
if (!canReuseLogsVolumeData(logsVolumeData, queries, absoluteRange)) {
dispatch(cleanLogsVolumeAction({ exploreId }));
dispatch(loadLogsVolumeData(exploreId));
if (logsVolumeEnabled) {
dispatch(loadLogsVolumeData(exploreId));
}
}
} else {
dispatch(
@ -670,6 +683,16 @@ export function loadLogsVolumeData(exploreId: ExploreId): ThunkResult<void> {
};
}
export function setLogsVolumeEnabled(exploreId: ExploreId, enabled: boolean): ThunkResult<void> {
return (dispatch, getState) => {
dispatch(setLogsVolumeEnabledAction({ exploreId, enabled }));
storeLogsVolumeEnabled(enabled);
if (enabled) {
dispatch(loadLogsVolumeData(exploreId));
}
};
}
//
// Reducer
//
@ -757,6 +780,20 @@ export const queryReducer = (state: ExploreItemState, action: AnyAction): Explor
};
}
if (setLogsVolumeEnabledAction.match(action)) {
const { enabled } = action.payload;
if (!enabled && state.logsVolumeDataSubscription) {
state.logsVolumeDataSubscription.unsubscribe();
}
return {
...state,
logsVolumeEnabled: enabled,
// NOTE: the dataProvider is not cleared, we may need it later,
// if the user re-enables the histogram-visualization
logsVolumeData: undefined,
};
}
if (storeLogsVolumeDataProviderAction.match(action)) {
let { logsVolumeDataProvider } = action.payload;
if (state.logsVolumeDataSubscription) {

View File

@ -17,6 +17,7 @@ import { ExploreGraphStyle, ExploreItemState } from 'app/types/explore';
import store from '../../../core/store';
import { clearQueryKeys, lastUsedDatasourceKeyForOrgId, toGraphStyle } from '../../../core/utils/explore';
import { getDatasourceSrv } from '../../plugins/datasource_srv';
import { SETTINGS_KEYS } from '../utils/logs';
import { toRawTimeRange } from '../utils/time';
export const DEFAULT_RANGE = {
@ -34,6 +35,21 @@ const loadGraphStyle = (): ExploreGraphStyle => {
return toGraphStyle(data);
};
const LOGS_VOLUME_ENABLED_KEY = SETTINGS_KEYS.enableVolumeHistogram;
export const storeLogsVolumeEnabled = (enabled: boolean): void => {
store.set(LOGS_VOLUME_ENABLED_KEY, enabled ? 'true' : 'false');
};
const loadLogsVolumeEnabled = (): boolean => {
const data = store.get(LOGS_VOLUME_ENABLED_KEY);
// we default to `enabled=true`
if (data === 'false') {
return false;
}
return true;
};
/**
* Returns a fresh Explore area state
*/
@ -65,6 +81,7 @@ export const makeExplorePaneState = (): ExploreItemState => ({
eventBridge: null as unknown as EventBusExtended,
cache: [],
richHistory: [],
logsVolumeEnabled: loadLogsVolumeEnabled(),
logsVolumeDataProvider: undefined,
logsVolumeData: undefined,
graphStyle: loadGraphStyle(),

View File

@ -0,0 +1,8 @@
export const SETTINGS_KEYS = {
showLabels: 'grafana.explore.logs.showLabels',
showTime: 'grafana.explore.logs.showTime',
wrapLogMessage: 'grafana.explore.logs.wrapLogMessage',
prettifyLogMessage: 'grafana.explore.logs.prettifyLogMessage',
logsSortOrder: 'grafana.explore.logs.sortOrder',
enableVolumeHistogram: 'grafana.explore.logs.enableVolumeHistogram',
};

View File

@ -192,6 +192,7 @@ export interface ExploreItemState {
// properties below should be more generic if we add more providers
// see also: DataSourceWithLogsVolumeSupport
logsVolumeEnabled: boolean;
logsVolumeDataProvider?: Observable<DataQueryResponse>;
logsVolumeDataSubscription?: SubscriptionLike;
logsVolumeData?: DataQueryResponse;