Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/pmetrictest] option to ignore float precision discrepancies when using CompareMetrics #35085

Merged
7 changes: 7 additions & 0 deletions pkg/pdatatest/pmetrictest/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ func TestCompareMetrics(t *testing.T) {
},
withoutOptions: errors.New(`resource "map[]": scope "": metric "gauge.one": datapoint "map[]": double value doesn't match expected: 123.456000, actual: 654.321000`),
},
{
name: "ignore-data-point-value-double-precision",
compareOptions: []CompareMetricsOption{
IgnoreMetricFloatPrecision(3),
},
withoutOptions: errors.New(`resource "map[]": scope "": metric "gauge.one": datapoint "map[]": double value doesn't match expected: 654.321110, actual: 654.321000`),
},
{
name: "ignore-data-point-value-int-mismatch",
compareOptions: []CompareMetricsOption{
Expand Down
51 changes: 51 additions & 0 deletions pkg/pdatatest/pmetrictest/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package pmetrictest // import "github.com/open-telemetry/opentelemetry-collector
import (
"bytes"
"fmt"
"math"
"regexp"
"sort"
"time"
Expand Down Expand Up @@ -110,6 +111,56 @@ func maskHistogramDataPointSliceValues(dataPoints pmetric.HistogramDataPointSlic
}
}

// IgnoreMetricFloatPrecision is a CompareMetricsOption that rounds away float precision discrepancies in metric values.
func IgnoreMetricFloatPrecision(precision int, metricNames ...string) CompareMetricsOption {
return compareMetricsOptionFunc(func(expected, actual pmetric.Metrics) {
floatMetricValues(precision, expected, metricNames...)
floatMetricValues(precision, actual, metricNames...)
})
}

func floatMetricValues(precision int, metrics pmetric.Metrics, metricNames ...string) {
rms := metrics.ResourceMetrics()
for i := 0; i < rms.Len(); i++ {
ilms := rms.At(i).ScopeMetrics()
for j := 0; j < ilms.Len(); j++ {
floatMetricSliceValues(precision, ilms.At(j).Metrics(), metricNames...)
}
}
}

// floatMetricSliceValues sets all data point values to zero.
func floatMetricSliceValues(precision int, metrics pmetric.MetricSlice, metricNames ...string) {
metricNameSet := make(map[string]bool, len(metricNames))
for _, metricName := range metricNames {
metricNameSet[metricName] = true
}
for i := 0; i < metrics.Len(); i++ {
if len(metricNames) == 0 || metricNameSet[metrics.At(i).Name()] {
switch metrics.At(i).Type() {
case pmetric.MetricTypeEmpty, pmetric.MetricTypeSum, pmetric.MetricTypeGauge:
roundDataPointSliceValues(getDataPointSlice(metrics.At(i)), precision)
default:
panic(fmt.Sprintf("data type not supported: %s", metrics.At(i).Type()))
}
}
}
}

// maskDataPointSliceValues rounds all data point values at a given decimal.
func roundDataPointSliceValues(dataPoints pmetric.NumberDataPointSlice, precision int) {
for i := 0; i < dataPoints.Len(); i++ {
dataPoint := dataPoints.At(i)
factor := math.Pow(10, float64(precision))
switch {
case dataPoint.DoubleValue() != 0.0:
dataPoint.SetDoubleValue(math.Round(dataPoint.DoubleValue()*factor) / factor)
case dataPoint.IntValue() != 0:
panic(fmt.Sprintf("integers can not have float precision ignored: %v", dataPoints.At(i)))
}
}
}

// IgnoreTimestamp is a CompareMetricsOption that clears Timestamp fields on all the data points.
func IgnoreTimestamp() CompareMetricsOption {
return compareMetricsOptionFunc(func(expected, actual pmetric.Metrics) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resourceMetrics:
- resource: {}
scopeMetrics:
- metrics:
- gauge:
dataPoints:
- asDouble: 654.321
name: gauge.one
scope: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resourceMetrics:
- resource: {}
scopeMetrics:
- metrics:
- gauge:
dataPoints:
- asDouble: 654.32111
name: gauge.one
scope: {}
Loading