mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: calculate intervals when building data source request (#19107)
* Explore: calculate intervals when building data source request * Added unit test * updated unit test
This commit is contained in:
@@ -11,10 +11,11 @@ import {
|
|||||||
refreshIntervalToSortOrder,
|
refreshIntervalToSortOrder,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
sortLogsResult,
|
sortLogsResult,
|
||||||
|
buildQueryTransaction,
|
||||||
} from './explore';
|
} from './explore';
|
||||||
import { ExploreUrlState, ExploreMode } from 'app/types/explore';
|
import { ExploreUrlState, ExploreMode } from 'app/types/explore';
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
import { LogsDedupStrategy, LogsModel, LogLevel } from '@grafana/data';
|
import { LogsDedupStrategy, LogsModel, LogLevel, dateTime } from '@grafana/data';
|
||||||
import { DataQueryError } from '@grafana/ui';
|
import { DataQueryError } from '@grafana/ui';
|
||||||
import { liveOption, offOption } from '@grafana/ui/src/components/RefreshPicker/RefreshPicker';
|
import { liveOption, offOption } from '@grafana/ui/src/components/RefreshPicker/RefreshPicker';
|
||||||
|
|
||||||
@@ -427,4 +428,33 @@ describe('sortLogsResult', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when buildQueryTransaction', () => {
|
||||||
|
it('it should calculate interval based on time range', () => {
|
||||||
|
const queries = [{ refId: 'A' }];
|
||||||
|
const queryOptions = { maxDataPoints: 1000, minInterval: '15s' };
|
||||||
|
const range = { from: dateTime().subtract(1, 'd'), to: dateTime(), raw: { from: '1h', to: '1h' } };
|
||||||
|
const transaction = buildQueryTransaction(queries, queryOptions, range, false);
|
||||||
|
|
||||||
|
expect(transaction.request.intervalMs).toEqual(60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should calculate interval taking minInterval into account', () => {
|
||||||
|
const queries = [{ refId: 'A' }];
|
||||||
|
const queryOptions = { maxDataPoints: 1000, minInterval: '15s' };
|
||||||
|
const range = { from: dateTime().subtract(1, 'm'), to: dateTime(), raw: { from: '1h', to: '1h' } };
|
||||||
|
const transaction = buildQueryTransaction(queries, queryOptions, range, false);
|
||||||
|
|
||||||
|
expect(transaction.request.intervalMs).toEqual(15000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should calculate interval taking maxDataPoints into account', () => {
|
||||||
|
const queries = [{ refId: 'A' }];
|
||||||
|
const queryOptions = { maxDataPoints: 10, minInterval: '15s' };
|
||||||
|
const range = { from: dateTime().subtract(1, 'd'), to: dateTime(), raw: { from: '1h', to: '1h' } };
|
||||||
|
const transaction = buildQueryTransaction(queries, queryOptions, range, false);
|
||||||
|
|
||||||
|
expect(transaction.request.interval).toEqual('2h');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,21 +13,16 @@ import {
|
|||||||
LogRowModel,
|
LogRowModel,
|
||||||
LogsModel,
|
LogsModel,
|
||||||
LogsDedupStrategy,
|
LogsDedupStrategy,
|
||||||
|
IntervalValues,
|
||||||
DefaultTimeZone,
|
DefaultTimeZone,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { renderUrl } from 'app/core/utils/url';
|
import { renderUrl } from 'app/core/utils/url';
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
|
import kbn from 'app/core/utils/kbn';
|
||||||
import { getNextRefIdChar } from './query';
|
import { getNextRefIdChar } from './query';
|
||||||
// Types
|
// Types
|
||||||
import { DataQuery, DataSourceApi, DataQueryError, DataQueryRequest, PanelModel } from '@grafana/ui';
|
import { DataQuery, DataSourceApi, DataQueryError, DataQueryRequest, PanelModel } from '@grafana/ui';
|
||||||
import {
|
import { ExploreUrlState, HistoryItem, QueryTransaction, QueryOptions, ExploreMode } from 'app/types/explore';
|
||||||
ExploreUrlState,
|
|
||||||
HistoryItem,
|
|
||||||
QueryTransaction,
|
|
||||||
QueryIntervals,
|
|
||||||
QueryOptions,
|
|
||||||
ExploreMode,
|
|
||||||
} from 'app/types/explore';
|
|
||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
|
|
||||||
@@ -103,17 +98,16 @@ export function buildQueryTransaction(
|
|||||||
queries: DataQuery[],
|
queries: DataQuery[],
|
||||||
queryOptions: QueryOptions,
|
queryOptions: QueryOptions,
|
||||||
range: TimeRange,
|
range: TimeRange,
|
||||||
queryIntervals: QueryIntervals,
|
|
||||||
scanning: boolean
|
scanning: boolean
|
||||||
): QueryTransaction {
|
): QueryTransaction {
|
||||||
const { interval, intervalMs } = queryIntervals;
|
|
||||||
|
|
||||||
const configuredQueries = queries.map(query => ({ ...query, ...queryOptions }));
|
const configuredQueries = queries.map(query => ({ ...query, ...queryOptions }));
|
||||||
const key = queries.reduce((combinedKey, query) => {
|
const key = queries.reduce((combinedKey, query) => {
|
||||||
combinedKey += query.key;
|
combinedKey += query.key;
|
||||||
return combinedKey;
|
return combinedKey;
|
||||||
}, '');
|
}, '');
|
||||||
|
|
||||||
|
const { interval, intervalMs } = getIntervals(range, queryOptions.minInterval, queryOptions.maxDataPoints);
|
||||||
|
|
||||||
// Most datasource is using `panelId + query.refId` for cancellation logic.
|
// Most datasource is using `panelId + query.refId` for cancellation logic.
|
||||||
// Using `format` here because it relates to the view panel that the request is for.
|
// Using `format` here because it relates to the view panel that the request is for.
|
||||||
// However, some datasources don't use `panelId + query.refId`, but only `panelId`.
|
// However, some datasources don't use `panelId + query.refId`, but only `panelId`.
|
||||||
@@ -518,3 +512,11 @@ export const stopQueryState = (querySubscription: Unsubscribable) => {
|
|||||||
querySubscription.unsubscribe();
|
querySubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getIntervals(range: TimeRange, lowLimit: string, resolution: number): IntervalValues {
|
||||||
|
if (!resolution) {
|
||||||
|
return { interval: '1s', intervalMs: 1000 };
|
||||||
|
}
|
||||||
|
|
||||||
|
return kbn.calculateInterval(range, resolution, lowLimit);
|
||||||
|
}
|
||||||
|
|||||||
@@ -437,7 +437,6 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
|
|||||||
datasourceError,
|
datasourceError,
|
||||||
containerWidth,
|
containerWidth,
|
||||||
isLive: live,
|
isLive: live,
|
||||||
queryIntervals,
|
|
||||||
range,
|
range,
|
||||||
scanning,
|
scanning,
|
||||||
queryResponse,
|
queryResponse,
|
||||||
@@ -461,14 +460,13 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
|
|||||||
|
|
||||||
// Some datasource's query builders allow per-query interval limits,
|
// Some datasource's query builders allow per-query interval limits,
|
||||||
// but we're using the datasource interval limit for now
|
// but we're using the datasource interval limit for now
|
||||||
const interval = datasourceInstance.interval;
|
const minInterval = datasourceInstance.interval;
|
||||||
|
|
||||||
stopQueryState(querySubscription);
|
stopQueryState(querySubscription);
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
interval,
|
minInterval,
|
||||||
// This is used for logs streaming for buffer size.
|
// This is used for logs streaming for buffer size.
|
||||||
// TODO: not sure if this makes sense for normal query when using both graph and table
|
|
||||||
maxDataPoints: mode === ExploreMode.Logs ? 1000 : containerWidth,
|
maxDataPoints: mode === ExploreMode.Logs ? 1000 : containerWidth,
|
||||||
live,
|
live,
|
||||||
showingGraph,
|
showingGraph,
|
||||||
@@ -476,7 +474,7 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const datasourceId = datasourceInstance.meta.id;
|
const datasourceId = datasourceInstance.meta.id;
|
||||||
const transaction = buildQueryTransaction(queries, queryOptions, range, queryIntervals, scanning);
|
const transaction = buildQueryTransaction(queries, queryOptions, range, scanning);
|
||||||
|
|
||||||
let firstResponse = true;
|
let firstResponse = true;
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,6 @@ export const DEFAULT_RANGE = {
|
|||||||
to: 'now',
|
to: 'now',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Millies step for helper bar charts
|
|
||||||
const DEFAULT_GRAPH_INTERVAL = 15 * 1000;
|
|
||||||
|
|
||||||
export const makeInitialUpdateState = (): ExploreUpdateState => ({
|
export const makeInitialUpdateState = (): ExploreUpdateState => ({
|
||||||
datasource: false,
|
datasource: false,
|
||||||
queries: false,
|
queries: false,
|
||||||
@@ -93,7 +90,6 @@ export const makeExploreItemState = (): ExploreItemState => ({
|
|||||||
history: [],
|
history: [],
|
||||||
queries: [],
|
queries: [],
|
||||||
initialized: false,
|
initialized: false,
|
||||||
queryIntervals: { interval: '15s', intervalMs: DEFAULT_GRAPH_INTERVAL },
|
|
||||||
range: {
|
range: {
|
||||||
from: null,
|
from: null,
|
||||||
to: null,
|
to: null,
|
||||||
@@ -617,7 +613,7 @@ export const processQueryResponse = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const latency = request.endTime ? request.endTime - request.startTime : 0;
|
const latency = request.endTime ? request.endTime - request.startTime : 0;
|
||||||
const processor = new ResultProcessor(state, series);
|
const processor = new ResultProcessor(state, series, request.intervalMs);
|
||||||
const graphResult = processor.getGraphResult();
|
const graphResult = processor.getGraphResult();
|
||||||
const tableResult = processor.getTableResult();
|
const tableResult = processor.getTableResult();
|
||||||
const logsResult = processor.getLogsResult();
|
const logsResult = processor.getLogsResult();
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const testContext = (options: any = {}) => {
|
|||||||
queryIntervals: { intervalMs: 10 },
|
queryIntervals: { intervalMs: 10 },
|
||||||
} as any) as ExploreItemState;
|
} as any) as ExploreItemState;
|
||||||
|
|
||||||
const resultProcessor = new ResultProcessor(state, combinedOptions.dataFrames);
|
const resultProcessor = new ResultProcessor(state, combinedOptions.dataFrames, 60000);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dataFrames: combinedOptions.dataFrames,
|
dataFrames: combinedOptions.dataFrames,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { dataFrameToLogsModel } from 'app/core/logs_model';
|
|||||||
import { getGraphSeriesModel } from 'app/plugins/panel/graph2/getGraphSeriesModel';
|
import { getGraphSeriesModel } from 'app/plugins/panel/graph2/getGraphSeriesModel';
|
||||||
|
|
||||||
export class ResultProcessor {
|
export class ResultProcessor {
|
||||||
constructor(private state: ExploreItemState, private dataFrames: DataFrame[]) {}
|
constructor(private state: ExploreItemState, private dataFrames: DataFrame[], private intervalMs: number) {}
|
||||||
|
|
||||||
getGraphResult(): GraphSeriesXY[] {
|
getGraphResult(): GraphSeriesXY[] {
|
||||||
if (this.state.mode !== ExploreMode.Metrics) {
|
if (this.state.mode !== ExploreMode.Metrics) {
|
||||||
@@ -77,9 +77,7 @@ export class ResultProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const graphInterval = this.state.queryIntervals.intervalMs;
|
const newResults = dataFrameToLogsModel(this.dataFrames, this.intervalMs);
|
||||||
|
|
||||||
const newResults = dataFrameToLogsModel(this.dataFrames, graphInterval);
|
|
||||||
const sortOrder = refreshIntervalToSortOrder(this.state.refreshInterval);
|
const sortOrder = refreshIntervalToSortOrder(this.state.refreshInterval);
|
||||||
const sortedNewResults = sortLogsResult(newResults, sortOrder);
|
const sortedNewResults = sortLogsResult(newResults, sortOrder);
|
||||||
|
|
||||||
|
|||||||
@@ -186,11 +186,6 @@ export interface ExploreItemState {
|
|||||||
*/
|
*/
|
||||||
logsResult?: LogsModel;
|
logsResult?: LogsModel;
|
||||||
|
|
||||||
/**
|
|
||||||
* Query intervals for graph queries to determine how many datapoints to return.
|
|
||||||
* Needs to be updated when `datasourceInstance` or `containerWidth` is changed.
|
|
||||||
*/
|
|
||||||
queryIntervals: QueryIntervals;
|
|
||||||
/**
|
/**
|
||||||
* Time range for this Explore. Managed by the time picker and used by all query runs.
|
* Time range for this Explore. Managed by the time picker and used by all query runs.
|
||||||
*/
|
*/
|
||||||
@@ -330,7 +325,7 @@ export interface QueryIntervals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryOptions {
|
export interface QueryOptions {
|
||||||
interval: string;
|
minInterval: string;
|
||||||
maxDataPoints?: number;
|
maxDataPoints?: number;
|
||||||
live?: boolean;
|
live?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user