Browse Source

Explore: calculate intervals when building data source request (#19107)

* Explore: calculate intervals when building data source request

* Added unit test

* updated unit test
Torkel Ödegaard 6 years ago
parent
commit
9d0a076eb1

+ 31 - 1
public/app/core/utils/explore.test.ts

@@ -11,10 +11,11 @@ import {
   refreshIntervalToSortOrder,
   SortOrder,
   sortLogsResult,
+  buildQueryTransaction,
 } from './explore';
 import { ExploreUrlState, ExploreMode } from 'app/types/explore';
 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 { 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 - 11
public/app/core/utils/explore.ts

@@ -13,21 +13,16 @@ import {
   LogRowModel,
   LogsModel,
   LogsDedupStrategy,
+  IntervalValues,
   DefaultTimeZone,
 } from '@grafana/data';
 import { renderUrl } from 'app/core/utils/url';
 import store from 'app/core/store';
+import kbn from 'app/core/utils/kbn';
 import { getNextRefIdChar } from './query';
 // Types
 import { DataQuery, DataSourceApi, DataQueryError, DataQueryRequest, PanelModel } from '@grafana/ui';
-import {
-  ExploreUrlState,
-  HistoryItem,
-  QueryTransaction,
-  QueryIntervals,
-  QueryOptions,
-  ExploreMode,
-} from 'app/types/explore';
+import { ExploreUrlState, HistoryItem, QueryTransaction, QueryOptions, ExploreMode } from 'app/types/explore';
 import { config } from '../config';
 import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
 
@@ -103,17 +98,16 @@ export function buildQueryTransaction(
   queries: DataQuery[],
   queryOptions: QueryOptions,
   range: TimeRange,
-  queryIntervals: QueryIntervals,
   scanning: boolean
 ): QueryTransaction {
-  const { interval, intervalMs } = queryIntervals;
-
   const configuredQueries = queries.map(query => ({ ...query, ...queryOptions }));
   const key = queries.reduce((combinedKey, query) => {
     combinedKey += query.key;
     return combinedKey;
   }, '');
 
+  const { interval, intervalMs } = getIntervals(range, queryOptions.minInterval, queryOptions.maxDataPoints);
+
   // 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.
   // However, some datasources don't use `panelId + query.refId`, but only `panelId`.
@@ -518,3 +512,11 @@ export const stopQueryState = (querySubscription: Unsubscribable) => {
     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);
+}

+ 3 - 5
public/app/features/explore/state/actions.ts

@@ -437,7 +437,6 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
       datasourceError,
       containerWidth,
       isLive: live,
-      queryIntervals,
       range,
       scanning,
       queryResponse,
@@ -461,14 +460,13 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
 
     // Some datasource's query builders allow per-query interval limits,
     // but we're using the datasource interval limit for now
-    const interval = datasourceInstance.interval;
+    const minInterval = datasourceInstance.interval;
 
     stopQueryState(querySubscription);
 
     const queryOptions = {
-      interval,
+      minInterval,
       // 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,
       live,
       showingGraph,
@@ -476,7 +474,7 @@ export function runQueries(exploreId: ExploreId): ThunkResult<void> {
     };
 
     const datasourceId = datasourceInstance.meta.id;
-    const transaction = buildQueryTransaction(queries, queryOptions, range, queryIntervals, scanning);
+    const transaction = buildQueryTransaction(queries, queryOptions, range, scanning);
 
     let firstResponse = true;
 

+ 1 - 5
public/app/features/explore/state/reducers.ts

@@ -67,9 +67,6 @@ export const DEFAULT_RANGE = {
   to: 'now',
 };
 
-// Millies step for helper bar charts
-const DEFAULT_GRAPH_INTERVAL = 15 * 1000;
-
 export const makeInitialUpdateState = (): ExploreUpdateState => ({
   datasource: false,
   queries: false,
@@ -93,7 +90,6 @@ export const makeExploreItemState = (): ExploreItemState => ({
   history: [],
   queries: [],
   initialized: false,
-  queryIntervals: { interval: '15s', intervalMs: DEFAULT_GRAPH_INTERVAL },
   range: {
     from: null,
     to: null,
@@ -617,7 +613,7 @@ export const processQueryResponse = (
   }
 
   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 tableResult = processor.getTableResult();
   const logsResult = processor.getLogsResult();

+ 1 - 1
public/app/features/explore/utils/ResultProcessor.test.ts

@@ -56,7 +56,7 @@ const testContext = (options: any = {}) => {
     queryIntervals: { intervalMs: 10 },
   } as any) as ExploreItemState;
 
-  const resultProcessor = new ResultProcessor(state, combinedOptions.dataFrames);
+  const resultProcessor = new ResultProcessor(state, combinedOptions.dataFrames, 60000);
 
   return {
     dataFrames: combinedOptions.dataFrames,

+ 2 - 4
public/app/features/explore/utils/ResultProcessor.ts

@@ -7,7 +7,7 @@ import { dataFrameToLogsModel } from 'app/core/logs_model';
 import { getGraphSeriesModel } from 'app/plugins/panel/graph2/getGraphSeriesModel';
 
 export class ResultProcessor {
-  constructor(private state: ExploreItemState, private dataFrames: DataFrame[]) {}
+  constructor(private state: ExploreItemState, private dataFrames: DataFrame[], private intervalMs: number) {}
 
   getGraphResult(): GraphSeriesXY[] {
     if (this.state.mode !== ExploreMode.Metrics) {
@@ -77,9 +77,7 @@ export class ResultProcessor {
       return null;
     }
 
-    const graphInterval = this.state.queryIntervals.intervalMs;
-
-    const newResults = dataFrameToLogsModel(this.dataFrames, graphInterval);
+    const newResults = dataFrameToLogsModel(this.dataFrames, this.intervalMs);
     const sortOrder = refreshIntervalToSortOrder(this.state.refreshInterval);
     const sortedNewResults = sortLogsResult(newResults, sortOrder);
 

+ 1 - 6
public/app/types/explore.ts

@@ -186,11 +186,6 @@ export interface ExploreItemState {
    */
   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.
    */
@@ -330,7 +325,7 @@ export interface QueryIntervals {
 }
 
 export interface QueryOptions {
-  interval: string;
+  minInterval: string;
   maxDataPoints?: number;
   live?: boolean;
 }