Commit e50a75f2 by Torkel Ödegaard Committed by GitHub

Singlestat/Gauge/BarGauge: Improvements to decimals logic and added test dashboard (#18676)

* Singlevalue: Improvements to decimals logic and added test dashboard

* updated

* Fixed tests
parent 0f2a393e
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"links": [],
"panels": [
{
"cacheTimeout": null,
"gridPos": {
"h": 5,
"w": 4,
"x": 0,
"y": 0
},
"id": 2,
"links": [],
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [
{
"id": 0,
"op": "=",
"text": "N/A",
"type": 1,
"value": "null"
}
],
"max": 100,
"min": 0,
"nullValueMode": "connected",
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "none"
},
"override": {},
"values": false
},
"orientation": "horizontal",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,0.2"
}
],
"timeFrom": null,
"timeShift": null,
"title": "0.2 = 0.2",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 4,
"y": 0
},
"id": 4,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,0.0002"
}
],
"timeFrom": null,
"timeShift": null,
"title": "0.0002 = 0.0002",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 8,
"y": 0
},
"id": 3,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1.125"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1.125 = 1.12",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 12,
"y": 0
},
"id": 19,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,2.235"
}
],
"timeFrom": null,
"timeShift": null,
"title": "2.235 = 2.2",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 16,
"y": 0
},
"id": 6,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1000 = 1K",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 20,
"y": 0
},
"id": 7,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1200"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1200 = 1.2K",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 0,
"y": 5
},
"id": 8,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1250"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1250 = 1.25K",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 4,
"y": 5
},
"id": 9,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1500"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1500 = 1.5K",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 8,
"y": 5
},
"id": 10,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,15258"
}
],
"timeFrom": null,
"timeShift": null,
"title": "15258 = 15.26K",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 12,
"y": 5
},
"id": 5,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,100.50"
}
],
"timeFrom": null,
"timeShift": null,
"title": "100.50 = 101",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 16,
"y": 5
},
"id": 11,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1500000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1500000 = 1.5Mil",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 20,
"y": 5
},
"id": 13,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1000000000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1000000000 = 1 Bil",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 0,
"y": 10
},
"id": 14,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1500000000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1500000000 = 1.5 Bil",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 4,
"y": 10
},
"id": 15,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "ms"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1000 (ms) = 1s",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 8,
"y": 10
},
"id": 16,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "ms"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1200"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1200 (ms) = 1.2s",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 12,
"y": 10
},
"id": 12,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "short"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1000000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1000000 = 1 Mil",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 16,
"y": 10
},
"id": 18,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "ms"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,90000"
}
],
"timeFrom": null,
"timeShift": null,
"title": "90000 (ms) = 1.5 min",
"type": "gauge"
},
{
"gridPos": {
"h": 5,
"w": 4,
"x": 0,
"y": 15
},
"id": 17,
"options": {
"fieldOptions": {
"calcs": ["lastNotNull"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
],
"unit": "ms"
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"alias": "",
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "0,1200"
}
],
"timeFrom": null,
"timeShift": null,
"title": "1860 (ms) = 1.86s",
"type": "gauge"
}
],
"schemaVersion": 19,
"style": "dark",
"tags": ["gdev", "panel-tests"],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
},
"timezone": "",
"title": "Panel Tests - Auto Decimals",
"uid": "5mqG8qdZz",
"version": 1
}
import { MappingType, ValueMapping, DisplayProcessor, DisplayValue } from '@grafana/data'; import { MappingType, ValueMapping, DisplayProcessor, DisplayValue } from '@grafana/data';
import { getDisplayProcessor, getColorFromThreshold } from './displayProcessor';
import { getDisplayProcessor, getColorFromThreshold, getDecimalsForValue } from './displayProcessor';
function assertSame(input: any, processors: DisplayProcessor[], match: DisplayValue) { function assertSame(input: any, processors: DisplayProcessor[], match: DisplayValue) {
processors.forEach(processor => { processors.forEach(processor => {
...@@ -135,17 +134,16 @@ describe('Format value', () => { ...@@ -135,17 +134,16 @@ describe('Format value', () => {
}); });
it('should set auto decimals, 1 significant', () => { it('should set auto decimals, 1 significant', () => {
const value = '1.23'; const value = 3.23;
const instance = getDisplayProcessor({ field: { decimals: null } }); const instance = getDisplayProcessor({ field: { decimals: null } });
expect(instance(value).text).toEqual('3.2');
expect(instance(value).text).toEqual('1.2');
}); });
it('should set auto decimals, 2 significant', () => { it('should set auto decimals, 2 significant', () => {
const value = '0.0245'; const value = 0.0245;
const instance = getDisplayProcessor({ field: { decimals: null } }); const instance = getDisplayProcessor({ field: { decimals: null } });
expect(instance(value).text).toEqual('0.02'); expect(instance(value).text).toEqual('0.025');
}); });
it('should use override decimals', () => { it('should use override decimals', () => {
...@@ -164,20 +162,32 @@ describe('Format value', () => { ...@@ -164,20 +162,32 @@ describe('Format value', () => {
expect(instance(value).text).toEqual('1-20'); expect(instance(value).text).toEqual('1-20');
}); });
});
describe('getDecimalsForValue()', () => { //
it('should calculate reasonable decimals precision for given value', () => { // Below is current behavior but I it's clearly not working great
expect(getDecimalsForValue(1.01)).toEqual({ decimals: 1, scaledDecimals: 4 }); //
expect(getDecimalsForValue(9.01)).toEqual({ decimals: 0, scaledDecimals: 2 });
expect(getDecimalsForValue(1.1)).toEqual({ decimals: 1, scaledDecimals: 4 }); it('with value 1000 and unit short', () => {
expect(getDecimalsForValue(2)).toEqual({ decimals: 0, scaledDecimals: 2 }); const value = 1000;
expect(getDecimalsForValue(20)).toEqual({ decimals: 0, scaledDecimals: 1 }); const instance = getDisplayProcessor({ field: { decimals: null, unit: 'short' } });
expect(getDecimalsForValue(200)).toEqual({ decimals: 0, scaledDecimals: 0 }); expect(instance(value).text).toEqual('1.000 K');
expect(getDecimalsForValue(2000)).toEqual({ decimals: 0, scaledDecimals: 0 }); });
expect(getDecimalsForValue(20000)).toEqual({ decimals: 0, scaledDecimals: -2 });
expect(getDecimalsForValue(200000)).toEqual({ decimals: 0, scaledDecimals: -3 }); it('with value 1200 and unit short', () => {
expect(getDecimalsForValue(200000000)).toEqual({ decimals: 0, scaledDecimals: -6 }); const value = 1200;
expect(getDecimalsForValue(100, 2)).toEqual({ decimals: 2, scaledDecimals: null }); const instance = getDisplayProcessor({ field: { decimals: null, unit: 'short' } });
expect(instance(value).text).toEqual('1.200 K');
});
it('with value 1250 and unit short', () => {
const value = 1250;
const instance = getDisplayProcessor({ field: { decimals: null, unit: 'short' } });
expect(instance(value).text).toEqual('1.250 K');
});
it('with value 10000000 and unit short', () => {
const value = 1000000;
const instance = getDisplayProcessor({ field: { decimals: null, unit: 'short' } });
expect(instance(value).text).toEqual('1.000 Mil');
}); });
}); });
...@@ -127,17 +127,31 @@ export function getColorFromThreshold(value: number, thresholds: Threshold[], th ...@@ -127,17 +127,31 @@ export function getColorFromThreshold(value: number, thresholds: Threshold[], th
return getColorFromHexRgbOrName(thresholds[0].color, themeType); return getColorFromHexRgbOrName(thresholds[0].color, themeType);
} }
// function getSignificantDigitCount(n: number): number {
// // remove decimal and make positive
// n = Math.abs(parseInt(String(n).replace('.', ''), 10));
// if (n === 0) {
// return 0;
// }
//
// // kill the 0s at the end of n
// while (n !== 0 && n % 10 === 0) {
// n /= 10;
// }
//
// // get number of digits
// return Math.floor(Math.log(n) / Math.LN10) + 1;
// }
export function getDecimalsForValue(value: number, decimalOverride?: DecimalCount): DecimalInfo { export function getDecimalsForValue(value: number, decimalOverride?: DecimalCount): DecimalInfo {
if (_.isNumber(decimalOverride)) { if (_.isNumber(decimalOverride)) {
// It's important that scaledDecimals is null here // It's important that scaledDecimals is null here
return { decimals: decimalOverride, scaledDecimals: null }; return { decimals: decimalOverride, scaledDecimals: null };
} }
const delta = value / 2; let dec = -Math.floor(Math.log(value) / Math.LN10) + 1;
let dec = -Math.floor(Math.log(delta) / Math.LN10);
const magn = Math.pow(10, -dec); const magn = Math.pow(10, -dec);
const norm = delta / magn; // norm is between 1.0 and 10.0 const norm = value / magn; // norm is between 1.0 and 10.0
let size; let size;
if (norm < 1.5) { if (norm < 1.5) {
...@@ -158,7 +172,7 @@ export function getDecimalsForValue(value: number, decimalOverride?: DecimalCoun ...@@ -158,7 +172,7 @@ export function getDecimalsForValue(value: number, decimalOverride?: DecimalCoun
size *= magn; size *= magn;
// reduce starting decimals if not needed // reduce starting decimals if not needed
if (Math.floor(value) === value) { if (value % 1 === 0) {
dec = 0; dec = 0;
} }
......
...@@ -193,7 +193,7 @@ describe('SingleStatCtrl', () => { ...@@ -193,7 +193,7 @@ describe('SingleStatCtrl', () => {
singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => { singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => {
ctx.setup(() => { ctx.setup(() => {
ctx.input = [{ target: 'test.cpu1', datapoints: [[9.9, 1]] }]; ctx.input = [{ target: 'test.cpu1', datapoints: [[9.9, 1]] }];
ctx.ctrl.panel.valueMaps = [{ value: '10', text: 'OK' }]; ctx.ctrl.panel.valueMaps = [{ value: '9.9', text: 'OK' }];
}); });
it('value should remain', () => { it('value should remain', () => {
...@@ -291,20 +291,16 @@ describe('SingleStatCtrl', () => { ...@@ -291,20 +291,16 @@ describe('SingleStatCtrl', () => {
singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => { singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => {
ctx.setup(() => { ctx.setup(() => {
ctx.input = tableData; ctx.input = tableData;
ctx.input[0].rows[0] = [1492759673649, 'ignore1', 9.9, 'ignore2']; ctx.input[0].rows[0] = [1492759673649, 'ignore1', 10, 'ignore2'];
ctx.ctrl.panel.mappingType = 2; ctx.ctrl.panel.mappingType = 2;
ctx.ctrl.panel.tableColumn = 'mean'; ctx.ctrl.panel.tableColumn = 'mean';
ctx.ctrl.panel.valueMaps = [{ value: '10', text: 'OK' }]; ctx.ctrl.panel.valueMaps = [{ value: '10', text: 'OK' }];
}); });
it('value should remain', () => { it('value should remain', () => {
expect(ctx.data.value).toBe(9.9); expect(ctx.data.value).toBe(10);
}); });
// it('round should be rounded up', () => {
// expect(ctx.data.valueRounded).toBe(10);
// });
it('Should replace value with text', () => { it('Should replace value with text', () => {
expect(ctx.data.display.text).toBe('OK'); expect(ctx.data.display.text).toBe('OK');
}); });
......
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