1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-11-25 22:41:46 +02:00

Handle duplicate Aggregators and log instrument conflicts (#3251)

* Add the cache type

* Add cache unit tests

* Test cache concurrency

* Add the instrumentCache

* Use the instrumentCache to deduplicate creation

* Drop unique check from addAggregator

* Fix aggregatorCache* docs

* Update cachedAggregator and aggregator method docs

* Remove unnecessary type constraint

* Remove unused errAlreadyRegistered

* Rename to not shadow imports

* Add changes to changelog

* Fix changelog English

* Store resolvers in the meter instead of caches

* Test all Aggregator[N] impls are comparable

* Fix lint

* Add documentation that Aggregators need to be comparable

* Update sdk/metric/internal/aggregator.go

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Update sdk/metric/instrument.go

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Update sdk/metric/instrument.go

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Update sdk/metric/internal/aggregator_test.go

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Fix pipeline_test.go use of newInstrumentCache

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
This commit is contained in:
Tyler Yahn
2022-10-11 12:41:47 -07:00
committed by GitHub
parent ffa94ca529
commit b5292b8459
10 changed files with 505 additions and 242 deletions

View File

@@ -16,6 +16,7 @@ package metric // import "go.opentelemetry.io/otel/sdk/metric"
import (
"context"
"fmt"
"sync"
"testing"
@@ -49,8 +50,10 @@ func TestEmptyPipeline(t *testing.T) {
assert.Nil(t, output.Resource)
assert.Len(t, output.ScopeMetrics, 0)
err = pipe.addAggregator(instrumentation.Scope{}, "name", "desc", unit.Dimensionless, testSumAggregator{})
assert.NoError(t, err)
iSync := instrumentSync{"name", "desc", unit.Dimensionless, testSumAggregator{}}
assert.NotPanics(t, func() {
pipe.addSync(instrumentation.Scope{}, iSync)
})
require.NotPanics(t, func() {
pipe.addCallback(func(ctx context.Context) {})
@@ -71,8 +74,10 @@ func TestNewPipeline(t *testing.T) {
assert.Equal(t, resource.Empty(), output.Resource)
assert.Len(t, output.ScopeMetrics, 0)
err = pipe.addAggregator(instrumentation.Scope{}, "name", "desc", unit.Dimensionless, testSumAggregator{})
assert.NoError(t, err)
iSync := instrumentSync{"name", "desc", unit.Dimensionless, testSumAggregator{}}
assert.NotPanics(t, func() {
pipe.addSync(instrumentation.Scope{}, iSync)
})
require.NotPanics(t, func() {
pipe.addCallback(func(ctx context.Context) {})
@@ -85,99 +90,6 @@ func TestNewPipeline(t *testing.T) {
require.Len(t, output.ScopeMetrics[0].Metrics, 1)
}
func TestPipelineDuplicateRegistration(t *testing.T) {
type instrumentID struct {
scope instrumentation.Scope
name string
description string
unit unit.Unit
}
testCases := []struct {
name string
secondInst instrumentID
want error
wantScopeLen int
wantMetricsLen int
}{
{
name: "exact should error",
secondInst: instrumentID{
scope: instrumentation.Scope{},
name: "name",
description: "desc",
unit: unit.Dimensionless,
},
want: errAlreadyRegistered,
wantScopeLen: 1,
wantMetricsLen: 1,
},
{
name: "description should not be identifying",
secondInst: instrumentID{
scope: instrumentation.Scope{},
name: "name",
description: "other desc",
unit: unit.Dimensionless,
},
want: errAlreadyRegistered,
wantScopeLen: 1,
wantMetricsLen: 1,
},
{
name: "scope should be identifying",
secondInst: instrumentID{
scope: instrumentation.Scope{
Name: "newScope",
},
name: "name",
description: "desc",
unit: unit.Dimensionless,
},
wantScopeLen: 2,
wantMetricsLen: 1,
},
{
name: "name should be identifying",
secondInst: instrumentID{
scope: instrumentation.Scope{},
name: "newName",
description: "desc",
unit: unit.Dimensionless,
},
wantScopeLen: 1,
wantMetricsLen: 2,
},
{
name: "unit should be identifying",
secondInst: instrumentID{
scope: instrumentation.Scope{},
name: "name",
description: "desc",
unit: unit.Bytes,
},
wantScopeLen: 1,
wantMetricsLen: 2,
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
pipe := newPipeline(nil, nil, nil)
err := pipe.addAggregator(instrumentation.Scope{}, "name", "desc", unit.Dimensionless, testSumAggregator{})
require.NoError(t, err)
err = pipe.addAggregator(tt.secondInst.scope, tt.secondInst.name, tt.secondInst.description, tt.secondInst.unit, testSumAggregator{})
assert.ErrorIs(t, err, tt.want)
if tt.wantScopeLen > 0 {
output, err := pipe.produce(context.Background())
assert.NoError(t, err)
require.Len(t, output.ScopeMetrics, tt.wantScopeLen)
require.Len(t, output.ScopeMetrics[0].Metrics, tt.wantMetricsLen)
}
})
}
}
func TestPipelineUsesResource(t *testing.T) {
res := resource.NewWithAttributes("noSchema", attribute.String("test", "resource"))
pipe := newPipeline(res, nil, nil)
@@ -201,10 +113,12 @@ func TestPipelineConcurrency(t *testing.T) {
}()
wg.Add(1)
go func() {
go func(n int) {
defer wg.Done()
_ = pipe.addAggregator(instrumentation.Scope{}, "name", "desc", unit.Dimensionless, testSumAggregator{})
}()
name := fmt.Sprintf("name %d", n)
sync := instrumentSync{name, "desc", unit.Dimensionless, testSumAggregator{}}
pipe.addSync(instrumentation.Scope{}, sync)
}(i)
wg.Add(1)
go func() {
@@ -249,7 +163,8 @@ func testDefaultViewImplicit[N int64 | float64]() func(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
i := newInserter[N](test.pipe)
c := newInstrumentCache[N](nil, nil)
i := newInserter(test.pipe, c)
got, err := i.Instrument(inst, unit.Dimensionless)
require.NoError(t, err)
assert.Len(t, got, 1, "default view not applied")