Skip to content

Commit

Permalink
[pkg/pmetrictest] option to ignore float precision discrepancies when…
Browse files Browse the repository at this point in the history
… using `CompareMetrics` (open-telemetry#35085)

**Description:** <Describe what has changed.>
Addresses issue:
open-telemetry#35060
Adds option to `CompareMetrics` testing function that rounds floats to
an arbitrary number of decimals. This is needed to avoid issues with
float precision during testing.

**Link to tracking Issue:** <Issue number if applicable>

open-telemetry#35060

**Testing:** <Describe what testing was performed and which tests were
added.>
Test and test data added for this CompareMetrics option

**Documentation:** 
No new docs. Let me know if I should be adding something somewhere!

Co-authored-by: Antoine Toulme <[email protected]>
  • Loading branch information
greatestusername and atoulme authored Sep 11, 2024
1 parent 78318b8 commit 290063a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 0 deletions.
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: {}

0 comments on commit 290063a

Please sign in to comment.