Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Introduce the `EMPTY` Type in `go.opentelemetry.io/otel/attribute` to reflect that an empty value is now a valid value, with `INVALID` remaining as a deprecated alias of `EMPTY`. (#8038)
- Refactor slice handling in `go.opentelemetry.io/otel/attribute` to optimize short slice values with fixed-size fast paths. (#8039)
- Improve performance of span metric recording in `go.opentelemetry.io/otel/sdk/trace` by returning early if self-observability is not enabled. (#8067)
- Improve formatting of metric data diffs in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8073)

### Deprecated

Expand Down
178 changes: 107 additions & 71 deletions sdk/metric/metricdata/metricdatatest/comparisons.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"reflect"
"slices"
"strings"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
Expand All @@ -23,14 +24,16 @@ func equalResourceMetrics(a, b metricdata.ResourceMetrics, cfg config) (reasons
reasons = append(reasons, notEqualStr("Resources", a.Resource, b.Resource))
}

r := compareDiff(diffSlices(
r := diffSlices(
a.ScopeMetrics,
b.ScopeMetrics,
func(a, b metricdata.ScopeMetrics) bool {
r := equalScopeMetrics(a, b, cfg)
return len(r) == 0
func(sm metricdata.ScopeMetrics) string {
return fmt.Sprintf("Scope %q", sm.Scope.Name)
},
))
func(a, b metricdata.ScopeMetrics) []string {
return equalScopeMetrics(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "ResourceMetrics ScopeMetrics not equal:\n"+r)
}
Expand All @@ -47,14 +50,16 @@ func equalScopeMetrics(a, b metricdata.ScopeMetrics, cfg config) (reasons []stri
reasons = append(reasons, notEqualStr("Scope", a.Scope, b.Scope))
}

r := compareDiff(diffSlices(
r := diffSlices(
a.Metrics,
b.Metrics,
func(a, b metricdata.Metrics) bool {
r := equalMetrics(a, b, cfg)
return len(r) == 0
func(m metricdata.Metrics) string {
return fmt.Sprintf("Metric %q", m.Name)
},
func(a, b metricdata.Metrics) []string {
return equalMetrics(a, b, cfg)
},
))
)
if r != "" {
reasons = append(reasons, "ScopeMetrics Metrics not equal:\n"+r)
}
Expand Down Expand Up @@ -163,14 +168,16 @@ func equalAggregations(a, b metricdata.Aggregation, cfg config) (reasons []strin
// The DataPoints each Gauge contains are compared based on containing the
// same DataPoints, not the order they are stored in.
func equalGauges[N int64 | float64](a, b metricdata.Gauge[N], cfg config) (reasons []string) {
r := compareDiff(diffSlices(
r := diffSlices(
a.DataPoints,
b.DataPoints,
func(a, b metricdata.DataPoint[N]) bool {
r := equalDataPoints(a, b, cfg)
return len(r) == 0
func(dp metricdata.DataPoint[N]) string {
return fmt.Sprintf("DataPoint [%v]", dp.Attributes.Encoded(attribute.DefaultEncoder()))
},
))
func(a, b metricdata.DataPoint[N]) []string {
return equalDataPoints(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "Gauge DataPoints not equal:\n"+r)
}
Expand All @@ -190,14 +197,16 @@ func equalSums[N int64 | float64](a, b metricdata.Sum[N], cfg config) (reasons [
reasons = append(reasons, notEqualStr("IsMonotonic", a.IsMonotonic, b.IsMonotonic))
}

r := compareDiff(diffSlices(
r := diffSlices(
a.DataPoints,
b.DataPoints,
func(a, b metricdata.DataPoint[N]) bool {
r := equalDataPoints(a, b, cfg)
return len(r) == 0
func(dp metricdata.DataPoint[N]) string {
return fmt.Sprintf("DataPoint [%v]", dp.Attributes.Encoded(attribute.DefaultEncoder()))
},
func(a, b metricdata.DataPoint[N]) []string {
return equalDataPoints(a, b, cfg)
},
))
)
if r != "" {
reasons = append(reasons, "Sum DataPoints not equal:\n"+r)
}
Expand All @@ -214,14 +223,16 @@ func equalHistograms[N int64 | float64](a, b metricdata.Histogram[N], cfg config
reasons = append(reasons, notEqualStr("Temporality", a.Temporality, b.Temporality))
}

r := compareDiff(diffSlices(
r := diffSlices(
a.DataPoints,
b.DataPoints,
func(a, b metricdata.HistogramDataPoint[N]) bool {
r := equalHistogramDataPoints(a, b, cfg)
return len(r) == 0
func(dp metricdata.HistogramDataPoint[N]) string {
return fmt.Sprintf("HistogramDataPoint [%v]", dp.Attributes.Encoded(attribute.DefaultEncoder()))
},
))
func(a, b metricdata.HistogramDataPoint[N]) []string {
return equalHistogramDataPoints(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "Histogram DataPoints not equal:\n"+r)
}
Expand Down Expand Up @@ -258,14 +269,16 @@ func equalDataPoints[N int64 | float64](
}

if !cfg.ignoreExemplars {
r := compareDiff(diffSlices(
r := diffSlices(
a.Exemplars,
b.Exemplars,
func(a, b metricdata.Exemplar[N]) bool {
r := equalExemplars(a, b, cfg)
return len(r) == 0
func(_ metricdata.Exemplar[N]) string {
return "Exemplar"
},
))
func(a, b metricdata.Exemplar[N]) []string {
return equalExemplars(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "Exemplars not equal:\n"+r)
}
Expand Down Expand Up @@ -315,14 +328,16 @@ func equalHistogramDataPoints[N int64 | float64](
}
}
if !cfg.ignoreExemplars {
r := compareDiff(diffSlices(
r := diffSlices(
a.Exemplars,
b.Exemplars,
func(a, b metricdata.Exemplar[N]) bool {
r := equalExemplars(a, b, cfg)
return len(r) == 0
func(_ metricdata.Exemplar[N]) string {
return "Exemplar"
},
))
func(a, b metricdata.Exemplar[N]) []string {
return equalExemplars(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "Exemplars not equal:\n"+r)
}
Expand All @@ -343,14 +358,16 @@ func equalExponentialHistograms[N int64 | float64](
reasons = append(reasons, notEqualStr("Temporality", a.Temporality, b.Temporality))
}

r := compareDiff(diffSlices(
r := diffSlices(
a.DataPoints,
b.DataPoints,
func(a, b metricdata.ExponentialHistogramDataPoint[N]) bool {
r := equalExponentialHistogramDataPoints(a, b, cfg)
return len(r) == 0
func(dp metricdata.ExponentialHistogramDataPoint[N]) string {
return fmt.Sprintf("ExponentialHistogramDataPoint [%v]", dp.Attributes.Encoded(attribute.DefaultEncoder()))
},
func(a, b metricdata.ExponentialHistogramDataPoint[N]) []string {
return equalExponentialHistogramDataPoints(a, b, cfg)
},
))
)
if r != "" {
reasons = append(reasons, "Histogram DataPoints not equal:\n"+r)
}
Expand Down Expand Up @@ -409,14 +426,16 @@ func equalExponentialHistogramDataPoints[N int64 | float64](
}
}
if !cfg.ignoreExemplars {
r := compareDiff(diffSlices(
r := diffSlices(
a.Exemplars,
b.Exemplars,
func(a, b metricdata.Exemplar[N]) bool {
r := equalExemplars(a, b, cfg)
return len(r) == 0
func(_ metricdata.Exemplar[N]) string {
return "Exemplar"
},
))
func(a, b metricdata.Exemplar[N]) []string {
return equalExemplars(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, "Exemplars not equal:\n"+r)
}
Expand All @@ -435,14 +454,16 @@ func equalExponentialBuckets(a, b metricdata.ExponentialBucket, _ config) (reaso
}

func equalSummary(a, b metricdata.Summary, cfg config) (reasons []string) {
r := compareDiff(diffSlices(
r := diffSlices(
a.DataPoints,
b.DataPoints,
func(a, b metricdata.SummaryDataPoint) bool {
r := equalSummaryDataPoint(a, b, cfg)
return len(r) == 0
func(dp metricdata.SummaryDataPoint) string {
return fmt.Sprintf("SummaryDataPoint [%v]", dp.Attributes.Encoded(attribute.DefaultEncoder()))
},
func(a, b metricdata.SummaryDataPoint) []string {
return equalSummaryDataPoint(a, b, cfg)
},
))
)
if r != "" {
reasons = append(reasons, "Summary DataPoints not equal:\n"+r)
}
Expand Down Expand Up @@ -472,14 +493,16 @@ func equalSummaryDataPoint(a, b metricdata.SummaryDataPoint, cfg config) (reason
if a.Sum != b.Sum {
reasons = append(reasons, notEqualStr("Sum", a.Sum, b.Sum))
}
r := compareDiff(diffSlices(
r := diffSlices(
a.QuantileValues,
b.QuantileValues,
func(a, b metricdata.QuantileValue) bool {
r := equalQuantileValue(a, b, cfg)
return len(r) == 0
func(qv metricdata.QuantileValue) string {
return fmt.Sprintf("QuantileValue %v", qv.Quantile)
},
))
func(a, b metricdata.QuantileValue) []string {
return equalQuantileValue(a, b, cfg)
},
)
if r != "" {
reasons = append(reasons, r)
}
Expand Down Expand Up @@ -590,15 +613,18 @@ func equalExemplars[N int64 | float64](a, b metricdata.Exemplar[N], cfg config)
return reasons
}

func diffSlices[T any](a, b []T, equal func(T, T) bool) (extraA, extraB []T) {
func diffSlices[T any](a, b []T, formatContext func(T) string, compare func(T, T) []string) string {
visited := make([]bool, len(b))
var extraA []T
var extraB []T

for i := range a {
found := false
for j := range b {
if visited[j] {
continue
}
if equal(a[i], b[j]) {
if len(compare(a[i], b[j])) == 0 {
visited[j] = true
found = true
break
Expand All @@ -616,30 +642,40 @@ func diffSlices[T any](a, b []T, equal func(T, T) bool) (extraA, extraB []T) {
extraB = append(extraB, b[j])
}

return extraA, extraB
}

func compareDiff[T any](extraExpected, extraActual []T) string {
if len(extraExpected) == 0 && len(extraActual) == 0 {
if len(extraA) == 0 && len(extraB) == 0 {
return ""
}

var msg bytes.Buffer
minLen := min(len(extraB), len(extraA))

for i := range minLen {
reasons := compare(extraA[i], extraB[i])
_, _ = msg.WriteString(formatContext(extraA[i]) + ":\n")
for _, reason := range reasons {
// Indent reasons
lines := strings.SplitSeq(reason, "\n")
for line := range lines {
if line != "" {
_, _ = msg.WriteString("\t" + line + "\n")
}
}
}
}

formatter := func(v T) string {
return fmt.Sprintf("%#v", v)
}

var msg bytes.Buffer
if len(extraExpected) > 0 {
if len(extraA) > minLen {
_, _ = msg.WriteString("missing expected values:\n")
for _, v := range extraExpected {
_, _ = msg.WriteString(formatter(v) + "\n")
for i := minLen; i < len(extraA); i++ {
_, _ = msg.WriteString(formatter(extraA[i]) + "\n")
}
}

if len(extraActual) > 0 {
if len(extraB) > minLen {
_, _ = msg.WriteString("unexpected additional values:\n")
for _, v := range extraActual {
_, _ = msg.WriteString(formatter(v) + "\n")
for i := minLen; i < len(extraB); i++ {
_, _ = msg.WriteString(formatter(extraB[i]) + "\n")
}
}

Expand Down
Loading