Skip to content

Commit 25fac4c

Browse files
committed
add unit tests for the per-series starttime feature
1 parent 888d6e7 commit 25fac4c

File tree

10 files changed

+272
-100
lines changed

10 files changed

+272
-100
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1414
- Add service detection with `WithService` in `go.opentelemetry.io/otel/sdk/resource`. (#7642)
1515
- Support attributes with empty value (`attribute.EMPTY`) in OTLP exporters (`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`). (#8038)
1616
- Support attributes with empty value (`attribute.EMPTY`) in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8038)
17+
- Add support for per-series start time tracking for cumulative metrics in `go.opentelemetry.io/otel/sdk/metric`. Set `OTEL_GO_X_PER_SERIES_START_TIMESTAMPS=true` to enable. (#8060)
1718

1819
### Changed
1920

sdk/internal/x/features_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,3 @@ func TestPerSeriesStartTimestamps(t *testing.T) {
3030
t.Run("false", run(setenv(key, "false"), assertDisabled(PerSeriesStartTimestamps)))
3131
t.Run("empty", run(assertDisabled(PerSeriesStartTimestamps)))
3232
}
33-

sdk/metric/internal/aggregate/exponential_histogram.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,9 @@ func newExpoHistogramDataPoint[N int64 | float64](
5757
noSum: noSum,
5858
}
5959
dp.scale.Store(maxScale)
60-
dp.startTime = func() time.Time {
61-
if x.PerSeriesStartTimestamps.Enabled() {
62-
return now()
63-
}
64-
return time.Time{}
65-
}()
60+
if x.PerSeriesStartTimestamps.Enabled() {
61+
dp.startTime = now()
62+
}
6663
return dp
6764
}
6865

@@ -437,14 +434,14 @@ func (e *expoHistogram[N]) cumulative(
437434
n := len(e.values)
438435
hDPts := reset(h.DataPoints, n, n)
439436

440-
featureEnabled := x.PerSeriesStartTimestamps.Enabled()
437+
perSeriesStartTimeEnabled := x.PerSeriesStartTimestamps.Enabled()
441438

442439
var i int
443440
for _, val := range e.values {
444441
hDPts[i].Attributes = val.attrs
445442

446443
startTime := e.start
447-
if featureEnabled {
444+
if perSeriesStartTimeEnabled {
448445
startTime = val.startTime
449446
}
450447
hDPts[i].StartTime = startTime

sdk/metric/internal/aggregate/exponential_histogram_test.go

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -735,10 +735,29 @@ func TestExponentialHistogramAggregation(t *testing.T) {
735735
t.Run("Float64/Delta", testDeltaExpoHist[float64]())
736736
c.Reset()
737737

738-
t.Run("Int64/Cumulative", testCumulativeExpoHist[int64]())
738+
t.Run("Int64/Cumulative", func(t *testing.T) {
739+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
740+
testCumulativeExpoHist[int64](false)(t)
741+
})
739742
c.Reset()
740743

741-
t.Run("Float64/Cumulative", testCumulativeExpoHist[float64]())
744+
t.Run("Int64/Cumulative/PerSeriesStartTimeEnabled", func(t *testing.T) {
745+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
746+
testCumulativeExpoHist[int64](true)(t)
747+
})
748+
c.Reset()
749+
750+
t.Run("Float64/Cumulative", func(t *testing.T) {
751+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
752+
testCumulativeExpoHist[float64](false)(t)
753+
})
754+
c.Reset()
755+
756+
t.Run("Float64/Cumulative/PerSeriesStartTimeEnabled", func(t *testing.T) {
757+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
758+
testCumulativeExpoHist[float64](true)(t)
759+
})
760+
c.Reset()
742761
}
743762

744763
func testDeltaExpoHist[N int64 | float64]() func(t *testing.T) {
@@ -868,12 +887,31 @@ func testDeltaExpoHist[N int64 | float64]() func(t *testing.T) {
868887
})
869888
}
870889

871-
func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
890+
func testCumulativeExpoHist[N int64 | float64](perSeriesStartTimeEnabled bool) func(t *testing.T) {
872891
in, out := Builder[N]{
873892
Temporality: metricdata.CumulativeTemporality,
874893
Filter: attrFltr,
875894
AggregationLimit: 2,
876895
}.ExponentialBucketHistogram(4, 20, false, false)
896+
897+
aliceStartTime := y2kPlus(0)
898+
overflowStartTime := y2kPlus(0)
899+
900+
timeStep1 := y2kPlus(2)
901+
timeStep2 := y2kPlus(3)
902+
timeStep3 := y2kPlus(4)
903+
timeStep4 := y2kPlus(5)
904+
905+
if perSeriesStartTimeEnabled {
906+
aliceStartTime = y2kPlus(2)
907+
overflowStartTime = y2kPlus(6)
908+
909+
timeStep1 = y2kPlus(3)
910+
timeStep2 = y2kPlus(4)
911+
timeStep3 = y2kPlus(5)
912+
timeStep4 = y2kPlus(7)
913+
}
914+
877915
ctx := context.Background()
878916
return test[N](in, out, []teststep[N]{
879917
{
@@ -903,8 +941,8 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
903941
DataPoints: []metricdata.ExponentialHistogramDataPoint[N]{
904942
{
905943
Attributes: fltrAlice,
906-
StartTime: y2kPlus(0),
907-
Time: y2kPlus(2),
944+
StartTime: aliceStartTime,
945+
Time: timeStep1,
908946
Count: 7,
909947
Min: metricdata.NewExtrema[N](-1),
910948
Max: metricdata.NewExtrema[N](16),
@@ -936,8 +974,8 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
936974
DataPoints: []metricdata.ExponentialHistogramDataPoint[N]{
937975
{
938976
Attributes: fltrAlice,
939-
StartTime: y2kPlus(0),
940-
Time: y2kPlus(3),
977+
StartTime: aliceStartTime,
978+
Time: timeStep2,
941979
Count: 10,
942980
Min: metricdata.NewExtrema[N](-1),
943981
Max: metricdata.NewExtrema[N](16),
@@ -965,8 +1003,8 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
9651003
DataPoints: []metricdata.ExponentialHistogramDataPoint[N]{
9661004
{
9671005
Attributes: fltrAlice,
968-
StartTime: y2kPlus(0),
969-
Time: y2kPlus(4),
1006+
StartTime: aliceStartTime,
1007+
Time: timeStep3,
9701008
Count: 10,
9711009
Min: metricdata.NewExtrema[N](-1),
9721010
Max: metricdata.NewExtrema[N](16),
@@ -1002,8 +1040,8 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
10021040
DataPoints: []metricdata.ExponentialHistogramDataPoint[N]{
10031041
{
10041042
Attributes: fltrAlice,
1005-
StartTime: y2kPlus(0),
1006-
Time: y2kPlus(5),
1043+
StartTime: aliceStartTime,
1044+
Time: timeStep4,
10071045
Count: 10,
10081046
Min: metricdata.NewExtrema[N](-1),
10091047
Max: metricdata.NewExtrema[N](16),
@@ -1020,8 +1058,8 @@ func testCumulativeExpoHist[N int64 | float64]() func(t *testing.T) {
10201058
},
10211059
{
10221060
Attributes: overflowSet,
1023-
StartTime: y2kPlus(0),
1024-
Time: y2kPlus(5),
1061+
StartTime: overflowStartTime,
1062+
Time: timeStep4,
10251063
Count: 6,
10261064
Min: metricdata.NewExtrema[N](1),
10271065
Max: metricdata.NewExtrema[N](16),

sdk/metric/internal/aggregate/histogram.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ func (s *cumulativeHistogram[N]) measure(
282282
droppedAttr []attribute.KeyValue,
283283
) {
284284
h := s.values.LoadOrStoreAttr(fltrAttr, func(attr attribute.Set) any {
285+
var startTime time.Time
286+
if x.PerSeriesStartTimestamps.Enabled() {
287+
startTime = now()
288+
}
285289
hPt := &hotColdHistogramPoint[N]{
286290
res: s.newRes(attr),
287291
attrs: attr,
@@ -300,12 +304,7 @@ func (s *cumulativeHistogram[N]) measure(
300304
counts: make([]atomic.Uint64, len(s.bounds)+1),
301305
},
302306
},
303-
startTime: func() time.Time {
304-
if x.PerSeriesStartTimestamps.Enabled() {
305-
return now()
306-
}
307-
return time.Time{}
308-
}(),
307+
startTime: startTime,
309308
}
310309
return hPt
311310
}).(*hotColdHistogramPoint[N])
@@ -347,14 +346,14 @@ func (s *cumulativeHistogram[N]) collect(
347346
// current length for capacity.
348347
hDPts := reset(h.DataPoints, 0, s.values.Len())
349348

350-
featureEnabled := x.PerSeriesStartTimestamps.Enabled()
349+
perSeriesStartTimeEnabled := x.PerSeriesStartTimestamps.Enabled()
351350

352351
var i int
353352
s.values.Range(func(_, value any) bool {
354353
val := value.(*hotColdHistogramPoint[N])
355354

356355
startTime := s.start
357-
if featureEnabled {
356+
if perSeriesStartTimeEnabled {
358357
startTime = val.startTime
359358
}
360359
// swap, observe, and clear the point

sdk/metric/internal/aggregate/histogram_test.go

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,59 @@ func TestHistogram(t *testing.T) {
3535
t.Run("Float64/Delta/NoSum", testDeltaHist[float64](conf[float64]{noSum: true, hPt: hPoint[float64]}))
3636
c.Reset()
3737

38-
t.Run("Int64/Cumulative/Sum", testCumulativeHist[int64](conf[int64]{hPt: hPointSummed[int64]}))
38+
t.Run("Int64/Cumulative/Sum", func(t *testing.T) {
39+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
40+
testCumulativeHist[int64](conf[int64]{hPt: hPointSummed[int64], perSeriesStartTimeEnabled: false})(t)
41+
})
42+
c.Reset()
43+
44+
t.Run("Int64/Cumulative/Sum/PerSeriesStartTimeEnabled", func(t *testing.T) {
45+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
46+
testCumulativeHist[int64](conf[int64]{hPt: hPointSummed[int64], perSeriesStartTimeEnabled: true})(t)
47+
})
48+
c.Reset()
49+
50+
t.Run("Int64/Cumulative/NoSum", func(t *testing.T) {
51+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
52+
testCumulativeHist[int64](conf[int64]{noSum: true, hPt: hPoint[int64], perSeriesStartTimeEnabled: false})(t)
53+
})
54+
c.Reset()
55+
56+
t.Run("Int64/Cumulative/NoSum/PerSeriesStartTimeEnabled", func(t *testing.T) {
57+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
58+
testCumulativeHist[int64](conf[int64]{noSum: true, hPt: hPoint[int64], perSeriesStartTimeEnabled: true})(t)
59+
})
60+
c.Reset()
61+
62+
t.Run("Float64/Cumulative/Sum", func(t *testing.T) {
63+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
64+
testCumulativeHist[float64](conf[float64]{hPt: hPointSummed[float64], perSeriesStartTimeEnabled: false})(t)
65+
})
3966
c.Reset()
40-
t.Run("Int64/Cumulative/NoSum", testCumulativeHist[int64](conf[int64]{noSum: true, hPt: hPoint[int64]}))
67+
68+
t.Run("Float64/Cumulative/Sum/PerSeriesStartTimeEnabled", func(t *testing.T) {
69+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
70+
testCumulativeHist[float64](conf[float64]{hPt: hPointSummed[float64], perSeriesStartTimeEnabled: true})(t)
71+
})
4172
c.Reset()
42-
t.Run("Float64/Cumulative/Sum", testCumulativeHist[float64](conf[float64]{hPt: hPointSummed[float64]}))
73+
74+
t.Run("Float64/Cumulative/NoSum", func(t *testing.T) {
75+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "false")
76+
testCumulativeHist[float64](conf[float64]{noSum: true, hPt: hPoint[float64], perSeriesStartTimeEnabled: false})(t)
77+
})
78+
c.Reset()
79+
80+
t.Run("Float64/Cumulative/NoSum/PerSeriesStartTimeEnabled", func(t *testing.T) {
81+
t.Setenv("OTEL_GO_X_PER_SERIES_START_TIMESTAMPS", "true")
82+
testCumulativeHist[float64](conf[float64]{noSum: true, hPt: hPoint[float64], perSeriesStartTimeEnabled: true})(t)
83+
})
4384
c.Reset()
44-
t.Run("Float64/Cumulative/NoSum", testCumulativeHist[float64](conf[float64]{noSum: true, hPt: hPoint[float64]}))
4585
}
4686

4787
type conf[N int64 | float64] struct {
48-
noSum bool
49-
hPt func(attribute.Set, N, uint64, time.Time, time.Time) metricdata.HistogramDataPoint[N]
88+
noSum bool
89+
hPt func(attribute.Set, N, uint64, time.Time, time.Time) metricdata.HistogramDataPoint[N]
90+
perSeriesStartTimeEnabled bool
5091
}
5192

5293
func testDeltaHist[N int64 | float64](c conf[N]) func(t *testing.T) {
@@ -142,6 +183,27 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
142183
Filter: attrFltr,
143184
AggregationLimit: 3,
144185
}.ExplicitBucketHistogram(bounds, noMinMax, c.noSum)
186+
187+
aliceStartTime := y2kPlus(0)
188+
bobStartTime := y2kPlus(0)
189+
overflowStartTime := y2kPlus(0)
190+
191+
timeStep1 := y2kPlus(2)
192+
timeStep2 := y2kPlus(3)
193+
timeStep3 := y2kPlus(4)
194+
timeStep4 := y2kPlus(5)
195+
196+
if c.perSeriesStartTimeEnabled {
197+
aliceStartTime = y2kPlus(2)
198+
bobStartTime = y2kPlus(3)
199+
overflowStartTime = y2kPlus(7)
200+
201+
timeStep1 = y2kPlus(4)
202+
timeStep2 = y2kPlus(5)
203+
timeStep3 = y2kPlus(6)
204+
timeStep4 = y2kPlus(8)
205+
}
206+
145207
ctx := context.Background()
146208
return test[N](in, out, []teststep[N]{
147209
{
@@ -167,8 +229,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
167229
agg: metricdata.Histogram[N]{
168230
Temporality: metricdata.CumulativeTemporality,
169231
DataPoints: []metricdata.HistogramDataPoint[N]{
170-
c.hPt(fltrAlice, 2, 3, y2kPlus(0), y2kPlus(2)),
171-
c.hPt(fltrBob, 10, 2, y2kPlus(0), y2kPlus(2)),
232+
c.hPt(fltrAlice, 2, 3, aliceStartTime, timeStep1),
233+
c.hPt(fltrBob, 10, 2, bobStartTime, timeStep1),
172234
},
173235
},
174236
},
@@ -183,8 +245,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
183245
agg: metricdata.Histogram[N]{
184246
Temporality: metricdata.CumulativeTemporality,
185247
DataPoints: []metricdata.HistogramDataPoint[N]{
186-
c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(3)),
187-
c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(3)),
248+
c.hPt(fltrAlice, 2, 4, aliceStartTime, timeStep2),
249+
c.hPt(fltrBob, 10, 3, bobStartTime, timeStep2),
188250
},
189251
},
190252
},
@@ -196,8 +258,8 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
196258
agg: metricdata.Histogram[N]{
197259
Temporality: metricdata.CumulativeTemporality,
198260
DataPoints: []metricdata.HistogramDataPoint[N]{
199-
c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(4)),
200-
c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(4)),
261+
c.hPt(fltrAlice, 2, 4, aliceStartTime, timeStep3),
262+
c.hPt(fltrBob, 10, 3, bobStartTime, timeStep3),
201263
},
202264
},
203265
},
@@ -213,9 +275,9 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
213275
agg: metricdata.Histogram[N]{
214276
Temporality: metricdata.CumulativeTemporality,
215277
DataPoints: []metricdata.HistogramDataPoint[N]{
216-
c.hPt(fltrAlice, 2, 4, y2kPlus(0), y2kPlus(5)),
217-
c.hPt(fltrBob, 10, 3, y2kPlus(0), y2kPlus(5)),
218-
c.hPt(overflowSet, 1, 2, y2kPlus(0), y2kPlus(5)),
278+
c.hPt(fltrAlice, 2, 4, aliceStartTime, timeStep4),
279+
c.hPt(fltrBob, 10, 3, bobStartTime, timeStep4),
280+
c.hPt(overflowSet, 1, 2, overflowStartTime, timeStep4),
219281
},
220282
},
221283
},

sdk/metric/internal/aggregate/lastvalue.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,14 @@ func (s *lastValueMap[N]) measure(
3333
droppedAttr []attribute.KeyValue,
3434
) {
3535
lv := s.values.LoadOrStoreAttr(fltrAttr, func(attr attribute.Set) any {
36+
var startTime time.Time
37+
if x.PerSeriesStartTimestamps.Enabled() {
38+
startTime = now()
39+
}
3640
return &lastValuePoint[N]{
3741
res: s.newRes(attr),
3842
attrs: attr,
39-
startTime: func() time.Time {
40-
if x.PerSeriesStartTimestamps.Enabled() {
41-
return now()
42-
}
43-
return time.Time{}
44-
}(),
43+
startTime: startTime,
4544
}
4645
}).(*lastValuePoint[N])
4746

@@ -164,14 +163,14 @@ func (s *cumulativeLastValue[N]) collect(
164163
// current length for capacity.
165164
dPts := reset(gData.DataPoints, 0, s.values.Len())
166165

167-
featureEnabled := x.PerSeriesStartTimestamps.Enabled()
166+
perSeriesStartTimeEnabled := x.PerSeriesStartTimestamps.Enabled()
168167

169168
var i int
170169
s.values.Range(func(_, value any) bool {
171170
v := value.(*lastValuePoint[N])
172171

173172
startTime := s.start
174-
if featureEnabled {
173+
if perSeriesStartTimeEnabled {
175174
startTime = v.startTime
176175
}
177176
newPt := metricdata.DataPoint[N]{

0 commit comments

Comments
 (0)