diff --git a/CHANGELOG.md b/CHANGELOG.md index 41609fae5f5a..d6bd67a539b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/sdk/resource`. (#5490) - Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/sdk/trace`. (#5490) - Use non-generic functions in the `Start` method of `"go.opentelemetry.io/otel/sdk/trace".Trace` to reduce memory allocation. (#5497) +- Improve performance of metric instruments in `go.opentelemetry.io/otel/sdk/metric` by removing unnecessary calls to time.Now. (#5545) ### Fixed diff --git a/sdk/metric/internal/aggregate/exemplar.go b/sdk/metric/internal/aggregate/exemplar.go index 170ae8e58e2a..f0c3fbfe6f3d 100644 --- a/sdk/metric/internal/aggregate/exemplar.go +++ b/sdk/metric/internal/aggregate/exemplar.go @@ -5,14 +5,18 @@ package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggreg import ( "sync" + "time" "go.opentelemetry.io/otel/sdk/metric/internal/exemplar" "go.opentelemetry.io/otel/sdk/metric/metricdata" ) -var exemplarPool = sync.Pool{ - New: func() any { return new([]exemplar.Exemplar) }, -} +var ( + zeroTime time.Time + exemplarPool = sync.Pool{ + New: func() any { return new([]exemplar.Exemplar) }, + } +) func collectExemplars[N int64 | float64](out *[]metricdata.Exemplar[N], f func(*[]exemplar.Exemplar)) { dest := exemplarPool.Get().(*[]exemplar.Exemplar) diff --git a/sdk/metric/internal/aggregate/exponential_histogram.go b/sdk/metric/internal/aggregate/exponential_histogram.go index 902074b5bfdc..6251796ea351 100644 --- a/sdk/metric/internal/aggregate/exponential_histogram.go +++ b/sdk/metric/internal/aggregate/exponential_histogram.go @@ -319,8 +319,6 @@ func (e *expoHistogram[N]) measure(ctx context.Context, value N, fltrAttr attrib return } - t := now() - e.valuesMu.Lock() defer e.valuesMu.Unlock() @@ -333,7 +331,7 @@ func (e *expoHistogram[N]) measure(ctx context.Context, value N, fltrAttr attrib e.values[attr.Equivalent()] = v } v.record(value) - v.res.Offer(ctx, t, exemplar.NewValue(value), droppedAttr) + v.res.Offer(ctx, zeroTime, exemplar.NewValue(value), droppedAttr) } func (e *expoHistogram[N]) delta(dest *metricdata.Aggregation) int { diff --git a/sdk/metric/internal/aggregate/exponential_histogram_test.go b/sdk/metric/internal/aggregate/exponential_histogram_test.go index 2ffd3ebf0bfc..8af8589d3a63 100644 --- a/sdk/metric/internal/aggregate/exponential_histogram_test.go +++ b/sdk/metric/internal/aggregate/exponential_histogram_test.go @@ -778,7 +778,7 @@ func testDeltaExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(1), - Time: y2kPlus(9), + Time: y2kPlus(2), Count: 7, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -832,8 +832,8 @@ func testDeltaExpoHist[N int64 | float64]() func(t *testing.T) { DataPoints: []metricdata.ExponentialHistogramDataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(10), - Time: y2kPlus(24), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Count: 7, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -850,8 +850,8 @@ func testDeltaExpoHist[N int64 | float64]() func(t *testing.T) { }, { Attributes: overflowSet, - StartTime: y2kPlus(10), - Time: y2kPlus(24), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Count: 6, Min: metricdata.NewExtrema[N](1), Max: metricdata.NewExtrema[N](16), @@ -905,7 +905,7 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(9), + Time: y2kPlus(2), Count: 7, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -938,7 +938,7 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(13), + Time: y2kPlus(3), Count: 10, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -967,7 +967,7 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(14), + Time: y2kPlus(4), Count: 10, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -1004,7 +1004,7 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(21), + Time: y2kPlus(5), Count: 10, Min: metricdata.NewExtrema[N](-1), Max: metricdata.NewExtrema[N](16), @@ -1022,7 +1022,7 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) { { Attributes: overflowSet, StartTime: y2kPlus(0), - Time: y2kPlus(21), + Time: y2kPlus(5), Count: 6, Min: metricdata.NewExtrema[N](1), Max: metricdata.NewExtrema[N](16), diff --git a/sdk/metric/internal/aggregate/histogram.go b/sdk/metric/internal/aggregate/histogram.go index 213baf50f53a..f2377c511059 100644 --- a/sdk/metric/internal/aggregate/histogram.go +++ b/sdk/metric/internal/aggregate/histogram.go @@ -80,8 +80,6 @@ func (s *histValues[N]) measure(ctx context.Context, value N, fltrAttr attribute // (s.bounds[len(s.bounds)-1], +∞). idx := sort.SearchFloat64s(s.bounds, float64(value)) - t := now() - s.valuesMu.Lock() defer s.valuesMu.Unlock() @@ -106,7 +104,7 @@ func (s *histValues[N]) measure(ctx context.Context, value N, fltrAttr attribute if !s.noSum { b.sum(value) } - b.res.Offer(ctx, t, exemplar.NewValue(value), droppedAttr) + b.res.Offer(ctx, zeroTime, exemplar.NewValue(value), droppedAttr) } // newHistogram returns an Aggregator that summarizes a set of measurements as diff --git a/sdk/metric/internal/aggregate/histogram_test.go b/sdk/metric/internal/aggregate/histogram_test.go index 38ba1229eb29..cc9772da0d92 100644 --- a/sdk/metric/internal/aggregate/histogram_test.go +++ b/sdk/metric/internal/aggregate/histogram_test.go @@ -80,8 +80,8 @@ func testDeltaHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.DeltaTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 2, 3, y2kPlus(1), y2kPlus(7)), - c.hPt(fltrBob, 10, 2, y2kPlus(1), y2kPlus(7)), + c.hPt(fltrAlice, 2, 3, y2kPlus(1), y2kPlus(2)), + c.hPt(fltrBob, 10, 2, y2kPlus(1), y2kPlus(2)), }, }, }, @@ -96,8 +96,8 @@ func testDeltaHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.DeltaTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 10, 1, y2kPlus(7), y2kPlus(10)), - c.hPt(fltrBob, 3, 1, y2kPlus(7), y2kPlus(10)), + c.hPt(fltrAlice, 10, 1, y2kPlus(2), y2kPlus(3)), + c.hPt(fltrBob, 3, 1, y2kPlus(2), y2kPlus(3)), }, }, }, @@ -126,9 +126,9 @@ func testDeltaHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.DeltaTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 1, 1, y2kPlus(11), y2kPlus(16)), - c.hPt(fltrBob, 1, 1, y2kPlus(11), y2kPlus(16)), - c.hPt(overflowSet, 1, 2, y2kPlus(11), y2kPlus(16)), + c.hPt(fltrAlice, 1, 1, y2kPlus(4), y2kPlus(5)), + c.hPt(fltrBob, 1, 1, y2kPlus(4), y2kPlus(5)), + c.hPt(overflowSet, 1, 2, y2kPlus(4), y2kPlus(5)), }, }, }, @@ -167,8 +167,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.CumulativeTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 2, 3, y2kPlus(0), y2kPlus(7)), - c.hPt(fltrBob, 10, 2, y2kPlus(0), y2kPlus(7)), + c.hPt(fltrAlice, 2, 3, y2kPlus(0), y2kPlus(2)), + c.hPt(fltrBob, 10, 2, y2kPlus(0), y2kPlus(2)), }, }, }, @@ -183,8 +183,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.CumulativeTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(10)), - c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(10)), + c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(3)), + c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(3)), }, }, }, @@ -196,8 +196,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.CumulativeTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(11)), - c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(11)), + c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(4)), + c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(4)), }, }, }, @@ -213,9 +213,9 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) { agg: metricdata.Histogram[N]{ Temporality: metricdata.CumulativeTemporality, DataPoints: []metricdata.HistogramDataPoint[N]{ - c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(14)), - c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(14)), - c.hPt(overflowSet, 1, 2, y2kPlus(0), y2kPlus(14)), + c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(5)), + c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(5)), + c.hPt(overflowSet, 1, 2, y2kPlus(0), y2kPlus(5)), }, }, }, diff --git a/sdk/metric/internal/aggregate/lastvalue.go b/sdk/metric/internal/aggregate/lastvalue.go index 3b65e761e862..176d73026439 100644 --- a/sdk/metric/internal/aggregate/lastvalue.go +++ b/sdk/metric/internal/aggregate/lastvalue.go @@ -40,8 +40,6 @@ type lastValue[N int64 | float64] struct { } func (s *lastValue[N]) measure(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) { - t := now() - s.Lock() defer s.Unlock() @@ -53,7 +51,7 @@ func (s *lastValue[N]) measure(ctx context.Context, value N, fltrAttr attribute. d.attrs = attr d.value = value - d.res.Offer(ctx, t, exemplar.NewValue(value), droppedAttr) + d.res.Offer(ctx, zeroTime, exemplar.NewValue(value), droppedAttr) s.values[attr.Equivalent()] = d } diff --git a/sdk/metric/internal/aggregate/lastvalue_test.go b/sdk/metric/internal/aggregate/lastvalue_test.go index 1e4ca21c96ad..77e0d283ba0f 100644 --- a/sdk/metric/internal/aggregate/lastvalue_test.go +++ b/sdk/metric/internal/aggregate/lastvalue_test.go @@ -61,13 +61,13 @@ func testDeltaLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 2, }, { Attributes: fltrBob, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -10, }, }, @@ -88,14 +88,14 @@ func testDeltaLastValue[N int64 | float64]() func(*testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(8), - Time: y2kPlus(11), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Value: 10, }, { Attributes: fltrBob, - StartTime: y2kPlus(8), - Time: y2kPlus(11), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Value: 3, }, }, @@ -115,20 +115,20 @@ func testDeltaLastValue[N int64 | float64]() func(*testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, }, @@ -165,13 +165,13 @@ func testCumulativeLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 2, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -10, }, }, @@ -187,13 +187,13 @@ func testCumulativeLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(8), + Time: y2kPlus(3), Value: 2, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(8), + Time: y2kPlus(3), Value: -10, }, }, @@ -211,13 +211,13 @@ func testCumulativeLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(4), Value: 10, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(4), Value: 3, }, }, @@ -238,19 +238,19 @@ func testCumulativeLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, }, @@ -287,13 +287,13 @@ func testDeltaPrecomputedLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 2, }, { Attributes: fltrBob, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -10, }, }, @@ -314,14 +314,14 @@ func testDeltaPrecomputedLastValue[N int64 | float64]() func(*testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(8), - Time: y2kPlus(11), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Value: 10, }, { Attributes: fltrBob, - StartTime: y2kPlus(8), - Time: y2kPlus(11), + StartTime: y2kPlus(3), + Time: y2kPlus(4), Value: 3, }, }, @@ -341,20 +341,20 @@ func testDeltaPrecomputedLastValue[N int64 | float64]() func(*testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, }, @@ -391,13 +391,13 @@ func testCumulativePrecomputedLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 2, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -10, }, }, @@ -419,13 +419,13 @@ func testCumulativePrecomputedLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(4), Value: 10, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(4), Value: 3, }, }, @@ -446,19 +446,19 @@ func testCumulativePrecomputedLastValue[N int64 | float64]() func(*testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, StartTime: y2kPlus(0), - Time: y2kPlus(16), + Time: y2kPlus(5), Value: 1, }, }, diff --git a/sdk/metric/internal/aggregate/sum.go b/sdk/metric/internal/aggregate/sum.go index babe76aba9b7..58d0938e5694 100644 --- a/sdk/metric/internal/aggregate/sum.go +++ b/sdk/metric/internal/aggregate/sum.go @@ -36,8 +36,6 @@ func newValueMap[N int64 | float64](limit int, r func() exemplar.Reservoir) *val } func (s *valueMap[N]) measure(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) { - t := now() - s.Lock() defer s.Unlock() @@ -49,7 +47,7 @@ func (s *valueMap[N]) measure(ctx context.Context, value N, fltrAttr attribute.S v.attrs = attr v.n += value - v.res.Offer(ctx, t, exemplar.NewValue(value), droppedAttr) + v.res.Offer(ctx, zeroTime, exemplar.NewValue(value), droppedAttr) s.values[attr.Equivalent()] = v } diff --git a/sdk/metric/internal/aggregate/sum_test.go b/sdk/metric/internal/aggregate/sum_test.go index c20adaed500b..bb825e183757 100644 --- a/sdk/metric/internal/aggregate/sum_test.go +++ b/sdk/metric/internal/aggregate/sum_test.go @@ -75,13 +75,13 @@ func testDeltaSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 4, }, { Attributes: fltrBob, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -11, }, }, @@ -101,14 +101,14 @@ func testDeltaSum[N int64 | float64]() func(t *testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(7), - Time: y2kPlus(10), + StartTime: y2kPlus(2), + Time: y2kPlus(3), Value: 10, }, { Attributes: fltrBob, - StartTime: y2kPlus(7), - Time: y2kPlus(10), + StartTime: y2kPlus(2), + Time: y2kPlus(3), Value: 3, }, }, @@ -143,20 +143,20 @@ func testDeltaSum[N int64 | float64]() func(t *testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, - StartTime: y2kPlus(11), - Time: y2kPlus(16), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 2, }, }, @@ -203,13 +203,13 @@ func testCumulativeSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 4, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -11, }, }, @@ -230,13 +230,13 @@ func testCumulativeSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(10), + Time: y2kPlus(3), Value: 14, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(10), + Time: y2kPlus(3), Value: -8, }, }, @@ -258,19 +258,19 @@ func testCumulativeSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(13), + Time: y2kPlus(4), Value: 14, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(13), + Time: y2kPlus(4), Value: -8, }, { Attributes: overflowSet, StartTime: y2kPlus(0), - Time: y2kPlus(13), + Time: y2kPlus(4), Value: 2, }, }, @@ -317,13 +317,13 @@ func testDeltaPrecomputedSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 4, }, { Attributes: fltrBob, StartTime: y2kPlus(1), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -11, }, }, @@ -344,14 +344,14 @@ func testDeltaPrecomputedSum[N int64 | float64]() func(t *testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(7), - Time: y2kPlus(11), + StartTime: y2kPlus(2), + Time: y2kPlus(3), Value: 7, }, { Attributes: fltrBob, - StartTime: y2kPlus(7), - Time: y2kPlus(11), + StartTime: y2kPlus(2), + Time: y2kPlus(3), Value: 14, }, }, @@ -386,20 +386,20 @@ func testDeltaPrecomputedSum[N int64 | float64]() func(t *testing.T) { DataPoints: []metricdata.DataPoint[N]{ { Attributes: fltrAlice, - StartTime: y2kPlus(12), - Time: y2kPlus(17), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, - StartTime: y2kPlus(12), - Time: y2kPlus(17), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, - StartTime: y2kPlus(12), - Time: y2kPlus(17), + StartTime: y2kPlus(4), + Time: y2kPlus(5), Value: 2, }, }, @@ -446,13 +446,13 @@ func testCumulativePrecomputedSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: 4, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(7), + Time: y2kPlus(2), Value: -11, }, }, @@ -474,13 +474,13 @@ func testCumulativePrecomputedSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(3), Value: 11, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(11), + Time: y2kPlus(3), Value: 3, }, }, @@ -516,19 +516,19 @@ func testCumulativePrecomputedSum[N int64 | float64]() func(t *testing.T) { { Attributes: fltrAlice, StartTime: y2kPlus(0), - Time: y2kPlus(17), + Time: y2kPlus(5), Value: 1, }, { Attributes: fltrBob, StartTime: y2kPlus(0), - Time: y2kPlus(17), + Time: y2kPlus(5), Value: 1, }, { Attributes: overflowSet, StartTime: y2kPlus(0), - Time: y2kPlus(17), + Time: y2kPlus(5), Value: 2, }, }, diff --git a/sdk/metric/internal/exemplar/hist.go b/sdk/metric/internal/exemplar/hist.go index a6ff86d02714..b968413b4aff 100644 --- a/sdk/metric/internal/exemplar/hist.go +++ b/sdk/metric/internal/exemplar/hist.go @@ -42,5 +42,8 @@ func (r *histRes) Offer(ctx context.Context, t time.Time, v Value, a []attribute default: panic("unknown value type") } + if t.IsZero() { + t = now() + } r.store[sort.SearchFloat64s(r.bounds, x)] = newMeasurement(ctx, t, v, a) } diff --git a/sdk/metric/internal/exemplar/rand.go b/sdk/metric/internal/exemplar/rand.go index 199a2608f718..4effda9cb024 100644 --- a/sdk/metric/internal/exemplar/rand.go +++ b/sdk/metric/internal/exemplar/rand.go @@ -118,6 +118,9 @@ func (r *randRes) Offer(ctx context.Context, t time.Time, n Value, a []attribute // https://github.com/MrAlias/reservoir-sampling for a performance // comparison of reservoir sampling algorithms. + if t.IsZero() { + t = now() + } if int(r.count) < cap(r.store) { r.store[r.count] = newMeasurement(ctx, t, n, a) } else { diff --git a/sdk/metric/internal/exemplar/reservoir.go b/sdk/metric/internal/exemplar/reservoir.go index 80fa59554f20..bf679d967d47 100644 --- a/sdk/metric/internal/exemplar/reservoir.go +++ b/sdk/metric/internal/exemplar/reservoir.go @@ -10,6 +10,16 @@ import ( "go.opentelemetry.io/otel/attribute" ) +var ( + // now is used to return the current local time while allowing tests to + // override the default time.Now function. + now = time.Now + + // zeroTime is an unset time.Time. If Offer'd to a reservoir, the reservoir + // will use the current time for the observation instead. + zeroTime time.Time +) + // Reservoir holds the sampled exemplar of measurements made. type Reservoir interface { // Offer accepts the parameters associated with a measurement. The @@ -20,7 +30,8 @@ type Reservoir interface { // when the measurement was made. This information may be used by the // Reservoir in making a sampling decision. // - // The time t is the time when the measurement was made. The val and attr + // The time t is the time when the measurement was made, or may be the + // zero time if the reservoir should use the current time. The val and attr // parameters are the value and dropped (filtered) attributes of the // measurement respectively. Offer(ctx context.Context, t time.Time, val Value, attr []attribute.KeyValue) diff --git a/sdk/metric/internal/exemplar/reservoir_test.go b/sdk/metric/internal/exemplar/reservoir_test.go index b5fc5453d421..2f83b048d35c 100644 --- a/sdk/metric/internal/exemplar/reservoir_test.go +++ b/sdk/metric/internal/exemplar/reservoir_test.go @@ -57,6 +57,41 @@ func ReservoirTest[N int64 | float64](f factory) func(*testing.T) { assert.Equal(t, want, dest[0]) }) + t.Run("CaptureSpanContext with zero time", func(t *testing.T) { + t.Helper() + // return staticTime from calls to now() during the test + now = func() time.Time { return staticTime } + defer func() { now = time.Now }() + + r, n := f(1) + if n < 1 { + t.Skip("skipping, reservoir capacity less than 1:", n) + } + + tID, sID := trace.TraceID{0x01}, trace.SpanID{0x01} + sc := trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: tID, + SpanID: sID, + TraceFlags: trace.FlagsSampled, + }) + ctx := trace.ContextWithSpanContext(ctx, sc) + + // pass a zero time to Offer + r.Offer(ctx, zeroTime, NewValue(N(10)), nil) + + var dest []Exemplar + r.Collect(&dest) + + want := Exemplar{ + Time: staticTime, + Value: NewValue(N(10)), + SpanID: sID[:], + TraceID: tID[:], + } + require.Len(t, dest, 1, "number of collected exemplars") + assert.Equal(t, want, dest[0]) + }) + t.Run("FilterAttributes", func(t *testing.T) { t.Helper()