From d20ac041201768eec24831b52dc87f57a2bbd2aa Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Thu, 3 Feb 2022 15:57:01 +0100 Subject: [PATCH] Loki: use generic grafana null-insertion mechanism (#44826) (#44846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * loki: refactor: return dataframes instead of timeseries * fixed unit test * removed unused import (cherry picked from commit 0c2ba819a7a0772fdec7358c80f2e31e2246eac1) Co-authored-by: Gábor Farkas --- .../datasource/loki/datasource.test.ts | 19 ++++--- .../loki/result_transformer.test.ts | 6 +-- .../datasource/loki/result_transformer.ts | 50 ++++++++++++------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index da697baefa1..2c75f36b5da 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -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({ 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); + } + }); }); }); diff --git a/public/app/plugins/datasource/loki/result_transformer.test.ts b/public/app/plugins/datasource/loki/result_transformer.test.ts index b2fb3682d4e..d9d0e0b99b8 100644 --- a/public/app/plugins/datasource/loki/result_transformer.test.ts +++ b/public/app/plugins/datasource/loki/result_transformer.test.ts @@ -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 = { 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], ]); }); diff --git a/public/app/plugins/datasource/loki/result_transformer.ts b/public/app/plugins/datasource/loki/result_transformer.ts index 970cb1ddc45..ae7ef9ce46c 100644 --- a/public/app/plugins/datasource/loki/result_transformer.ts +++ b/public/app/plugins/datasource/loki/result_transformer.ts @@ -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, {