diff --git a/sdk/metric/metricdata/data.go b/sdk/metric/metricdata/data.go index ac9eb54c55a..b770b702346 100644 --- a/sdk/metric/metricdata/data.go +++ b/sdk/metric/metricdata/data.go @@ -65,17 +65,17 @@ type Aggregation interface { } // Gauge represents a measurement of the current value of an instrument. -type Gauge struct { +type Gauge[N int64 | float64] struct { // DataPoints reprents individual aggregated measurements with unique Attributes. - DataPoints []DataPoint + DataPoints []DataPoint[N] } -func (Gauge) privateAggregation() {} +func (Gauge[N]) privateAggregation() {} // Sum represents the sum of all measurements of values from an instrument. -type Sum struct { +type Sum[N int64 | float64] struct { // DataPoints reprents individual aggregated measurements with unique Attributes. - DataPoints []DataPoint + DataPoints []DataPoint[N] // Temporality describes if the aggregation is reported as the change from the // last report time, or the cumulative changes since a fixed start time. Temporality Temporality @@ -83,10 +83,10 @@ type Sum struct { IsMonotonic bool } -func (Sum) privateAggregation() {} +func (Sum[N]) privateAggregation() {} // DataPoint is a single data point in a timeseries. -type DataPoint struct { +type DataPoint[N int64 | float64] struct { // Attributes is the set of key value pairs that uniquely identify the // timeseries. Attributes attribute.Set @@ -95,25 +95,9 @@ type DataPoint struct { // Time is the time when the timeseries was recorded. (optional) Time time.Time // Value is the value of this data point. - Value Value + Value N } -// Value is a int64 or float64. All Values created by the sdk will be either -// Int64 or Float64. -type Value interface { - privateValue() -} - -// Int64 is a container for an int64 value. -type Int64 int64 - -func (Int64) privateValue() {} - -// Float64 is a container for a float64 value. -type Float64 float64 - -func (Float64) privateValue() {} - // Histogram represents the histogram of all measurements of values from an instrument. type Histogram struct { // DataPoints reprents individual aggregated measurements with unique Attributes. diff --git a/sdk/metric/metricdata/metricdatatest/assertion.go b/sdk/metric/metricdata/metricdatatest/assertion.go index 9d32886904d..c66409f4814 100644 --- a/sdk/metric/metricdata/metricdatatest/assertion.go +++ b/sdk/metric/metricdata/metricdatatest/assertion.go @@ -28,7 +28,17 @@ import ( // Datatypes are the concrete data-types the metricdata package provides. type Datatypes interface { - metricdata.DataPoint | metricdata.Float64 | metricdata.Gauge | metricdata.Histogram | metricdata.HistogramDataPoint | metricdata.Int64 | metricdata.Metrics | metricdata.ResourceMetrics | metricdata.ScopeMetrics | metricdata.Sum + metricdata.DataPoint[float64] | + metricdata.DataPoint[int64] | + metricdata.Gauge[float64] | + metricdata.Gauge[int64] | + metricdata.Histogram | + metricdata.HistogramDataPoint | + metricdata.Metrics | + metricdata.ResourceMetrics | + metricdata.ScopeMetrics | + metricdata.Sum[float64] | + metricdata.Sum[int64] // Interface types are not allowed in union types, therefore the // Aggregation and Value type from metricdata are not included here. @@ -44,26 +54,28 @@ func AssertEqual[T Datatypes](t *testing.T, expected, actual T) bool { var r []string switch e := interface{}(expected).(type) { - case metricdata.DataPoint: - r = equalDataPoints(e, aIface.(metricdata.DataPoint)) - case metricdata.Float64: - r = equalFloat64(e, aIface.(metricdata.Float64)) - case metricdata.Gauge: - r = equalGauges(e, aIface.(metricdata.Gauge)) + case metricdata.DataPoint[int64]: + r = equalDataPoints(e, aIface.(metricdata.DataPoint[int64])) + case metricdata.DataPoint[float64]: + r = equalDataPoints(e, aIface.(metricdata.DataPoint[float64])) + case metricdata.Gauge[int64]: + r = equalGauges(e, aIface.(metricdata.Gauge[int64])) + case metricdata.Gauge[float64]: + r = equalGauges(e, aIface.(metricdata.Gauge[float64])) case metricdata.Histogram: r = equalHistograms(e, aIface.(metricdata.Histogram)) case metricdata.HistogramDataPoint: r = equalHistogramDataPoints(e, aIface.(metricdata.HistogramDataPoint)) - case metricdata.Int64: - r = equalInt64(e, aIface.(metricdata.Int64)) case metricdata.Metrics: r = equalMetrics(e, aIface.(metricdata.Metrics)) case metricdata.ResourceMetrics: r = equalResourceMetrics(e, aIface.(metricdata.ResourceMetrics)) case metricdata.ScopeMetrics: r = equalScopeMetrics(e, aIface.(metricdata.ScopeMetrics)) - case metricdata.Sum: - r = equalSums(e, aIface.(metricdata.Sum)) + case metricdata.Sum[int64]: + r = equalSums(e, aIface.(metricdata.Sum[int64])) + case metricdata.Sum[float64]: + r = equalSums(e, aIface.(metricdata.Sum[float64])) default: // We control all types passed to this, panic to signal developers // early they changed things in an incompatible way. @@ -86,13 +98,3 @@ func AssertAggregationsEqual(t *testing.T, expected, actual metricdata.Aggregati } return true } - -// AssertValuesEqual asserts that two Values are equal. -func AssertValuesEqual(t *testing.T, expected, actual metricdata.Value) bool { - t.Helper() - if r := equalValues(expected, actual); len(r) > 0 { - t.Error(r) - return false - } - return true -} diff --git a/sdk/metric/metricdata/metricdatatest/assertion_fail_test.go b/sdk/metric/metricdata/metricdatatest/assertion_fail_test.go index 228bfbddd8c..fffbe6421be 100644 --- a/sdk/metric/metricdata/metricdatatest/assertion_fail_test.go +++ b/sdk/metric/metricdata/metricdatatest/assertion_fail_test.go @@ -37,27 +37,23 @@ func TestFailAssertEqual(t *testing.T) { t.Run("ScopeMetrics", testFailDatatype(scopeMetricsA, scopeMetricsB)) t.Run("Metrics", testFailDatatype(metricsA, metricsB)) t.Run("Histogram", testFailDatatype(histogramA, histogramB)) - t.Run("Sum", testFailDatatype(sumA, sumB)) - t.Run("Gauge", testFailDatatype(gaugeA, gaugeB)) + t.Run("SumInt64", testFailDatatype(sumInt64A, sumInt64B)) + t.Run("SumFloat64", testFailDatatype(sumFloat64A, sumFloat64B)) + t.Run("GaugeInt64", testFailDatatype(gaugeInt64A, gaugeInt64B)) + t.Run("GaugeFloat64", testFailDatatype(gaugeFloat64A, gaugeFloat64B)) t.Run("HistogramDataPoint", testFailDatatype(histogramDataPointA, histogramDataPointB)) - t.Run("DataPoint", testFailDatatype(dataPointsA, dataPointsB)) - t.Run("Int64", testFailDatatype(int64A, int64B)) - t.Run("Float64", testFailDatatype(float64A, float64B)) + t.Run("DataPointInt64", testFailDatatype(dataPointInt64A, dataPointInt64B)) + t.Run("DataPointFloat64", testFailDatatype(dataPointFloat64A, dataPointFloat64B)) + } func TestFailAssertAggregationsEqual(t *testing.T) { - AssertAggregationsEqual(t, sumA, nil) - AssertAggregationsEqual(t, sumA, gaugeA) + AssertAggregationsEqual(t, sumInt64A, nil) + AssertAggregationsEqual(t, sumFloat64A, gaugeFloat64A) AssertAggregationsEqual(t, unknownAggregation{}, unknownAggregation{}) - AssertAggregationsEqual(t, sumA, sumB) - AssertAggregationsEqual(t, gaugeA, gaugeB) + AssertAggregationsEqual(t, sumInt64A, sumInt64B) + AssertAggregationsEqual(t, sumFloat64A, sumFloat64B) + AssertAggregationsEqual(t, gaugeInt64A, gaugeInt64B) + AssertAggregationsEqual(t, gaugeFloat64A, gaugeFloat64B) AssertAggregationsEqual(t, histogramA, histogramB) } - -func TestFailAssertValuesEqual(t *testing.T) { - AssertValuesEqual(t, int64A, nil) - AssertValuesEqual(t, int64A, float64A) - AssertValuesEqual(t, unknownValue{}, unknownValue{}) - AssertValuesEqual(t, int64A, int64B) - AssertValuesEqual(t, float64A, float64B) -} diff --git a/sdk/metric/metricdata/metricdatatest/assertion_test.go b/sdk/metric/metricdata/metricdatatest/assertion_test.go index 79d639ba2c3..79657dd15fb 100644 --- a/sdk/metric/metricdata/metricdatatest/assertion_test.go +++ b/sdk/metric/metricdata/metricdatatest/assertion_test.go @@ -34,28 +34,34 @@ var ( attrA = attribute.NewSet(attribute.Bool("A", true)) attrB = attribute.NewSet(attribute.Bool("B", true)) - float64A = metricdata.Float64(-1.0) - float64B = metricdata.Float64(2.0) - - int64A = metricdata.Int64(-1) - int64B = metricdata.Int64(2) - startA = time.Now() startB = startA.Add(time.Millisecond) endA = startA.Add(time.Second) endB = startB.Add(time.Second) - dataPointsA = metricdata.DataPoint{ + dataPointInt64A = metricdata.DataPoint[int64]{ Attributes: attrA, StartTime: startA, Time: endA, - Value: int64A, + Value: -1, + } + dataPointFloat64A = metricdata.DataPoint[float64]{ + Attributes: attrA, + StartTime: startA, + Time: endA, + Value: -1.0, + } + dataPointInt64B = metricdata.DataPoint[int64]{ + Attributes: attrB, + StartTime: startB, + Time: endB, + Value: 2, } - dataPointsB = metricdata.DataPoint{ + dataPointFloat64B = metricdata.DataPoint[float64]{ Attributes: attrB, StartTime: startB, Time: endB, - Value: float64B, + Value: 2.0, } max, min = 99.0, 3. @@ -80,18 +86,38 @@ var ( Sum: 3, } - gaugeA = metricdata.Gauge{DataPoints: []metricdata.DataPoint{dataPointsA}} - gaugeB = metricdata.Gauge{DataPoints: []metricdata.DataPoint{dataPointsB}} + gaugeInt64A = metricdata.Gauge[int64]{ + DataPoints: []metricdata.DataPoint[int64]{dataPointInt64A}, + } + gaugeFloat64A = metricdata.Gauge[float64]{ + DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64A}, + } + gaugeInt64B = metricdata.Gauge[int64]{ + DataPoints: []metricdata.DataPoint[int64]{dataPointInt64B}, + } + gaugeFloat64B = metricdata.Gauge[float64]{ + DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64B}, + } - sumA = metricdata.Sum{ + sumInt64A = metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, - DataPoints: []metricdata.DataPoint{dataPointsA}, + DataPoints: []metricdata.DataPoint[int64]{dataPointInt64A}, } - sumB = metricdata.Sum{ - Temporality: metricdata.DeltaTemporality, - IsMonotonic: false, - DataPoints: []metricdata.DataPoint{dataPointsB}, + sumFloat64A = metricdata.Sum[float64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: true, + DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64A}, + } + sumInt64B = metricdata.Sum[int64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: true, + DataPoints: []metricdata.DataPoint[int64]{dataPointInt64B}, + } + sumFloat64B = metricdata.Sum[float64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: true, + DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64B}, } histogramA = metricdata.Histogram{ @@ -107,13 +133,13 @@ var ( Name: "A", Description: "A desc", Unit: unit.Dimensionless, - Data: sumA, + Data: sumInt64A, } metricsB = metricdata.Metrics{ Name: "B", Description: "B desc", Unit: unit.Bytes, - Data: gaugeB, + Data: gaugeFloat64B, } scopeMetricsA = metricdata.ScopeMetrics{ @@ -152,12 +178,13 @@ func TestAssertEqual(t *testing.T) { t.Run("ScopeMetrics", testDatatype(scopeMetricsA, scopeMetricsB, equalScopeMetrics)) t.Run("Metrics", testDatatype(metricsA, metricsB, equalMetrics)) t.Run("Histogram", testDatatype(histogramA, histogramB, equalHistograms)) - t.Run("Sum", testDatatype(sumA, sumB, equalSums)) - t.Run("Gauge", testDatatype(gaugeA, gaugeB, equalGauges)) + t.Run("SumInt64", testDatatype(sumInt64A, sumInt64B, equalSums[int64])) + t.Run("SumFloat64", testDatatype(sumFloat64A, sumFloat64B, equalSums[float64])) + t.Run("GaugeInt64", testDatatype(gaugeInt64A, gaugeInt64B, equalGauges[int64])) + t.Run("GaugeFloat64", testDatatype(gaugeFloat64A, gaugeFloat64B, equalGauges[float64])) t.Run("HistogramDataPoint", testDatatype(histogramDataPointA, histogramDataPointB, equalHistogramDataPoints)) - t.Run("DataPoint", testDatatype(dataPointsA, dataPointsB, equalDataPoints)) - t.Run("Int64", testDatatype(int64A, int64B, equalInt64)) - t.Run("Float64", testDatatype(float64A, float64B, equalFloat64)) + t.Run("DataPointInt64", testDatatype(dataPointInt64A, dataPointInt64B, equalDataPoints[int64])) + t.Run("DataPointFloat64", testDatatype(dataPointFloat64A, dataPointFloat64B, equalDataPoints[float64])) } type unknownAggregation struct { @@ -166,50 +193,33 @@ type unknownAggregation struct { func TestAssertAggregationsEqual(t *testing.T) { AssertAggregationsEqual(t, nil, nil) - AssertAggregationsEqual(t, sumA, sumA) - AssertAggregationsEqual(t, gaugeA, gaugeA) + AssertAggregationsEqual(t, sumInt64A, sumInt64A) + AssertAggregationsEqual(t, sumFloat64A, sumFloat64A) + AssertAggregationsEqual(t, gaugeInt64A, gaugeInt64A) + AssertAggregationsEqual(t, gaugeFloat64A, gaugeFloat64A) AssertAggregationsEqual(t, histogramA, histogramA) - r := equalAggregations(sumA, nil) + r := equalAggregations(sumInt64A, nil) assert.Len(t, r, 1, "should return nil comparison mismatch only") - r = equalAggregations(sumA, gaugeA) + r = equalAggregations(sumInt64A, gaugeInt64A) assert.Len(t, r, 1, "should return with type mismatch only") r = equalAggregations(unknownAggregation{}, unknownAggregation{}) assert.Len(t, r, 1, "should return with unknown aggregation only") - r = equalAggregations(sumA, sumB) - assert.Greaterf(t, len(r), 0, "%v == %v", sumA, sumB) - - r = equalAggregations(gaugeA, gaugeB) - assert.Greaterf(t, len(r), 0, "%v == %v", gaugeA, gaugeB) - - r = equalAggregations(histogramA, histogramB) - assert.Greaterf(t, len(r), 0, "%v == %v", histogramA, histogramB) -} - -type unknownValue struct { - metricdata.Value -} + r = equalAggregations(sumInt64A, sumInt64B) + assert.Greaterf(t, len(r), 0, "%v == %v", sumInt64A, sumInt64B) -func TestAssertValuesEqual(t *testing.T) { - AssertValuesEqual(t, nil, nil) - AssertValuesEqual(t, int64A, int64A) - AssertValuesEqual(t, float64A, float64A) + r = equalAggregations(sumFloat64A, sumFloat64B) + assert.Greaterf(t, len(r), 0, "%v == %v", sumFloat64A, sumFloat64B) - r := equalValues(int64A, nil) - assert.Len(t, r, 1, "should return nil comparison mismatch only") + r = equalAggregations(gaugeInt64A, gaugeInt64B) + assert.Greaterf(t, len(r), 0, "%v == %v", gaugeInt64A, gaugeInt64B) - r = equalValues(int64A, float64A) - assert.Len(t, r, 1, "should return with type mismatch only") + r = equalAggregations(gaugeFloat64A, gaugeFloat64B) + assert.Greaterf(t, len(r), 0, "%v == %v", gaugeFloat64A, gaugeFloat64B) - r = equalValues(unknownValue{}, unknownValue{}) - assert.Len(t, r, 1, "should return with unknown value only") - - r = equalValues(int64A, int64B) - assert.Greaterf(t, len(r), 0, "%v == %v", int64A, int64B) - - r = equalValues(float64A, float64B) - assert.Greaterf(t, len(r), 0, "%v == %v", float64A, float64B) + r = equalAggregations(histogramA, histogramB) + assert.Greaterf(t, len(r), 0, "%v == %v", histogramA, histogramB) } diff --git a/sdk/metric/metricdata/metricdatatest/comparisons.go b/sdk/metric/metricdata/metricdatatest/comparisons.go index 78e36169461..171e9a50749 100644 --- a/sdk/metric/metricdata/metricdatatest/comparisons.go +++ b/sdk/metric/metricdata/metricdatatest/comparisons.go @@ -110,16 +110,28 @@ func equalAggregations(a, b metricdata.Aggregation) (reasons []string) { } switch v := a.(type) { - case metricdata.Gauge: - r := equalGauges(v, b.(metricdata.Gauge)) + case metricdata.Gauge[int64]: + r := equalGauges(v, b.(metricdata.Gauge[int64])) if len(r) > 0 { - reasons = append(reasons, "Gauge not equal:") + reasons = append(reasons, "Gauge[int64] not equal:") reasons = append(reasons, r...) } - case metricdata.Sum: - r := equalSums(v, b.(metricdata.Sum)) + case metricdata.Gauge[float64]: + r := equalGauges(v, b.(metricdata.Gauge[float64])) if len(r) > 0 { - reasons = append(reasons, "Sum not equal:") + reasons = append(reasons, "Gauge[float64] not equal:") + reasons = append(reasons, r...) + } + case metricdata.Sum[int64]: + r := equalSums(v, b.(metricdata.Sum[int64])) + if len(r) > 0 { + reasons = append(reasons, "Sum[int64] not equal:") + reasons = append(reasons, r...) + } + case metricdata.Sum[float64]: + r := equalSums(v, b.(metricdata.Sum[float64])) + if len(r) > 0 { + reasons = append(reasons, "Sum[float64] not equal:") reasons = append(reasons, r...) } case metricdata.Histogram: @@ -139,11 +151,11 @@ func equalAggregations(a, b metricdata.Aggregation) (reasons []string) { // // The DataPoints each Gauge contains are compared based on containing the // same DataPoints, not the order they are stored in. -func equalGauges(a, b metricdata.Gauge) (reasons []string) { +func equalGauges[N int64 | float64](a, b metricdata.Gauge[N]) (reasons []string) { r := compareDiff(diffSlices( a.DataPoints, b.DataPoints, - func(a, b metricdata.DataPoint) bool { + func(a, b metricdata.DataPoint[N]) bool { r := equalDataPoints(a, b) return len(r) == 0 }, @@ -159,7 +171,7 @@ func equalGauges(a, b metricdata.Gauge) (reasons []string) { // // The DataPoints each Sum contains are compared based on containing the same // DataPoints, not the order they are stored in. -func equalSums(a, b metricdata.Sum) (reasons []string) { +func equalSums[N int64 | float64](a, b metricdata.Sum[N]) (reasons []string) { if a.Temporality != b.Temporality { reasons = append(reasons, notEqualStr("Temporality", a.Temporality, b.Temporality)) } @@ -170,7 +182,7 @@ func equalSums(a, b metricdata.Sum) (reasons []string) { r := compareDiff(diffSlices( a.DataPoints, b.DataPoints, - func(a, b metricdata.DataPoint) bool { + func(a, b metricdata.DataPoint[N]) bool { r := equalDataPoints(a, b) return len(r) == 0 }, @@ -207,7 +219,7 @@ func equalHistograms(a, b metricdata.Histogram) (reasons []string) { // equalDataPoints returns reasons DataPoints are not equal. If they are // equal, the returned reasons will be empty. -func equalDataPoints(a, b metricdata.DataPoint) (reasons []string) { +func equalDataPoints[N int64 | float64](a, b metricdata.DataPoint[N]) (reasons []string) { if !a.Attributes.Equals(&b.Attributes) { reasons = append(reasons, notEqualStr( "Attributes", @@ -222,10 +234,8 @@ func equalDataPoints(a, b metricdata.DataPoint) (reasons []string) { reasons = append(reasons, notEqualStr("Time", a.Time.UnixNano(), b.Time.UnixNano())) } - r := equalValues(a.Value, b.Value) - if len(r) > 0 { - reasons = append(reasons, "DataPoint Value not equal:") - reasons = append(reasons, r...) + if a.Value != b.Value { + reasons = append(reasons, notEqualStr("Value", a.Value, b.Value)) } return reasons } @@ -267,58 +277,6 @@ func equalHistogramDataPoints(a, b metricdata.HistogramDataPoint) (reasons []str return reasons } -// equalValues returns reasons Values are not equal. If they are equal, the -// returned reasons will be empty. -func equalValues(a, b metricdata.Value) (reasons []string) { - if a == nil || b == nil { - if a != b { - return []string{notEqualStr("Values", a, b)} - } - return reasons - } - - if reflect.TypeOf(a) != reflect.TypeOf(b) { - return []string{fmt.Sprintf("Value types not equal:\nexpected: %T\nactual: %T", a, b)} - } - - switch v := a.(type) { - case metricdata.Int64: - r := equalInt64(v, b.(metricdata.Int64)) - if len(r) > 0 { - reasons = append(reasons, "Int64 not equal:") - reasons = append(reasons, r...) - } - case metricdata.Float64: - r := equalFloat64(v, b.(metricdata.Float64)) - if len(r) > 0 { - reasons = append(reasons, "Float64 not equal:") - reasons = append(reasons, r...) - } - default: - reasons = append(reasons, fmt.Sprintf("Value of unknown types %T", a)) - } - - return reasons -} - -// equalFloat64 returns reasons Float64s are not equal. If they are equal, the -// returned reasons will be empty. -func equalFloat64(a, b metricdata.Float64) (reasons []string) { - if a != b { - reasons = append(reasons, notEqualStr("Float64 value", a, b)) - } - return reasons -} - -// equalInt64 returns reasons Int64s are not equal. If they are equal, the -// returned reasons will be empty. -func equalInt64(a, b metricdata.Int64) (reasons []string) { - if a != b { - reasons = append(reasons, notEqualStr("Int64 value", a, b)) - } - return reasons -} - func notEqualStr(prefix string, expected, actual interface{}) string { return fmt.Sprintf("%s not equal:\nexpected: %v\nactual: %v", prefix, expected, actual) } diff --git a/sdk/metric/pipeline_test.go b/sdk/metric/pipeline_test.go index 95a169f0054..74dce02db46 100644 --- a/sdk/metric/pipeline_test.go +++ b/sdk/metric/pipeline_test.go @@ -35,10 +35,10 @@ import ( type testSumAggregator struct{} func (testSumAggregator) Aggregation() metricdata.Aggregation { - return metricdata.Sum{ + return metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: false, - DataPoints: []metricdata.DataPoint{}} + DataPoints: []metricdata.DataPoint[int64]{}} } func TestEmptyPipeline(t *testing.T) {