Loki: use generic grafana null-insertion mechanism (#44826)

* loki: refactor: return dataframes instead of timeseries

* fixed unit test

* removed unused import
This commit is contained in:
Gábor Farkas 2022-02-03 15:23:38 +01:00 committed by GitHub
parent afac7701cb
commit 0c2ba819a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 29 deletions

View File

@ -10,7 +10,6 @@ import {
FieldType,
LogRowModel,
MutableDataFrame,
TimeSeries,
toUtc,
} from '@grafana/data';
import { BackendSrvRequest, FetchResponse, config } from '@grafana/runtime';
@ -334,7 +333,7 @@ describe('LokiDatasource', () => {
expect(ds.runRangeQuery).toBeCalled();
});
it('should return series data for metrics range queries', async () => {
it('should return dataframe data for metrics range queries', async () => {
const ds = createLokiDSForTests();
const options = getQueryOptions<LokiQuery>({
targets: [{ expr: metricsQuery, refId: 'B', range: true }],
@ -345,11 +344,19 @@ describe('LokiDatasource', () => {
await expect(ds.query(options)).toEmitValuesWith((received) => {
const result = received[0];
const timeSeries = result.data[0] as TimeSeries;
const frame = result.data[0] as DataFrame;
expect(timeSeries.meta?.preferredVisualisationType).toBe('graph');
expect(timeSeries.refId).toBe('B');
expect(timeSeries.datapoints[0]).toEqual([1.1, 1605715380000]);
expect(frame.meta?.preferredVisualisationType).toBe('graph');
expect(frame.refId).toBe('B');
frame.fields.forEach((field) => {
const value = field.values.get(0);
if (field.type === FieldType.time) {
expect(value).toBe(1605715380000);
} else {
expect(value).toBe(1.1);
}
});
});
});

View File

@ -290,8 +290,6 @@ describe('enhanceDataFrame', () => {
* NOTE on time parameters:
* - Input time series data has timestamps in sec (like Prometheus)
* - Output time series has timestamps in ms (as expected for the chart lib)
* - Start/end parameters are in ns (as expected for Loki)
* - Step is in sec (like in Prometheus)
*/
const data: Array<[number, string]> = [
[1, '1'],
@ -300,12 +298,10 @@ describe('enhanceDataFrame', () => {
];
it('returns data as is if step, start, and end align', () => {
const options: Partial<TransformerOptions> = { start: 1 * 1e9, end: 4 * 1e9, step: 1 };
const result = ResultTransformer.lokiPointsToTimeseriesPoints(data, options as TransformerOptions);
const result = ResultTransformer.lokiPointsToTimeseriesPoints(data);
expect(result).toEqual([
[1, 1000],
[0, 2000],
[null, 3000],
[1, 4000],
]);
});

View File

@ -17,6 +17,7 @@ import {
QueryResultMeta,
TimeSeriesValue,
ScopedVars,
toDataFrame,
} from '@grafana/data';
import { getTemplateSrv, getDataSourceSrv } from '@grafana/runtime';
@ -184,21 +185,16 @@ function lokiMatrixToTimeSeries(matrixResult: LokiMatrixResult, options: Transfo
return {
target: name,
title: name,
datapoints: lokiPointsToTimeseriesPoints(matrixResult.values, options),
datapoints: lokiPointsToTimeseriesPoints(matrixResult.values),
tags: matrixResult.metric,
meta: options.meta,
refId: options.refId,
};
}
export function lokiPointsToTimeseriesPoints(
data: Array<[number, string]>,
options: TransformerOptions
): TimeSeriesValue[][] {
const stepMs = options.step * 1000;
export function lokiPointsToTimeseriesPoints(data: Array<[number, string]>): TimeSeriesValue[][] {
const datapoints: TimeSeriesValue[][] = [];
let baseTimestampMs = options.start / 1e6;
for (const [time, value] of data) {
let datapointValue: TimeSeriesValue = parseFloat(value);
@ -207,19 +203,10 @@ export function lokiPointsToTimeseriesPoints(
}
const timestamp = time * 1000;
for (let t = baseTimestampMs; t < timestamp; t += stepMs) {
datapoints.push([null, t]);
}
baseTimestampMs = timestamp + stepMs;
datapoints.push([datapointValue, timestamp]);
}
const endTimestamp = options.end / 1e6;
for (let t = baseTimestampMs; t <= endTimestamp; t += stepMs) {
datapoints.push([null, t]);
}
return datapoints;
}
@ -454,7 +441,7 @@ function fieldFromDerivedFieldConfig(derivedFieldConfigs: DerivedFieldConfig[]):
};
}
export function rangeQueryResponseToTimeSeries(
function rangeQueryResponseToTimeSeries(
response: LokiResponse,
query: LokiRangeQueryRequest,
target: LokiQuery,
@ -491,6 +478,33 @@ export function rangeQueryResponseToTimeSeries(
}
}
export function rangeQueryResponseToDataFrames(
response: LokiResponse,
query: LokiRangeQueryRequest,
target: LokiQuery,
responseListLength: number,
scopedVars: ScopedVars
): DataFrame[] {
const series = rangeQueryResponseToTimeSeries(response, query, target, responseListLength, scopedVars);
const frames = series.map((s) => toDataFrame(s));
const { step } = query;
if (step != null) {
const intervalMs = step * 1000;
frames.forEach((frame) => {
frame.fields.forEach((field) => {
if (field.type === FieldType.time) {
field.config.interval = intervalMs;
}
});
});
}
return frames;
}
export function processRangeQueryResponse(
response: LokiResponse,
target: LokiQuery,
@ -511,7 +525,7 @@ export function processRangeQueryResponse(
case LokiResultType.Vector:
case LokiResultType.Matrix:
return of({
data: rangeQueryResponseToTimeSeries(
data: rangeQueryResponseToDataFrames(
response,
query,
{