mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
Logs volume: Refactor (#60998)
* Rename log volume in redux to supp query to make it more generic
* Change enabled query to queries
* Small spell fix StoreSuppQueryDataProviderAction -> storeSuppQueryDataProviderAction
* WIP
* Improve
* WIP
* Rename
* Move to 1
* Small updates
* Use enum
* Unify naming
* Use SUPP_QUERY_TYPES instead of Object.keys()
* Move SuppQueryType to types/explore
* Rename suppQuery to supportingQuery
* Rename SUPP_QUERY_TYPES to SUPPORTING_QUERY_TYPES
* Rename supporting to supplementary 🙈
* Remove suppQueryData && suppQueryData.data[0] check as it is redundant
* Update public/app/features/explore/state/query.ts
Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
* Update public/app/features/explore/state/query.ts
Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
* Fix naming of SupplementaryQuery interface
Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
This commit is contained in:
parent
26a3c864f3
commit
ddc8beda07
@ -71,7 +71,7 @@ interface Props extends Themeable2 {
|
||||
logsVolumeData: DataQueryResponse | undefined;
|
||||
scrollElement?: HTMLDivElement;
|
||||
onSetLogsVolumeEnabled: (enabled: boolean) => void;
|
||||
loadLogsVolumeData: (exploreId: ExploreId) => void;
|
||||
loadLogsVolumeData: () => void;
|
||||
showContextToggle?: (row?: LogRowModel) => boolean;
|
||||
onChangeTime: (range: AbsoluteTimeRange) => void;
|
||||
onClickFilterLabel?: (key: string, value: string) => void;
|
||||
@ -389,7 +389,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
onUpdateTimeRange={onChangeTime}
|
||||
timeZone={timeZone}
|
||||
splitOpen={splitOpen}
|
||||
onLoadLogsVolume={() => loadLogsVolumeData(exploreId)}
|
||||
onLoadLogsVolume={loadLogsVolumeData}
|
||||
onHiddenSeriesChanged={this.onToggleLogLevel}
|
||||
eventBus={this.logsVolumeEventBus}
|
||||
/>
|
||||
|
@ -14,13 +14,13 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { Collapse } from '@grafana/ui';
|
||||
import { StoreState } from 'app/types';
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { ExploreId, ExploreItemState, SupplementaryQueryType } from 'app/types/explore';
|
||||
|
||||
import { getTimeZone } from '../profile/state/selectors';
|
||||
|
||||
import { LiveLogsWithTheme } from './LiveLogs';
|
||||
import { Logs } from './Logs';
|
||||
import { addResultsToCache, clearCache, loadLogsVolumeData, setLogsVolumeEnabled } from './state/query';
|
||||
import { addResultsToCache, clearCache, loadSupplementaryQueryData, setSupplementaryQueryEnabled } from './state/query';
|
||||
import { updateTimeRange } from './state/time';
|
||||
import { LiveTailControls } from './useLiveTailControls';
|
||||
import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition';
|
||||
@ -85,8 +85,8 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
logsMeta,
|
||||
logsSeries,
|
||||
logsQueries,
|
||||
logsVolumeData,
|
||||
loadLogsVolumeData,
|
||||
loadSupplementaryQueryData,
|
||||
setSupplementaryQueryEnabled,
|
||||
onClickFilterLabel,
|
||||
onClickFilterOutLabel,
|
||||
onStartScanning,
|
||||
@ -103,6 +103,7 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
addResultsToCache,
|
||||
clearCache,
|
||||
scrollElement,
|
||||
logsVolume,
|
||||
} = this.props;
|
||||
|
||||
if (!logRows) {
|
||||
@ -134,15 +135,17 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
logRows={logRows}
|
||||
logsMeta={logsMeta}
|
||||
logsSeries={logsSeries}
|
||||
logsVolumeEnabled={this.props.logsVolumeEnabled}
|
||||
onSetLogsVolumeEnabled={(enabled) => this.props.setLogsVolumeEnabled(exploreId, enabled)}
|
||||
logsVolumeData={logsVolumeData}
|
||||
logsVolumeEnabled={logsVolume.enabled}
|
||||
onSetLogsVolumeEnabled={(enabled) =>
|
||||
setSupplementaryQueryEnabled(exploreId, enabled, SupplementaryQueryType.LogsVolume)
|
||||
}
|
||||
logsVolumeData={logsVolume.data}
|
||||
logsQueries={logsQueries}
|
||||
width={width}
|
||||
splitOpen={splitOpenFn}
|
||||
loading={loading}
|
||||
loadingState={loadingState}
|
||||
loadLogsVolumeData={loadLogsVolumeData}
|
||||
loadLogsVolumeData={() => loadSupplementaryQueryData(exploreId, SupplementaryQueryType.LogsVolume)}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickFilterLabel={onClickFilterLabel}
|
||||
onClickFilterOutLabel={onClickFilterOutLabel}
|
||||
@ -180,11 +183,10 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
|
||||
isPaused,
|
||||
range,
|
||||
absoluteRange,
|
||||
logsVolumeEnabled,
|
||||
logsVolumeDataProvider,
|
||||
logsVolumeData,
|
||||
supplementaryQueries,
|
||||
} = item;
|
||||
const timeZone = getTimeZone(state.user);
|
||||
const logsVolume = supplementaryQueries[SupplementaryQueryType.LogsVolume];
|
||||
|
||||
return {
|
||||
loading,
|
||||
@ -200,9 +202,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
|
||||
isPaused,
|
||||
range,
|
||||
absoluteRange,
|
||||
logsVolumeEnabled,
|
||||
logsVolumeDataProvider,
|
||||
logsVolumeData,
|
||||
logsVolume,
|
||||
};
|
||||
}
|
||||
|
||||
@ -210,8 +210,8 @@ const mapDispatchToProps = {
|
||||
updateTimeRange,
|
||||
addResultsToCache,
|
||||
clearCache,
|
||||
loadLogsVolumeData,
|
||||
setLogsVolumeEnabled,
|
||||
loadSupplementaryQueryData,
|
||||
setSupplementaryQueryEnabled,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
@ -10,7 +10,7 @@ import { ExploreId } from 'app/types/explore';
|
||||
|
||||
import { importQueries, runQueries } from './query';
|
||||
import { changeRefreshInterval } from './time';
|
||||
import { createEmptyQueryResponse, loadAndInitDatasource } from './utils';
|
||||
import { createEmptyQueryResponse, loadAndInitDatasource, loadSupplementaryQueries } from './utils';
|
||||
|
||||
//
|
||||
// Actions and Payloads
|
||||
@ -99,8 +99,7 @@ export const datasourceReducer = (state: ExploreItemState, action: AnyAction): E
|
||||
graphResult: null,
|
||||
tableResult: null,
|
||||
logsResult: null,
|
||||
logsVolumeDataProvider: undefined,
|
||||
logsVolumeData: undefined,
|
||||
supplementaryQueries: loadSupplementaryQueries(),
|
||||
queryResponse: createEmptyQueryResponse(),
|
||||
loading: false,
|
||||
queryKeys: [],
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DefaultTimeZone, toUtc } from '@grafana/data';
|
||||
|
||||
import { ExploreId } from '../../../types';
|
||||
import { ExploreId, SupplementaryQueryType } from '../../../types';
|
||||
|
||||
export const createDefaultInitialState = () => {
|
||||
const t = toUtc();
|
||||
@ -40,7 +40,11 @@ export const createDefaultInitialState = () => {
|
||||
},
|
||||
cache: [],
|
||||
richHistory: [],
|
||||
logsVolumeEnabled: true,
|
||||
supplementaryQueries: {
|
||||
[SupplementaryQueryType.LogsVolume]: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
MutableDataFrame,
|
||||
RawTimeRange,
|
||||
} from '@grafana/data';
|
||||
import { ExploreId, ExploreItemState, StoreState, ThunkDispatch } from 'app/types';
|
||||
import { ExploreId, ExploreItemState, StoreState, SupplementaryQueryType, ThunkDispatch } from 'app/types';
|
||||
|
||||
import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
||||
import { configureStore } from '../../../store/configureStore';
|
||||
@ -26,15 +26,15 @@ import {
|
||||
addResultsToCache,
|
||||
cancelQueries,
|
||||
cancelQueriesAction,
|
||||
cleanLogsVolumeAction,
|
||||
cleanSupplementaryQueryAction,
|
||||
clearCache,
|
||||
importQueries,
|
||||
queryReducer,
|
||||
runQueries,
|
||||
scanStartAction,
|
||||
scanStopAction,
|
||||
storeLogsVolumeDataProviderAction,
|
||||
setLogsVolumeEnabled,
|
||||
storeSupplementaryQueryDataProviderAction,
|
||||
setSupplementaryQueryEnabled,
|
||||
} from './query';
|
||||
import { makeExplorePaneState } from './utils';
|
||||
|
||||
@ -164,6 +164,7 @@ describe('running queries', () => {
|
||||
querySubscription: unsubscribable,
|
||||
queries: ['A'],
|
||||
range: testRange,
|
||||
supplementaryQueries: { [SupplementaryQueryType.LogsVolume]: { enabled: true } },
|
||||
},
|
||||
},
|
||||
|
||||
@ -179,8 +180,8 @@ describe('running queries', () => {
|
||||
expect(dispatchedActions).toEqual([
|
||||
scanStopAction({ exploreId }),
|
||||
cancelQueriesAction({ exploreId }),
|
||||
storeLogsVolumeDataProviderAction({ exploreId, logsVolumeDataProvider: undefined }),
|
||||
cleanLogsVolumeAction({ exploreId }),
|
||||
storeSupplementaryQueryDataProviderAction({ exploreId, type: SupplementaryQueryType.LogsVolume }),
|
||||
cleanSupplementaryQueryAction({ exploreId, type: SupplementaryQueryType.LogsVolume }),
|
||||
]);
|
||||
});
|
||||
});
|
||||
@ -433,8 +434,12 @@ describe('reducer', () => {
|
||||
expect(unsubscribes).toHaveLength(1);
|
||||
expect(unsubscribes[0]).toBeCalled();
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeUndefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should load logs volume after running the query', async () => {
|
||||
@ -448,13 +453,23 @@ describe('reducer', () => {
|
||||
};
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Loading);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data!.state
|
||||
).toBe(LoadingState.Loading);
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).toBeDefined();
|
||||
|
||||
await dispatch(cancelQueries(ExploreId.left));
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeUndefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it('keeps complete log volume data when main query is canceled', async () => {
|
||||
@ -466,43 +481,69 @@ describe('reducer', () => {
|
||||
};
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Done);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data!.state
|
||||
).toBe(LoadingState.Done);
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).toBeDefined();
|
||||
|
||||
await dispatch(cancelQueries(ExploreId.left));
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Done);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data!.state
|
||||
).toBe(LoadingState.Done);
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).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);
|
||||
dispatch(setSupplementaryQueryEnabled(ExploreId.left, false, SupplementaryQueryType.LogsVolume));
|
||||
expect(getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].enabled).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();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].data
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataSubscription
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).toBeDefined();
|
||||
});
|
||||
|
||||
it('load logsVolume data when it gets enabled', async () => {
|
||||
// first it is disabled
|
||||
dispatch(setLogsVolumeEnabled(ExploreId.left, false));
|
||||
dispatch(setSupplementaryQueryEnabled(ExploreId.left, false, SupplementaryQueryType.LogsVolume));
|
||||
|
||||
// runQueries sets up the logsVolume query, but does not run it
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataProvider
|
||||
).toBeDefined();
|
||||
|
||||
// we turn logsvolume on
|
||||
await dispatch(setLogsVolumeEnabled(ExploreId.left, true));
|
||||
await dispatch(setSupplementaryQueryEnabled(ExploreId.left, true, SupplementaryQueryType.LogsVolume));
|
||||
|
||||
// verify it was turned on
|
||||
expect(getState().explore[ExploreId.left].logsVolumeEnabled).toBe(true);
|
||||
expect(getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].enabled).toBe(
|
||||
true
|
||||
);
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataSubscription).toBeDefined();
|
||||
expect(
|
||||
getState().explore[ExploreId.left].supplementaryQueries[SupplementaryQueryType.LogsVolume].dataSubscription
|
||||
).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -36,7 +36,7 @@ import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||
import { store } from 'app/store/store';
|
||||
import { ExploreItemState, ExplorePanelData, ThunkDispatch, ThunkResult } from 'app/types';
|
||||
import { ExploreId, ExploreState, QueryOptions } from 'app/types/explore';
|
||||
import { ExploreId, ExploreState, QueryOptions, SupplementaryQueryType, SupplementaryQueries } from 'app/types/explore';
|
||||
|
||||
import { notifyApp } from '../../../core/actions';
|
||||
import { createErrorNotification } from '../../../core/copy/appNotification';
|
||||
@ -46,7 +46,12 @@ import { decorateData } from '../utils/decorators';
|
||||
import { addHistoryItem, historyUpdatedAction, loadRichHistory } from './history';
|
||||
import { stateSave } from './main';
|
||||
import { updateTime } from './time';
|
||||
import { createCacheKey, getResultsFromCache, storeLogsVolumeEnabled } from './utils';
|
||||
import {
|
||||
createCacheKey,
|
||||
getResultsFromCache,
|
||||
storeSupplementaryQueryEnabled,
|
||||
SUPPLEMENTARY_QUERY_TYPES,
|
||||
} from './utils';
|
||||
|
||||
//
|
||||
// Actions and Payloads
|
||||
@ -95,43 +100,50 @@ export const queryStoreSubscriptionAction = createAction<QueryStoreSubscriptionP
|
||||
'explore/queryStoreSubscription'
|
||||
);
|
||||
|
||||
const setLogsVolumeEnabledAction = createAction<{ exploreId: ExploreId; enabled: boolean }>(
|
||||
'explore/setLogsVolumeEnabledAction'
|
||||
);
|
||||
|
||||
export interface StoreLogsVolumeDataProvider {
|
||||
const setSupplementaryQueryEnabledAction = createAction<{
|
||||
exploreId: ExploreId;
|
||||
logsVolumeDataProvider?: Observable<DataQueryResponse>;
|
||||
type: SupplementaryQueryType;
|
||||
enabled: boolean;
|
||||
}>('explore/setSupplementaryQueryEnabledAction');
|
||||
|
||||
export interface StoreSupplementaryQueryDataProvider {
|
||||
exploreId: ExploreId;
|
||||
dataProvider?: Observable<DataQueryResponse>;
|
||||
type: SupplementaryQueryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores available logs volume provider after running the query. Used internally by runQueries().
|
||||
*/
|
||||
export const storeLogsVolumeDataProviderAction = createAction<StoreLogsVolumeDataProvider>(
|
||||
'explore/storeLogsVolumeDataProviderAction'
|
||||
export const storeSupplementaryQueryDataProviderAction = createAction<StoreSupplementaryQueryDataProvider>(
|
||||
'explore/storeSupplementaryQueryDataProviderAction'
|
||||
);
|
||||
|
||||
export const cleanLogsVolumeAction = createAction<{ exploreId: ExploreId }>('explore/cleanLogsVolumeAction');
|
||||
export const cleanSupplementaryQueryAction = createAction<{ exploreId: ExploreId; type: SupplementaryQueryType }>(
|
||||
'explore/cleanSupplementaryQueryAction'
|
||||
);
|
||||
|
||||
export interface StoreLogsVolumeDataSubscriptionPayload {
|
||||
export interface StoreSupplementaryQueryDataSubscriptionPayload {
|
||||
exploreId: ExploreId;
|
||||
logsVolumeDataSubscription?: SubscriptionLike;
|
||||
dataSubscription?: SubscriptionLike;
|
||||
type: SupplementaryQueryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores current logs volume subscription for given explore pane.
|
||||
*/
|
||||
const storeLogsVolumeDataSubscriptionAction = createAction<StoreLogsVolumeDataSubscriptionPayload>(
|
||||
'explore/storeLogsVolumeDataSubscriptionAction'
|
||||
const storeSupplementaryQueryDataSubscriptionAction = createAction<StoreSupplementaryQueryDataSubscriptionPayload>(
|
||||
'explore/storeSupplementaryQueryDataSubscriptionAction'
|
||||
);
|
||||
|
||||
/**
|
||||
* Stores data returned by the provider. Used internally by loadLogsVolumeData().
|
||||
* Stores data returned by the provider. Used internally by loadSupplementaryQueryData().
|
||||
*/
|
||||
const updateLogsVolumeDataAction = createAction<{
|
||||
const updateSupplementaryQueryDataAction = createAction<{
|
||||
exploreId: ExploreId;
|
||||
logsVolumeData: DataQueryResponse;
|
||||
}>('explore/updateLogsVolumeDataAction');
|
||||
type: SupplementaryQueryType;
|
||||
data: DataQueryResponse;
|
||||
}>('explore/updateSupplementaryQueryDataAction');
|
||||
|
||||
export interface QueryEndedPayload {
|
||||
exploreId: ExploreId;
|
||||
@ -231,15 +243,16 @@ export function cancelQueries(exploreId: ExploreId): ThunkResult<void> {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(scanStopAction({ exploreId }));
|
||||
dispatch(cancelQueriesAction({ exploreId }));
|
||||
dispatch(
|
||||
storeLogsVolumeDataProviderAction({
|
||||
exploreId,
|
||||
logsVolumeDataProvider: undefined,
|
||||
})
|
||||
);
|
||||
// clear any incomplete data
|
||||
if (getState().explore[exploreId]!.logsVolumeData?.state !== LoadingState.Done) {
|
||||
dispatch(cleanLogsVolumeAction({ exploreId }));
|
||||
|
||||
const supplementaryQueries = getState().explore[exploreId]!.supplementaryQueries;
|
||||
// Cancel all data providers
|
||||
for (const type of SUPPLEMENTARY_QUERY_TYPES) {
|
||||
dispatch(storeSupplementaryQueryDataProviderAction({ exploreId, dataProvider: undefined, type }));
|
||||
|
||||
// And clear any incomplete data
|
||||
if (supplementaryQueries[type]?.data?.state !== LoadingState.Done) {
|
||||
dispatch(cleanSupplementaryQueryAction({ exploreId, type }));
|
||||
}
|
||||
}
|
||||
dispatch(stateSave());
|
||||
};
|
||||
@ -425,7 +438,6 @@ export const runQueries = (
|
||||
refreshInterval,
|
||||
absoluteRange,
|
||||
cache,
|
||||
logsVolumeEnabled,
|
||||
} = exploreItemState;
|
||||
let newQuerySub;
|
||||
|
||||
@ -558,13 +570,25 @@ export const runQueries = (
|
||||
});
|
||||
|
||||
if (live) {
|
||||
dispatch(
|
||||
storeLogsVolumeDataProviderAction({
|
||||
exploreId,
|
||||
logsVolumeDataProvider: undefined,
|
||||
})
|
||||
);
|
||||
dispatch(cleanLogsVolumeAction({ exploreId }));
|
||||
for (const type of SUPPLEMENTARY_QUERY_TYPES) {
|
||||
dispatch(
|
||||
storeSupplementaryQueryDataProviderAction({
|
||||
exploreId,
|
||||
dataProvider: undefined,
|
||||
type,
|
||||
})
|
||||
);
|
||||
dispatch(cleanSupplementaryQueryAction({ exploreId, type }));
|
||||
}
|
||||
|
||||
// In this whole part., we need to figure out
|
||||
// checking the type of enabled supp queries
|
||||
// then for which enabled supp queries has data source support
|
||||
// and then we need to run the supp queries
|
||||
// but we need to make sure that supp queries that dont work
|
||||
// return undefined provider
|
||||
// we should also make sure we store the type of provider that
|
||||
// was last stored
|
||||
} else if (hasLogsVolumeSupport(datasourceInstance)) {
|
||||
// we always prepare the logsVolumeProvider,
|
||||
// but we only load it, if the logs-volume-histogram is enabled.
|
||||
@ -576,25 +600,29 @@ export const runQueries = (
|
||||
...transaction.request,
|
||||
requestId: transaction.request.requestId + '_log_volume',
|
||||
};
|
||||
const logsVolumeDataProvider = datasourceInstance.getLogsVolumeDataProvider(sourceRequest);
|
||||
const type = SupplementaryQueryType.LogsVolume;
|
||||
const dataProvider = datasourceInstance.getLogsVolumeDataProvider(sourceRequest);
|
||||
dispatch(
|
||||
storeLogsVolumeDataProviderAction({
|
||||
storeSupplementaryQueryDataProviderAction({
|
||||
exploreId,
|
||||
logsVolumeDataProvider,
|
||||
type,
|
||||
dataProvider,
|
||||
})
|
||||
);
|
||||
const { logsVolumeData, absoluteRange } = getState().explore[exploreId]!;
|
||||
if (!canReuseLogsVolumeData(logsVolumeData, queries, absoluteRange)) {
|
||||
dispatch(cleanLogsVolumeAction({ exploreId }));
|
||||
if (logsVolumeEnabled) {
|
||||
dispatch(loadLogsVolumeData(exploreId));
|
||||
|
||||
const { supplementaryQueries, absoluteRange } = getState().explore[exploreId]!;
|
||||
if (!canReuseSupplementaryQueryData(supplementaryQueries[type].data, queries, absoluteRange)) {
|
||||
dispatch(cleanSupplementaryQueryAction({ exploreId, type }));
|
||||
if (supplementaryQueries[type].enabled) {
|
||||
dispatch(loadSupplementaryQueryData(exploreId, type));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dispatch(
|
||||
storeLogsVolumeDataProviderAction({
|
||||
storeSupplementaryQueryDataProviderAction({
|
||||
exploreId,
|
||||
logsVolumeDataProvider: undefined,
|
||||
dataProvider: undefined,
|
||||
type: SupplementaryQueryType.LogsVolume,
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -605,20 +633,20 @@ export const runQueries = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if after changing the time range the existing data can be used to show logs volume.
|
||||
* Checks if after changing the time range the existing data can be used to show supplementary query.
|
||||
* It can happen if queries are the same and new time range is within existing data time range.
|
||||
*/
|
||||
function canReuseLogsVolumeData(
|
||||
logsVolumeData: DataQueryResponse | undefined,
|
||||
function canReuseSupplementaryQueryData(
|
||||
supplementaryQueryData: DataQueryResponse | undefined,
|
||||
queries: DataQuery[],
|
||||
selectedTimeRange: AbsoluteTimeRange
|
||||
): boolean {
|
||||
if (logsVolumeData && logsVolumeData.data[0]) {
|
||||
if (supplementaryQueryData && supplementaryQueryData.data[0]) {
|
||||
// check if queries are the same
|
||||
if (!deepEqual(logsVolumeData.data[0].meta?.custom?.targets, queries)) {
|
||||
if (!deepEqual(supplementaryQueryData.data[0].meta?.custom?.targets, queries)) {
|
||||
return false;
|
||||
}
|
||||
const dataRange = logsVolumeData && logsVolumeData.data[0] && logsVolumeData.data[0].meta?.custom?.absoluteRange;
|
||||
const dataRange = supplementaryQueryData.data[0].meta?.custom?.absoluteRange;
|
||||
// if selected range is within loaded logs volume
|
||||
if (dataRange && dataRange.from <= selectedTimeRange.from && selectedTimeRange.to <= dataRange.to) {
|
||||
return true;
|
||||
@ -664,7 +692,7 @@ export function addResultsToCache(exploreId: ExploreId): ThunkResult<void> {
|
||||
const absoluteRange = getState().explore[exploreId]!.absoluteRange;
|
||||
const cacheKey = createCacheKey(absoluteRange);
|
||||
|
||||
// Save results to cache only when all results recived and loading is done
|
||||
// Save results to cache only when all results received and loading is done
|
||||
if (queryResponse.state === LoadingState.Done) {
|
||||
dispatch(addResultsToCacheAction({ exploreId, cacheKey, queryResponse }));
|
||||
}
|
||||
@ -680,26 +708,38 @@ export function clearCache(exploreId: ExploreId): ThunkResult<void> {
|
||||
/**
|
||||
* Initializes loading logs volume data and stores emitted value.
|
||||
*/
|
||||
export function loadLogsVolumeData(exploreId: ExploreId): ThunkResult<void> {
|
||||
export function loadSupplementaryQueryData(exploreId: ExploreId, type: SupplementaryQueryType): ThunkResult<void> {
|
||||
return (dispatch, getState) => {
|
||||
const { logsVolumeDataProvider } = getState().explore[exploreId]!;
|
||||
if (logsVolumeDataProvider) {
|
||||
const logsVolumeDataSubscription = logsVolumeDataProvider.subscribe({
|
||||
next: (logsVolumeData: DataQueryResponse) => {
|
||||
dispatch(updateLogsVolumeDataAction({ exploreId, logsVolumeData }));
|
||||
const { supplementaryQueries } = getState().explore[exploreId]!;
|
||||
const dataProvider = supplementaryQueries[type].dataProvider;
|
||||
|
||||
if (dataProvider) {
|
||||
const dataSubscription = dataProvider.subscribe({
|
||||
next: (supplementaryQueryData: DataQueryResponse) => {
|
||||
dispatch(updateSupplementaryQueryDataAction({ exploreId, type, data: supplementaryQueryData }));
|
||||
},
|
||||
});
|
||||
dispatch(storeLogsVolumeDataSubscriptionAction({ exploreId, logsVolumeDataSubscription }));
|
||||
dispatch(
|
||||
storeSupplementaryQueryDataSubscriptionAction({
|
||||
exploreId,
|
||||
type,
|
||||
dataSubscription,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setLogsVolumeEnabled(exploreId: ExploreId, enabled: boolean): ThunkResult<void> {
|
||||
export function setSupplementaryQueryEnabled(
|
||||
exploreId: ExploreId,
|
||||
enabled: boolean,
|
||||
type: SupplementaryQueryType
|
||||
): ThunkResult<void> {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(setLogsVolumeEnabledAction({ exploreId, enabled }));
|
||||
storeLogsVolumeEnabled(enabled);
|
||||
dispatch(setSupplementaryQueryEnabledAction({ exploreId, enabled, type }));
|
||||
storeSupplementaryQueryEnabled(enabled, type);
|
||||
if (enabled) {
|
||||
dispatch(loadLogsVolumeData(exploreId));
|
||||
dispatch(loadSupplementaryQueryData(exploreId, type));
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -763,53 +803,87 @@ export const queryReducer = (state: ExploreItemState, action: AnyAction): Explor
|
||||
};
|
||||
}
|
||||
|
||||
if (setLogsVolumeEnabledAction.match(action)) {
|
||||
const { enabled } = action.payload;
|
||||
if (!enabled && state.logsVolumeDataSubscription) {
|
||||
state.logsVolumeDataSubscription.unsubscribe();
|
||||
if (setSupplementaryQueryEnabledAction.match(action)) {
|
||||
const { enabled, type } = action.payload;
|
||||
const { supplementaryQueries } = state;
|
||||
const dataSubscription = supplementaryQueries[type].dataSubscription;
|
||||
if (!enabled && dataSubscription) {
|
||||
dataSubscription.unsubscribe();
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
logsVolumeEnabled: enabled,
|
||||
|
||||
const nextSupplementaryQueries: SupplementaryQueries = {
|
||||
...supplementaryQueries,
|
||||
// NOTE: the dataProvider is not cleared, we may need it later,
|
||||
// if the user re-enables the histogram-visualization
|
||||
logsVolumeData: undefined,
|
||||
// if the user re-enables the supplementary query
|
||||
[type]: { ...supplementaryQueries[type], enabled, data: undefined },
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
supplementaryQueries: nextSupplementaryQueries,
|
||||
};
|
||||
}
|
||||
|
||||
if (storeLogsVolumeDataProviderAction.match(action)) {
|
||||
let { logsVolumeDataProvider } = action.payload;
|
||||
if (state.logsVolumeDataSubscription) {
|
||||
state.logsVolumeDataSubscription.unsubscribe();
|
||||
if (storeSupplementaryQueryDataProviderAction.match(action)) {
|
||||
const { dataProvider, type } = action.payload;
|
||||
const { supplementaryQueries } = state;
|
||||
const supplementaryQuery = supplementaryQueries[type];
|
||||
|
||||
if (supplementaryQuery?.dataSubscription) {
|
||||
supplementaryQuery.dataSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
const nextSupplementaryQueries = {
|
||||
...supplementaryQueries,
|
||||
[type]: { ...supplementaryQuery, dataProvider, dataSubscription: undefined },
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
logsVolumeDataProvider,
|
||||
logsVolumeDataSubscription: undefined,
|
||||
supplementaryQueries: nextSupplementaryQueries,
|
||||
};
|
||||
}
|
||||
|
||||
if (cleanLogsVolumeAction.match(action)) {
|
||||
if (cleanSupplementaryQueryAction.match(action)) {
|
||||
const { type } = action.payload;
|
||||
const { supplementaryQueries } = state;
|
||||
const nextSupplementaryQueries = {
|
||||
...supplementaryQueries,
|
||||
[type]: { ...supplementaryQueries[type], data: undefined },
|
||||
};
|
||||
return {
|
||||
...state,
|
||||
logsVolumeData: undefined,
|
||||
supplementaryQueries: nextSupplementaryQueries,
|
||||
};
|
||||
}
|
||||
|
||||
if (storeLogsVolumeDataSubscriptionAction.match(action)) {
|
||||
const { logsVolumeDataSubscription } = action.payload;
|
||||
if (storeSupplementaryQueryDataSubscriptionAction.match(action)) {
|
||||
const { dataSubscription, type } = action.payload;
|
||||
|
||||
const { supplementaryQueries } = state;
|
||||
const nextSupplementaryQueries = {
|
||||
...supplementaryQueries,
|
||||
[type]: { ...supplementaryQueries[type], dataSubscription },
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
logsVolumeDataSubscription,
|
||||
supplementaryQueries: nextSupplementaryQueries,
|
||||
};
|
||||
}
|
||||
|
||||
if (updateLogsVolumeDataAction.match(action)) {
|
||||
let { logsVolumeData } = action.payload;
|
||||
if (updateSupplementaryQueryDataAction.match(action)) {
|
||||
let { data, type } = action.payload;
|
||||
const { supplementaryQueries } = state;
|
||||
|
||||
const nextSupplementaryQueries = {
|
||||
...supplementaryQueries,
|
||||
[type]: { ...supplementaryQueries[type], data },
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
logsVolumeData,
|
||||
supplementaryQueries: nextSupplementaryQueries,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
PanelData,
|
||||
} from '@grafana/data';
|
||||
import { ExplorePanelData } from 'app/types';
|
||||
import { ExploreItemState } from 'app/types/explore';
|
||||
import { ExploreItemState, SupplementaryQueries, SupplementaryQueryType } from 'app/types/explore';
|
||||
|
||||
import store from '../../../core/store';
|
||||
import { clearQueryKeys, lastUsedDatasourceKeyForOrgId } from '../../../core/utils/explore';
|
||||
@ -20,6 +20,14 @@ import { getDatasourceSrv } from '../../plugins/datasource_srv';
|
||||
import { SETTINGS_KEYS } from '../utils/logs';
|
||||
import { toRawTimeRange } from '../utils/time';
|
||||
|
||||
export const SUPPLEMENTARY_QUERY_TYPES: SupplementaryQueryType[] = [SupplementaryQueryType.LogsVolume];
|
||||
|
||||
// Used to match supplementaryQueryType to corresponding local storage key
|
||||
// TODO: Remove this and unify enum values with SETTINGS_KEYS.enableVolumeHistogram
|
||||
const supplementaryQuerySettings: { [key in SupplementaryQueryType]: string } = {
|
||||
[SupplementaryQueryType.LogsVolume]: SETTINGS_KEYS.enableVolumeHistogram,
|
||||
};
|
||||
|
||||
export const DEFAULT_RANGE = {
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
@ -30,19 +38,25 @@ export const storeGraphStyle = (graphStyle: string): void => {
|
||||
store.set(GRAPH_STYLE_KEY, graphStyle);
|
||||
};
|
||||
|
||||
const LOGS_VOLUME_ENABLED_KEY = SETTINGS_KEYS.enableVolumeHistogram;
|
||||
export const storeLogsVolumeEnabled = (enabled: boolean): void => {
|
||||
store.set(LOGS_VOLUME_ENABLED_KEY, enabled ? 'true' : 'false');
|
||||
export const storeSupplementaryQueryEnabled = (enabled: boolean, type: SupplementaryQueryType): void => {
|
||||
if (supplementaryQuerySettings[type]) {
|
||||
store.set(supplementaryQuerySettings[type], enabled ? 'true' : 'false');
|
||||
}
|
||||
};
|
||||
|
||||
const loadLogsVolumeEnabled = (): boolean => {
|
||||
const data = store.get(LOGS_VOLUME_ENABLED_KEY);
|
||||
// we default to `enabled=true`
|
||||
if (data === 'false') {
|
||||
return false;
|
||||
}
|
||||
export const loadSupplementaryQueries = (): SupplementaryQueries => {
|
||||
// We default to true for all supp queries
|
||||
let supplementaryQueries: SupplementaryQueries = {
|
||||
[SupplementaryQueryType.LogsVolume]: { enabled: true },
|
||||
};
|
||||
|
||||
return true;
|
||||
for (const type of SUPPLEMENTARY_QUERY_TYPES) {
|
||||
// Only if "false" value in local storage, we disable it
|
||||
if (store.get(supplementaryQuerySettings[type]) === 'false') {
|
||||
supplementaryQueries[type] = { enabled: false };
|
||||
}
|
||||
}
|
||||
return supplementaryQueries;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -77,9 +91,7 @@ export const makeExplorePaneState = (): ExploreItemState => ({
|
||||
eventBridge: null as unknown as EventBusExtended,
|
||||
cache: [],
|
||||
richHistory: [],
|
||||
logsVolumeEnabled: loadLogsVolumeEnabled(),
|
||||
logsVolumeDataProvider: undefined,
|
||||
logsVolumeData: undefined,
|
||||
supplementaryQueries: loadSupplementaryQueries(),
|
||||
panelsState: {},
|
||||
});
|
||||
|
||||
|
@ -204,12 +204,10 @@ export interface ExploreItemState {
|
||||
*/
|
||||
cache: Array<{ key: string; value: ExplorePanelData }>;
|
||||
|
||||
// properties below should be more generic if we add more providers
|
||||
// see also: DataSourceWithLogsVolumeSupport
|
||||
logsVolumeEnabled: boolean;
|
||||
logsVolumeDataProvider?: Observable<DataQueryResponse>;
|
||||
logsVolumeDataSubscription?: SubscriptionLike;
|
||||
logsVolumeData?: DataQueryResponse;
|
||||
/**
|
||||
* Supplementary queries are additional queries used in Explore, e.g. for logs volume
|
||||
*/
|
||||
supplementaryQueries: SupplementaryQueries;
|
||||
|
||||
panelsState: ExplorePanelsState;
|
||||
|
||||
@ -270,3 +268,18 @@ export enum TABLE_RESULTS_STYLE {
|
||||
}
|
||||
export const TABLE_RESULTS_STYLES = [TABLE_RESULTS_STYLE.table, TABLE_RESULTS_STYLE.raw];
|
||||
export type TableResultsStyle = typeof TABLE_RESULTS_STYLES[number];
|
||||
|
||||
export interface SupplementaryQuery {
|
||||
enabled: boolean;
|
||||
dataProvider?: Observable<DataQueryResponse>;
|
||||
dataSubscription?: SubscriptionLike;
|
||||
data?: DataQueryResponse;
|
||||
}
|
||||
|
||||
export type SupplementaryQueries = {
|
||||
[key in SupplementaryQueryType]: SupplementaryQuery;
|
||||
};
|
||||
|
||||
export enum SupplementaryQueryType {
|
||||
LogsVolume = 'LogsVolume',
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user