Commit a230aa10 by Zoltán Bedi Committed by GitHub

Prometheus: refactor to DataFrame (#27737)

* Add typing to prometheus response

* Refactor result_transformer to return DataFrame

* Refactor + test fixes

* Fix Prometheus data source test

* Modify heatmap function + add back tests

* Update performInstantQuery return type

* Remove duplicate code from result_transformer

* Address review comments

* Update metric labels retrival logic to be safer
parent f97f12f6
......@@ -108,7 +108,7 @@ export interface FetchErrorDataProps {
export interface FetchError<T extends FetchErrorDataProps = any> {
status: number;
statusText?: string;
data: T | string;
data: T;
cancelled?: boolean;
isHandled?: boolean;
config: BackendSrvRequest;
......
......@@ -681,32 +681,32 @@ describe('PrometheusDatasource', () => {
it('should be same length', () => {
expect(results.data.length).toBe(2);
expect(results.data[0].datapoints.length).toBe((end - start) / step + 1);
expect(results.data[1].datapoints.length).toBe((end - start) / step + 1);
expect(results.data[0].length).toBe((end - start) / step + 1);
expect(results.data[1].length).toBe((end - start) / step + 1);
});
it('should fill null until first datapoint in response', () => {
expect(results.data[0].datapoints[0][1]).toBe(start * 1000);
expect(results.data[0].datapoints[0][0]).toBe(null);
expect(results.data[0].datapoints[1][1]).toBe((start + step * 1) * 1000);
expect(results.data[0].datapoints[1][0]).toBe(3846);
expect(results.data[0].fields[0].values.get(0)).toBe(start * 1000);
expect(results.data[0].fields[1].values.get(0)).toBe(null);
expect(results.data[0].fields[0].values.get(1)).toBe((start + step * 1) * 1000);
expect(results.data[0].fields[1].values.get(1)).toBe(3846);
});
it('should fill null after last datapoint in response', () => {
const length = (end - start) / step + 1;
expect(results.data[0].datapoints[length - 2][1]).toBe((end - step * 1) * 1000);
expect(results.data[0].datapoints[length - 2][0]).toBe(3848);
expect(results.data[0].datapoints[length - 1][1]).toBe(end * 1000);
expect(results.data[0].datapoints[length - 1][0]).toBe(null);
expect(results.data[0].fields[0].values.get(length - 2)).toBe((end - step * 1) * 1000);
expect(results.data[0].fields[1].values.get(length - 2)).toBe(3848);
expect(results.data[0].fields[0].values.get(length - 1)).toBe(end * 1000);
expect(results.data[0].fields[1].values.get(length - 1)).toBe(null);
});
it('should fill null at gap between series', () => {
expect(results.data[0].datapoints[2][1]).toBe((start + step * 2) * 1000);
expect(results.data[0].datapoints[2][0]).toBe(null);
expect(results.data[1].datapoints[1][1]).toBe((start + step * 1) * 1000);
expect(results.data[1].datapoints[1][0]).toBe(null);
expect(results.data[1].datapoints[3][1]).toBe((start + step * 3) * 1000);
expect(results.data[1].datapoints[3][0]).toBe(null);
expect(results.data[0].fields[0].values.get(2)).toBe((start + step * 2) * 1000);
expect(results.data[0].fields[1].values.get(2)).toBe(null);
expect(results.data[1].fields[0].values.get(1)).toBe((start + step * 1) * 1000);
expect(results.data[1].fields[1].values.get(1)).toBe(null);
expect(results.data[1].fields[0].values.get(3)).toBe((start + step * 3) * 1000);
expect(results.data[1].fields[1].values.get(3)).toBe(null);
});
});
......
import _ from 'lodash';
import { map } from 'rxjs/operators';
import { MetricFindValue, TimeRange } from '@grafana/data';
import { PromDataQueryResponse, PrometheusDatasource } from './datasource';
import { PrometheusDatasource } from './datasource';
import { PromQueryRequest } from './types';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
......@@ -137,7 +137,7 @@ export default class PrometheusMetricFindQuery {
const end = this.datasource.getPrometheusTime(this.range.to, true);
const instantQuery: PromQueryRequest = { expr: query } as PromQueryRequest;
return this.datasource.performInstantQuery(instantQuery, end).pipe(
map((result: PromDataQueryResponse) => {
map(result => {
return _.map(result.data.data.result, metricData => {
let text = metricData.metric.__name__ || '';
delete metricData.metric.__name__;
......
import { DataQuery, DataSourceJsonData } from '@grafana/data';
import { DataQuery, DataSourceJsonData, QueryResultMeta, ScopedVars } from '@grafana/data';
import { FetchError } from '@grafana/runtime';
export interface PromQuery extends DataQuery {
expr: string;
......@@ -41,3 +42,77 @@ export interface PromMetricsMetadataItem {
export interface PromMetricsMetadata {
[metric: string]: PromMetricsMetadataItem[];
}
export interface PromDataSuccessResponse<T = PromData> {
status: 'success';
data: T;
}
export interface PromDataErrorResponse<T = PromData> {
status: 'error';
errorType: string;
error: string;
data: T;
}
export type PromData = PromMatrixData | PromVectorData | PromScalarData;
export interface PromVectorData {
resultType: 'vector';
result: Array<{
metric: PromMetric;
value: PromValue;
}>;
}
export interface PromMatrixData {
resultType: 'matrix';
result: Array<{
metric: PromMetric;
values: PromValue[];
}>;
}
export interface PromScalarData {
resultType: 'scalar';
result: PromValue;
}
export type PromValue = [number, any];
export interface PromMetric {
__name__?: string;
[index: string]: any;
}
export function isFetchErrorResponse(response: any): response is FetchError {
return 'cancelled' in response;
}
export function isMatrixData(result: MatrixOrVectorResult): result is PromMatrixData['result'][0] {
return 'values' in result;
}
export type MatrixOrVectorResult = PromMatrixData['result'][0] | PromVectorData['result'][0];
export interface TransformOptions {
format?: string;
step?: number;
legendFormat?: string;
start: number;
end: number;
query: string;
responseListLength: number;
scopedVars?: ScopedVars;
refId: string;
valueWithRefId?: boolean;
meta: QueryResultMeta;
}
export interface PromLabelQueryResponse {
data: {
status: string;
data: string[];
};
cancelled?: boolean;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment