Commit f3c09e8b by Aliaksei Tuzik Committed by GitHub

Prometheus: fix parsing of infinite sample values (#28287) (#28288)

* Prometheus: fix parsing of infinite sample values (#28287)

* Prometheus: Use common function to parse both sample values and histogram "le" label
parent ec40e49d
...@@ -379,4 +379,47 @@ describe('Prometheus Result Transformer', () => { ...@@ -379,4 +379,47 @@ describe('Prometheus Result Transformer', () => {
expect(result[0].fields[1].values.toArray()).toEqual([null, null, 10, null, 10]); expect(result[0].fields[1].values.toArray()).toEqual([null, null, 10, null, 10]);
}); });
}); });
describe('When infinity values are returned', () => {
describe('When resultType is scalar', () => {
const response = {
status: 'success',
data: {
resultType: 'scalar',
result: [1443454528, '+Inf'],
},
};
it('should correctly parse values', () => {
const result: DataFrame[] = transform({ data: response } as any, { ...options, target: { format: 'table' } });
expect(result[0].fields[1].values.toArray()).toEqual([Number.POSITIVE_INFINITY]);
});
});
describe('When resultType is vector', () => {
const response = {
status: 'success',
data: {
resultType: 'vector',
result: [
{
metric: { __name__: 'test', job: 'testjob' },
value: [1443454528, '+Inf'],
},
{
metric: { __name__: 'test', job: 'testjob' },
value: [1443454528, '-Inf'],
},
],
},
};
describe('When format is table', () => {
it('should correctly parse values', () => {
const result: DataFrame[] = transform({ data: response } as any, { ...options, target: { format: 'table' } });
expect(result[0].fields[3].values.toArray()).toEqual([Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]);
});
});
});
});
}); });
...@@ -22,6 +22,9 @@ import { ...@@ -22,6 +22,9 @@ import {
TransformOptions, TransformOptions,
} from './types'; } from './types';
const POSITIVE_INFINITY_SAMPLE_VALUE = '+Inf';
const NEGATIVE_INFINITY_SAMPLE_VALUE = '-Inf';
export function transform( export function transform(
response: FetchResponse<PromDataSuccessResponse>, response: FetchResponse<PromDataSuccessResponse>,
transformOptions: { transformOptions: {
...@@ -116,7 +119,7 @@ function transformToDataFrame(data: MatrixOrVectorResult, options: TransformOpti ...@@ -116,7 +119,7 @@ function transformToDataFrame(data: MatrixOrVectorResult, options: TransformOpti
const dps: PromValue[] = []; const dps: PromValue[] = [];
for (const value of data.values) { for (const value of data.values) {
let dpValue: number | null = parseFloat(value[1]); let dpValue: number | null = parseSampleValue(value[1]);
if (isNaN(dpValue)) { if (isNaN(dpValue)) {
dpValue = null; dpValue = null;
...@@ -180,12 +183,12 @@ function transformMetricDataToTable(md: MatrixOrVectorResult[], options: Transfo ...@@ -180,12 +183,12 @@ function transformMetricDataToTable(md: MatrixOrVectorResult[], options: Transfo
d.values.forEach(val => { d.values.forEach(val => {
timeField.values.add(val[0] * 1000); timeField.values.add(val[0] * 1000);
metricFields.forEach(metricField => metricField.values.add(getLabelValue(d.metric, metricField.name))); metricFields.forEach(metricField => metricField.values.add(getLabelValue(d.metric, metricField.name)));
valueField.values.add(parseFloat(val[1])); valueField.values.add(parseSampleValue(val[1]));
}); });
} else { } else {
timeField.values.add(d.value[0] * 1000); timeField.values.add(d.value[0] * 1000);
metricFields.forEach(metricField => metricField.values.add(getLabelValue(d.metric, metricField.name))); metricFields.forEach(metricField => metricField.values.add(getLabelValue(d.metric, metricField.name)));
valueField.values.add(parseFloat(d.value[1])); valueField.values.add(parseSampleValue(d.value[1]));
} }
}); });
...@@ -200,7 +203,7 @@ function transformMetricDataToTable(md: MatrixOrVectorResult[], options: Transfo ...@@ -200,7 +203,7 @@ function transformMetricDataToTable(md: MatrixOrVectorResult[], options: Transfo
function getLabelValue(metric: PromMetric, label: string): string | number { function getLabelValue(metric: PromMetric, label: string): string | number {
if (metric.hasOwnProperty(label)) { if (metric.hasOwnProperty(label)) {
if (label === 'le') { if (label === 'le') {
return parseHistogramLabel(metric[label]); return parseSampleValue(metric[label]);
} }
return metric[label]; return metric[label];
} }
...@@ -225,7 +228,7 @@ function getValueField( ...@@ -225,7 +228,7 @@ function getValueField(
name: valueName, name: valueName,
type: FieldType.number, type: FieldType.number,
config: {}, config: {},
values: new ArrayVector<number | null>(data.map(val => (parseValue ? parseFloat(val[1]) : val[1]))), values: new ArrayVector<number | null>(data.map(val => (parseValue ? parseSampleValue(val[1]) : val[1]))),
}; };
} }
...@@ -289,8 +292,8 @@ function sortSeriesByLabel(s1: DataFrame, s2: DataFrame): number { ...@@ -289,8 +292,8 @@ function sortSeriesByLabel(s1: DataFrame, s2: DataFrame): number {
try { try {
// fail if not integer. might happen with bad queries // fail if not integer. might happen with bad queries
le1 = parseHistogramLabel(s1.name ?? ''); le1 = parseSampleValue(s1.name ?? '');
le2 = parseHistogramLabel(s2.name ?? ''); le2 = parseSampleValue(s2.name ?? '');
} catch (err) { } catch (err) {
console.error(err); console.error(err);
return 0; return 0;
...@@ -307,9 +310,13 @@ function sortSeriesByLabel(s1: DataFrame, s2: DataFrame): number { ...@@ -307,9 +310,13 @@ function sortSeriesByLabel(s1: DataFrame, s2: DataFrame): number {
return 0; return 0;
} }
function parseHistogramLabel(le: string): number { function parseSampleValue(value: string): number {
if (le === '+Inf') { switch (value) {
return +Infinity; case POSITIVE_INFINITY_SAMPLE_VALUE:
return Number.POSITIVE_INFINITY;
case NEGATIVE_INFINITY_SAMPLE_VALUE:
return Number.NEGATIVE_INFINITY;
default:
return parseFloat(value);
} }
return Number(le);
} }
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