Skip to content

Commit 385c4d4

Browse files
committed
Metric SDK: Remove distiction between filtered and unfiltered
attributes.
1 parent 55fb2bb commit 385c4d4

7 files changed

Lines changed: 58 additions & 294 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2929
The `AttributeKeys` fields allows users to specify an allow-list of attributes allowed to be recorded for a view.
3030
This change is made to ensure compatibility with the OpenTelemetry specification. (#4288)
3131
- If an attribute set is omitted from an async callback, the previous value will no longer be exported. (#4290)
32+
- If an attribute set is Observed multiple times in an async callback, the values will be summed instead of the last observation winning. (#4289)
3233

3334
### Fixed
3435

sdk/metric/internal/aggregate/aggregator.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,3 @@ type Aggregator[N int64 | float64] interface {
3838
// measurements made and ends an aggregation cycle.
3939
Aggregation() metricdata.Aggregation
4040
}
41-
42-
// precomputeAggregator is an Aggregator that receives values to aggregate that
43-
// have been pre-computed by the caller.
44-
type precomputeAggregator[N int64 | float64] interface {
45-
// The Aggregate method of the embedded Aggregator is used to record
46-
// pre-computed measurements, scoped by attributes that have not been
47-
// filtered by an attribute filter.
48-
Aggregator[N]
49-
50-
// aggregateFiltered records measurements scoped by attributes that have
51-
// been filtered by an attribute filter.
52-
//
53-
// Pre-computed measurements of filtered attributes need to be recorded
54-
// separate from those that haven't been filtered so they can be added to
55-
// the non-filtered pre-computed measurements in a collection cycle and
56-
// then resets after the cycle (the non-filtered pre-computed measurements
57-
// are not reset).
58-
aggregateFiltered(N, attribute.Set)
59-
}

sdk/metric/internal/aggregate/filter.go

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ func NewFilter[N int64 | float64](agg Aggregator[N], fn attribute.Filter) Aggreg
2727
if fn == nil {
2828
return agg
2929
}
30-
if fa, ok := agg.(precomputeAggregator[N]); ok {
31-
return newPrecomputedFilter(fa, fn)
32-
}
3330
return newFilter(agg, fn)
3431
}
3532

@@ -68,43 +65,3 @@ func (f *filter[N]) Aggregate(measurement N, attr attribute.Set) {
6865
func (f *filter[N]) Aggregation() metricdata.Aggregation {
6966
return f.aggregator.Aggregation()
7067
}
71-
72-
// precomputedFilter is an aggregator that applies attribute filter when
73-
// Aggregating for pre-computed Aggregations. The pre-computed Aggregations
74-
// need to operate normally when no attribute filtering is done (for sums this
75-
// means setting the value), but when attribute filtering is done it needs to
76-
// be added to any set value.
77-
type precomputedFilter[N int64 | float64] struct {
78-
filter attribute.Filter
79-
aggregator precomputeAggregator[N]
80-
}
81-
82-
// newPrecomputedFilter returns a precomputedFilter Aggregator that wraps agg
83-
// with the attribute filter fn.
84-
//
85-
// This should not be used to wrap a non-pre-computed Aggregator. Use a
86-
// precomputedFilter instead.
87-
func newPrecomputedFilter[N int64 | float64](agg precomputeAggregator[N], fn attribute.Filter) *precomputedFilter[N] {
88-
return &precomputedFilter[N]{
89-
filter: fn,
90-
aggregator: agg,
91-
}
92-
}
93-
94-
// Aggregate records the measurement, scoped by attr, and aggregates it
95-
// into an aggregation.
96-
func (f *precomputedFilter[N]) Aggregate(measurement N, attr attribute.Set) {
97-
fAttr, _ := attr.Filter(f.filter)
98-
if fAttr.Equals(&attr) {
99-
// No filtering done.
100-
f.aggregator.Aggregate(measurement, fAttr)
101-
} else {
102-
f.aggregator.aggregateFiltered(measurement, fAttr)
103-
}
104-
}
105-
106-
// Aggregation returns an Aggregation, for all the aggregated
107-
// measurements made and ends an aggregation cycle.
108-
func (f *precomputedFilter[N]) Aggregation() metricdata.Aggregation {
109-
return f.aggregator.Aggregation()
110-
}

sdk/metric/internal/aggregate/filter_test.go

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
1616

1717
import (
18-
"fmt"
19-
"strings"
2018
"sync"
2119
"testing"
2220

@@ -196,90 +194,3 @@ func TestFilterConcurrent(t *testing.T) {
196194
testFilterConcurrent[float64](t)
197195
})
198196
}
199-
200-
func TestPrecomputedFilter(t *testing.T) {
201-
t.Run("Int64", testPrecomputedFilter[int64]())
202-
t.Run("Float64", testPrecomputedFilter[float64]())
203-
}
204-
205-
func testPrecomputedFilter[N int64 | float64]() func(t *testing.T) {
206-
return func(t *testing.T) {
207-
agg := newTestFilterAgg[N]()
208-
f := NewFilter[N](agg, testAttributeFilter)
209-
require.IsType(t, &precomputedFilter[N]{}, f)
210-
211-
var (
212-
powerLevel = attribute.Int("power-level", 9000)
213-
user = attribute.String("user", "Alice")
214-
admin = attribute.Bool("admin", true)
215-
)
216-
a := attribute.NewSet(powerLevel)
217-
key := a
218-
f.Aggregate(1, a)
219-
assert.Equal(t, N(1), agg.values[key].measured, str(a))
220-
assert.Equal(t, N(0), agg.values[key].filtered, str(a))
221-
222-
a = attribute.NewSet(powerLevel, user)
223-
f.Aggregate(2, a)
224-
assert.Equal(t, N(1), agg.values[key].measured, str(a))
225-
assert.Equal(t, N(2), agg.values[key].filtered, str(a))
226-
227-
a = attribute.NewSet(powerLevel, user, admin)
228-
f.Aggregate(3, a)
229-
assert.Equal(t, N(1), agg.values[key].measured, str(a))
230-
assert.Equal(t, N(5), agg.values[key].filtered, str(a))
231-
232-
a = attribute.NewSet(powerLevel)
233-
f.Aggregate(2, a)
234-
assert.Equal(t, N(2), agg.values[key].measured, str(a))
235-
assert.Equal(t, N(5), agg.values[key].filtered, str(a))
236-
237-
a = attribute.NewSet(user)
238-
f.Aggregate(3, a)
239-
assert.Equal(t, N(2), agg.values[key].measured, str(a))
240-
assert.Equal(t, N(5), agg.values[key].filtered, str(a))
241-
assert.Equal(t, N(3), agg.values[*attribute.EmptySet()].filtered, str(a))
242-
243-
_ = f.Aggregation()
244-
assert.Equal(t, 1, agg.aggregationN, "failed to propagate Aggregation")
245-
}
246-
}
247-
248-
func str(a attribute.Set) string {
249-
iter := a.Iter()
250-
out := make([]string, 0, iter.Len())
251-
for iter.Next() {
252-
kv := iter.Attribute()
253-
out = append(out, fmt.Sprintf("%s:%#v", kv.Key, kv.Value.AsInterface()))
254-
}
255-
return strings.Join(out, ",")
256-
}
257-
258-
type testFilterAgg[N int64 | float64] struct {
259-
values map[attribute.Set]precomputedValue[N]
260-
aggregationN int
261-
}
262-
263-
func newTestFilterAgg[N int64 | float64]() *testFilterAgg[N] {
264-
return &testFilterAgg[N]{
265-
values: make(map[attribute.Set]precomputedValue[N]),
266-
}
267-
}
268-
269-
func (a *testFilterAgg[N]) Aggregate(val N, attr attribute.Set) {
270-
v := a.values[attr]
271-
v.measured = val
272-
a.values[attr] = v
273-
}
274-
275-
// nolint: unused // Used to agg filtered.
276-
func (a *testFilterAgg[N]) aggregateFiltered(val N, attr attribute.Set) {
277-
v := a.values[attr]
278-
v.filtered += val
279-
a.values[attr] = v
280-
}
281-
282-
func (a *testFilterAgg[N]) Aggregation() metricdata.Aggregation {
283-
a.aggregationN++
284-
return nil
285-
}

sdk/metric/internal/aggregate/sum.go

Lines changed: 12 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -158,63 +158,6 @@ func (s *cumulativeSum[N]) Aggregation() metricdata.Aggregation {
158158
return out
159159
}
160160

161-
// precomputedValue is the recorded measurement value for a set of attributes.
162-
type precomputedValue[N int64 | float64] struct {
163-
// measured is the last value measured for a set of attributes that were
164-
// not filtered.
165-
measured N
166-
// filtered is the sum of values from measurements that had their
167-
// attributes filtered.
168-
filtered N
169-
}
170-
171-
// precomputedMap is the storage for precomputed sums.
172-
type precomputedMap[N int64 | float64] struct {
173-
sync.Mutex
174-
values map[attribute.Set]precomputedValue[N]
175-
}
176-
177-
func newPrecomputedMap[N int64 | float64]() *precomputedMap[N] {
178-
return &precomputedMap[N]{
179-
values: make(map[attribute.Set]precomputedValue[N]),
180-
}
181-
}
182-
183-
// Aggregate records value with the unfiltered attributes attr.
184-
//
185-
// If a previous measurement was made for the same attribute set:
186-
//
187-
// - If that measurement's attributes were not filtered, this value overwrite
188-
// that value.
189-
// - If that measurement's attributes were filtered, this value will be
190-
// recorded along side that value.
191-
func (s *precomputedMap[N]) Aggregate(value N, attr attribute.Set) {
192-
s.Lock()
193-
v := s.values[attr]
194-
v.measured = value
195-
s.values[attr] = v
196-
s.Unlock()
197-
}
198-
199-
// aggregateFiltered records value with the filtered attributes attr.
200-
//
201-
// If a previous measurement was made for the same attribute set:
202-
//
203-
// - If that measurement's attributes were not filtered, this value will be
204-
// recorded along side that value.
205-
// - If that measurement's attributes were filtered, this value will be
206-
// added to it.
207-
//
208-
// This method should not be used if attr have not been reduced by an attribute
209-
// filter.
210-
func (s *precomputedMap[N]) aggregateFiltered(value N, attr attribute.Set) { // nolint: unused // Used to agg filtered.
211-
s.Lock()
212-
v := s.values[attr]
213-
v.filtered += value
214-
s.values[attr] = v
215-
s.Unlock()
216-
}
217-
218161
// NewPrecomputedDeltaSum returns an Aggregator that summarizes a set of
219162
// pre-computed sums. Each sum is scoped by attributes and the aggregation
220163
// cycle the measurements were made in.
@@ -226,17 +169,17 @@ func (s *precomputedMap[N]) aggregateFiltered(value N, attr attribute.Set) { //
226169
// The output Aggregation will report recorded values as delta temporality.
227170
func NewPrecomputedDeltaSum[N int64 | float64](monotonic bool) Aggregator[N] {
228171
return &precomputedDeltaSum[N]{
229-
precomputedMap: newPrecomputedMap[N](),
230-
reported: make(map[attribute.Set]N),
231-
monotonic: monotonic,
232-
start: now(),
172+
valueMap: newValueMap[N](),
173+
reported: make(map[attribute.Set]N),
174+
monotonic: monotonic,
175+
start: now(),
233176
}
234177
}
235178

236179
// precomputedDeltaSum summarizes a set of pre-computed sums recorded over all
237180
// aggregation cycles as the delta of these sums.
238181
type precomputedDeltaSum[N int64 | float64] struct {
239-
*precomputedMap[N]
182+
*valueMap[N]
240183

241184
reported map[attribute.Set]N
242185

@@ -271,15 +214,14 @@ func (s *precomputedDeltaSum[N]) Aggregation() metricdata.Aggregation {
271214
DataPoints: make([]metricdata.DataPoint[N], 0, len(s.values)),
272215
}
273216
for attr, value := range s.values {
274-
v := value.measured + value.filtered
275-
delta := v - s.reported[attr]
217+
delta := value - s.reported[attr]
276218
out.DataPoints = append(out.DataPoints, metricdata.DataPoint[N]{
277219
Attributes: attr,
278220
StartTime: s.start,
279221
Time: t,
280222
Value: delta,
281223
})
282-
newReported[attr] = v
224+
newReported[attr] = value
283225
// Unused attribute sets do not report.
284226
delete(s.values, attr)
285227
}
@@ -302,15 +244,15 @@ func (s *precomputedDeltaSum[N]) Aggregation() metricdata.Aggregation {
302244
// temporality.
303245
func NewPrecomputedCumulativeSum[N int64 | float64](monotonic bool) Aggregator[N] {
304246
return &precomputedCumulativeSum[N]{
305-
precomputedMap: newPrecomputedMap[N](),
306-
monotonic: monotonic,
307-
start: now(),
247+
valueMap: newValueMap[N](),
248+
monotonic: monotonic,
249+
start: now(),
308250
}
309251
}
310252

311253
// precomputedCumulativeSum directly records and reports a set of pre-computed sums.
312254
type precomputedCumulativeSum[N int64 | float64] struct {
313-
*precomputedMap[N]
255+
*valueMap[N]
314256

315257
monotonic bool
316258
start time.Time
@@ -345,7 +287,7 @@ func (s *precomputedCumulativeSum[N]) Aggregation() metricdata.Aggregation {
345287
Attributes: attr,
346288
StartTime: s.start,
347289
Time: t,
348-
Value: value.measured + value.filtered,
290+
Value: value,
349291
})
350292
// Unused attribute sets do not report.
351293
delete(s.values, attr)

0 commit comments

Comments
 (0)