mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Datasource/Loki: Loki now goes to Logs mode when importing prom queries (#20890)
* Datasource/Loki: Loki now goes to Logs mode when importing prom queries Closes #20831 * Fixes behavior and adds tests * Update public/app/features/explore/state/actions.test.ts
This commit is contained in:
parent
ab3df98523
commit
b4736558ac
@ -178,6 +178,7 @@ export interface UpdateDatasourceInstancePayload {
|
|||||||
exploreId: ExploreId;
|
exploreId: ExploreId;
|
||||||
datasourceInstance: DataSourceApi;
|
datasourceInstance: DataSourceApi;
|
||||||
version?: string;
|
version?: string;
|
||||||
|
mode?: ExploreMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToggleLogLevelPayload {
|
export interface ToggleLogLevelPayload {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { loadDatasource, navigateToExplore, refreshExplore } from './actions';
|
import { changeDatasource, loadDatasource, navigateToExplore, refreshExplore } from './actions';
|
||||||
|
import * as Actions from './actions';
|
||||||
import { ExploreId, ExploreMode, ExploreUpdateState, ExploreUrlState } from 'app/types';
|
import { ExploreId, ExploreMode, ExploreUpdateState, ExploreUrlState } from 'app/types';
|
||||||
import { thunkTester } from 'test/core/thunk/thunkTester';
|
import { thunkTester } from 'test/core/thunk/thunkTester';
|
||||||
import {
|
import {
|
||||||
@ -8,6 +9,7 @@ import {
|
|||||||
loadDatasourceReadyAction,
|
loadDatasourceReadyAction,
|
||||||
setQueriesAction,
|
setQueriesAction,
|
||||||
updateUIStateAction,
|
updateUIStateAction,
|
||||||
|
updateDatasourceInstanceAction,
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { Emitter } from 'app/core/core';
|
import { Emitter } from 'app/core/core';
|
||||||
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
|
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
|
||||||
@ -16,16 +18,24 @@ import { DataQuery, DefaultTimeZone, LogsDedupStrategy, RawTimeRange, toUtc } fr
|
|||||||
import { PanelModel } from 'app/features/dashboard/state';
|
import { PanelModel } from 'app/features/dashboard/state';
|
||||||
import { updateLocation } from '../../../core/actions';
|
import { updateLocation } from '../../../core/actions';
|
||||||
import { MockDataSourceApi } from '../../../../test/mocks/datasource_srv';
|
import { MockDataSourceApi } from '../../../../test/mocks/datasource_srv';
|
||||||
|
import * as DatasourceSrv from 'app/features/plugins/datasource_srv';
|
||||||
|
|
||||||
jest.mock('app/features/plugins/datasource_srv', () => ({
|
jest.mock('app/features/plugins/datasource_srv');
|
||||||
getDatasourceSrv: () => ({
|
const getDatasourceSrvMock = (DatasourceSrv.getDatasourceSrv as any) as jest.Mock<DatasourceSrv.DatasourceSrv>;
|
||||||
getExternal: jest.fn().mockReturnValue([]),
|
|
||||||
get: jest.fn().mockReturnValue({
|
beforeEach(() => {
|
||||||
testDatasource: jest.fn(),
|
getDatasourceSrvMock.mockClear();
|
||||||
init: jest.fn(),
|
getDatasourceSrvMock.mockImplementation(
|
||||||
}),
|
() =>
|
||||||
}),
|
({
|
||||||
}));
|
getExternal: jest.fn().mockReturnValue([]),
|
||||||
|
get: jest.fn().mockReturnValue({
|
||||||
|
testDatasource: jest.fn(),
|
||||||
|
init: jest.fn(),
|
||||||
|
}),
|
||||||
|
} as any)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('../../dashboard/services/TimeSrv', () => ({
|
jest.mock('../../dashboard/services/TimeSrv', () => ({
|
||||||
getTimeSrv: jest.fn().mockReturnValue({
|
getTimeSrv: jest.fn().mockReturnValue({
|
||||||
@ -163,6 +173,62 @@ describe('refreshExplore', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('changing datasource', () => {
|
||||||
|
it('should switch to logs mode when changing from prometheus to loki', async () => {
|
||||||
|
const lokiMock = {
|
||||||
|
testDatasource: () => Promise.resolve({ status: 'success' }),
|
||||||
|
name: 'Loki',
|
||||||
|
init: jest.fn(),
|
||||||
|
meta: { id: 'some id', name: 'Loki' },
|
||||||
|
};
|
||||||
|
|
||||||
|
getDatasourceSrvMock.mockImplementation(
|
||||||
|
() =>
|
||||||
|
({
|
||||||
|
getExternal: jest.fn().mockReturnValue([]),
|
||||||
|
get: jest.fn().mockReturnValue(lokiMock),
|
||||||
|
} as any)
|
||||||
|
);
|
||||||
|
|
||||||
|
const exploreId = ExploreId.left;
|
||||||
|
const name = 'Prometheus';
|
||||||
|
const mockPromDatasourceInstance = {
|
||||||
|
testDatasource: () => Promise.resolve({ status: 'success' }),
|
||||||
|
name,
|
||||||
|
init: jest.fn(),
|
||||||
|
meta: { id: 'some id', name },
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
explore: {
|
||||||
|
[exploreId]: {
|
||||||
|
requestedDatasourceName: 'Loki',
|
||||||
|
datasourceInstance: mockPromDatasourceInstance,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
orgId: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.spyOn(Actions, 'importQueries').mockImplementationOnce(() => jest.fn);
|
||||||
|
jest.spyOn(Actions, 'loadDatasource').mockImplementationOnce(() => jest.fn);
|
||||||
|
jest.spyOn(Actions, 'runQueries').mockImplementationOnce(() => jest.fn);
|
||||||
|
const dispatchedActions = await thunkTester(initialState)
|
||||||
|
.givenThunk(changeDatasource)
|
||||||
|
.whenThunkIsDispatched(exploreId, name);
|
||||||
|
|
||||||
|
expect(dispatchedActions).toEqual([
|
||||||
|
updateDatasourceInstanceAction({
|
||||||
|
exploreId,
|
||||||
|
datasourceInstance: lokiMock as any,
|
||||||
|
version: undefined,
|
||||||
|
mode: ExploreMode.Logs,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('loading datasource', () => {
|
describe('loading datasource', () => {
|
||||||
describe('when loadDatasource thunk is dispatched', () => {
|
describe('when loadDatasource thunk is dispatched', () => {
|
||||||
describe('and all goes fine', () => {
|
describe('and all goes fine', () => {
|
||||||
|
@ -124,11 +124,16 @@ export function changeDatasource(exploreId: ExploreId, datasource: string): Thun
|
|||||||
const orgId = getState().user.orgId;
|
const orgId = getState().user.orgId;
|
||||||
const datasourceVersion = newDataSourceInstance.getVersion && (await newDataSourceInstance.getVersion());
|
const datasourceVersion = newDataSourceInstance.getVersion && (await newDataSourceInstance.getVersion());
|
||||||
|
|
||||||
|
// HACK: Switch to logs mode if coming from Prometheus to Loki
|
||||||
|
const prometheusToLoki =
|
||||||
|
currentDataSourceInstance?.meta?.name === 'Prometheus' && newDataSourceInstance?.meta?.name === 'Loki';
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
updateDatasourceInstanceAction({
|
updateDatasourceInstanceAction({
|
||||||
exploreId,
|
exploreId,
|
||||||
datasourceInstance: newDataSourceInstance,
|
datasourceInstance: newDataSourceInstance,
|
||||||
version: datasourceVersion,
|
version: datasourceVersion,
|
||||||
|
mode: prometheusToLoki ? ExploreMode.Logs : undefined,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -316,12 +321,12 @@ export const loadDatasourceReady = (
|
|||||||
* @param sourceDataSource
|
* @param sourceDataSource
|
||||||
* @param targetDataSource
|
* @param targetDataSource
|
||||||
*/
|
*/
|
||||||
export function importQueries(
|
export const importQueries = (
|
||||||
exploreId: ExploreId,
|
exploreId: ExploreId,
|
||||||
queries: DataQuery[],
|
queries: DataQuery[],
|
||||||
sourceDataSource: DataSourceApi,
|
sourceDataSource: DataSourceApi,
|
||||||
targetDataSource: DataSourceApi
|
targetDataSource: DataSourceApi
|
||||||
): ThunkResult<void> {
|
): ThunkResult<void> => {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
if (!sourceDataSource) {
|
if (!sourceDataSource) {
|
||||||
// explore not initialized
|
// explore not initialized
|
||||||
@ -346,12 +351,12 @@ export function importQueries(
|
|||||||
|
|
||||||
dispatch(queriesImportedAction({ exploreId, queries: nextQueries }));
|
dispatch(queriesImportedAction({ exploreId, queries: nextQueries }));
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main action to asynchronously load a datasource. Dispatches lots of smaller actions for feedback.
|
* Main action to asynchronously load a datasource. Dispatches lots of smaller actions for feedback.
|
||||||
*/
|
*/
|
||||||
export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi, orgId: number): ThunkResult<void> {
|
export const loadDatasource = (exploreId: ExploreId, instance: DataSourceApi, orgId: number): ThunkResult<void> => {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const datasourceName = instance.name;
|
const datasourceName = instance.name;
|
||||||
|
|
||||||
@ -373,7 +378,7 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi, or
|
|||||||
|
|
||||||
dispatch(loadDatasourceReady(exploreId, instance, orgId));
|
dispatch(loadDatasourceReady(exploreId, instance, orgId));
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to modify a query given a datasource-specific modifier action.
|
* Action to modify a query given a datasource-specific modifier action.
|
||||||
@ -399,7 +404,7 @@ export function modifyQueries(
|
|||||||
/**
|
/**
|
||||||
* Main action to run queries and dispatches sub-actions based on which result viewers are active
|
* Main action to run queries and dispatches sub-actions based on which result viewers are active
|
||||||
*/
|
*/
|
||||||
export function runQueries(exploreId: ExploreId): ThunkResult<void> {
|
export const runQueries = (exploreId: ExploreId): ThunkResult<void> => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(updateTime({ exploreId }));
|
dispatch(updateTime({ exploreId }));
|
||||||
|
|
||||||
@ -484,7 +489,7 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
|
|||||||
|
|
||||||
dispatch(queryStoreSubscriptionAction({ exploreId, querySubscription: newQuerySub }));
|
dispatch(queryStoreSubscriptionAction({ exploreId, querySubscription: newQuerySub }));
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const toRawTimeRange = (range: TimeRange): RawTimeRange => {
|
const toRawTimeRange = (range: TimeRange): RawTimeRange => {
|
||||||
let from = range.raw.from;
|
let from = range.raw.from;
|
||||||
|
@ -269,7 +269,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
|
|||||||
.addMapper({
|
.addMapper({
|
||||||
filter: updateDatasourceInstanceAction,
|
filter: updateDatasourceInstanceAction,
|
||||||
mapper: (state, action): ExploreItemState => {
|
mapper: (state, action): ExploreItemState => {
|
||||||
const { datasourceInstance, version } = action.payload;
|
const { datasourceInstance, version, mode } = action.payload;
|
||||||
|
|
||||||
// Custom components
|
// Custom components
|
||||||
stopQueryState(state.querySubscription);
|
stopQueryState(state.querySubscription);
|
||||||
@ -291,7 +291,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updatedDatasourceInstance = Object.assign(datasourceInstance, { meta: newMetadata });
|
const updatedDatasourceInstance = Object.assign(datasourceInstance, { meta: newMetadata });
|
||||||
const [supportedModes, mode] = getModesForDatasource(updatedDatasourceInstance, state.mode);
|
const [supportedModes, newMode] = getModesForDatasource(updatedDatasourceInstance, state.mode);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -304,7 +304,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
|
|||||||
loading: false,
|
loading: false,
|
||||||
queryKeys: [],
|
queryKeys: [],
|
||||||
supportedModes,
|
supportedModes,
|
||||||
mode,
|
mode: mode ?? newMode,
|
||||||
originPanelId: state.urlState && state.urlState.originPanelId,
|
originPanelId: state.urlState && state.urlState.originPanelId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -190,9 +190,9 @@ export class DatasourceSrv implements DataSourceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDatasourceSrv(): DatasourceSrv {
|
export const getDatasourceSrv = (): DatasourceSrv => {
|
||||||
return getDataSourceService() as DatasourceSrv;
|
return getDataSourceService() as DatasourceSrv;
|
||||||
}
|
};
|
||||||
|
|
||||||
coreModule.service('datasourceSrv', DatasourceSrv);
|
coreModule.service('datasourceSrv', DatasourceSrv);
|
||||||
export default DatasourceSrv;
|
export default DatasourceSrv;
|
||||||
|
Loading…
Reference in New Issue
Block a user