mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Fix query interval string interpolation in query cache (#93678)
fix query interval string interpolation in query cache
This commit is contained in:
parent
05dbba4c85
commit
18f8f38418
@ -141,6 +141,7 @@ export class PrometheusDatasource
|
||||
this.cache = new QueryCache({
|
||||
getTargetSignature: this.getPrometheusTargetSignature.bind(this),
|
||||
overlapString: instanceSettings.jsonData.incrementalQueryOverlapWindow ?? defaultPrometheusQueryOverlapWindow,
|
||||
applyInterpolation: this.interpolateString.bind(this),
|
||||
});
|
||||
|
||||
// This needs to be here and cannot be static because of how annotations typing affects casting of data source
|
||||
|
@ -6,7 +6,7 @@ import { DataFrame, DataQueryRequest, DateTime, dateTime, TimeRange } from '@gra
|
||||
import { QueryEditorMode } from '../querybuilder/shared/types';
|
||||
import { PromQuery } from '../types';
|
||||
|
||||
import { CacheRequestInfo, QueryCache } from './QueryCache';
|
||||
import { CacheRequestInfo, findDatapointStep, QueryCache } from './QueryCache';
|
||||
import { IncrementalStorageDataFrameScenarios, trimmedFirstPointInPromFrames } from './QueryCacheTestData';
|
||||
|
||||
// Will not interpolate vars!
|
||||
@ -559,3 +559,14 @@ describe('QueryCache: Prometheus', function () {
|
||||
expect(cacheRequest.shouldCache).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findDataPointStep', () => {
|
||||
it('should interpolate custom interval', () => {
|
||||
const mockApplyInterpolation = jest.fn().mockImplementation(() => '1m');
|
||||
const req = mockPromRequest();
|
||||
req.targets[0].interval = '$interval';
|
||||
const respFrames = trimmedFirstPointInPromFrames as unknown as DataFrame[];
|
||||
findDatapointStep(req, respFrames, mockApplyInterpolation);
|
||||
expect(mockApplyInterpolation).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
isValidDuration,
|
||||
parseDuration,
|
||||
rangeUtil,
|
||||
ScopedVars,
|
||||
Table,
|
||||
trimTable,
|
||||
} from '@grafana/data';
|
||||
@ -23,10 +24,9 @@ type TargetIdent = string;
|
||||
// query + template variables + interval + raw time range
|
||||
// used for full target cache busting -> full range re-query
|
||||
type TargetSig = string;
|
||||
|
||||
type TimestampMs = number;
|
||||
|
||||
type SupportedQueryTypes = PromQuery;
|
||||
type ApplyInterpolation = (str: string, scopedVars?: ScopedVars) => string;
|
||||
|
||||
// string matching requirements defined in durationutil.ts
|
||||
export const defaultPrometheusQueryOverlapWindow = '10m';
|
||||
@ -59,12 +59,14 @@ export const getFieldIdent = (field: Field) => `${field.type}|${field.name}|${JS
|
||||
export class QueryCache<T extends SupportedQueryTypes> {
|
||||
private overlapWindowMs: number;
|
||||
private getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;
|
||||
private applyInterpolation = (str: string, scopedVars?: ScopedVars) => str;
|
||||
|
||||
cache = new Map<TargetIdent, TargetCache>();
|
||||
|
||||
constructor(options: {
|
||||
getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;
|
||||
overlapString: string;
|
||||
applyInterpolation?: ApplyInterpolation;
|
||||
}) {
|
||||
const unverifiedOverlap = options.overlapString;
|
||||
if (isValidDuration(unverifiedOverlap)) {
|
||||
@ -76,6 +78,9 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
||||
}
|
||||
|
||||
this.getTargetSignature = options.getTargetSignature;
|
||||
if (options.applyInterpolation) {
|
||||
this.applyInterpolation = options.applyInterpolation;
|
||||
}
|
||||
}
|
||||
|
||||
// can be used to change full range request to partial, split into multiple requests
|
||||
@ -221,7 +226,7 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
let table: Table = frame.fields.map((field) => field.values) as Table;
|
||||
|
||||
const dataPointStep = findDatapointStep(request, respFrames);
|
||||
const dataPointStep = findDatapointStep(request, respFrames, this.applyInterpolation);
|
||||
|
||||
// query interval is greater than request.intervalMs, use query interval to make sure we've always got one datapoint outside the panel viewport
|
||||
let trimmed = trimTable(table, newFrom - dataPointStep, newTo);
|
||||
@ -260,7 +265,11 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
||||
}
|
||||
}
|
||||
|
||||
function findDatapointStep(request: DataQueryRequest<PromQuery>, respFrames: DataFrame[]): number {
|
||||
export function findDatapointStep(
|
||||
request: DataQueryRequest<PromQuery>,
|
||||
respFrames: DataFrame[],
|
||||
applyInterpolation: ApplyInterpolation
|
||||
): number {
|
||||
// Prometheus specific logic below
|
||||
if (request.targets[0].datasource?.type !== 'prometheus') {
|
||||
return 0;
|
||||
@ -270,7 +279,7 @@ function findDatapointStep(request: DataQueryRequest<PromQuery>, respFrames: Dat
|
||||
|
||||
let dataPointStep = request.intervalMs;
|
||||
if (target?.interval) {
|
||||
const minStepMs = rangeUtil.intervalToMs(target.interval);
|
||||
const minStepMs = rangeUtil.intervalToMs(applyInterpolation(target.interval));
|
||||
if (minStepMs > request.intervalMs) {
|
||||
dataPointStep = minStepMs;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user