diff --git a/CHANGELOG.md b/CHANGELOG.md index 742c2aaf4a6..822d55bd053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add the `go.opentelemetry.io/otel/semconv/v1.16.0` package. The package contains semantic conventions from the `v1.16.0` version of the OpenTelemetry specification. (#3579) - Metric instruments were added to `go.opentelemetry.io/otel/metric/instrument`. - These instruments are use as replacements of the depreacted `go.opentelemetry.io/otel/metric/instrument/{asyncfloat64,asyncint64,syncfloat64,syncint64}` packages.(#3575) + These instruments are use as replacements of the depreacted `go.opentelemetry.io/otel/metric/instrument/{asyncfloat64,asyncint64,syncfloat64,syncint64}` packages.(#3575, #3586) - `Float64ObservableCounter` replaces the `asyncfloat64.Counter` - `Float64ObservableUpDownCounter` replaces the `asyncfloat64.UpDownCounter` - `Float64ObservableGauge` replaces the `asyncfloat64.Gauge` diff --git a/metric/example_test.go b/metric/example_test.go index 9b33c0f9b5f..579404c7593 100644 --- a/metric/example_test.go +++ b/metric/example_test.go @@ -55,7 +55,7 @@ func ExampleMeter_asynchronous_single() { _, err := meter.Int64ObservableGauge( "DiskUsage", instrument.WithUnit(unit.Bytes), - instrument.WithInt64Callback(func(ctx context.Context, inst instrument.Int64Observer) error { + instrument.WithInt64Callback(func(_ context.Context, obsrv instrument.Int64Observer) error { // Do the real work here to get the real disk usage. For example, // // usage, err := GetDiskUsage(diskID) @@ -69,7 +69,7 @@ func ExampleMeter_asynchronous_single() { // // For demonstration purpose, a static value is used here. usage := 75000 - inst.Observe(ctx, int64(usage), attribute.Int("disk.id", 3)) + obsrv.Observe(int64(usage), attribute.Int("disk.id", 3)) return nil }), ) diff --git a/metric/instrument/asyncfloat64.go b/metric/instrument/asyncfloat64.go index ad58dd0d9e7..2f624bfe005 100644 --- a/metric/instrument/asyncfloat64.go +++ b/metric/instrument/asyncfloat64.go @@ -21,45 +21,51 @@ import ( "go.opentelemetry.io/otel/metric/unit" ) -// Float64Observer is a recorder of float64 measurement values. +// Float64Observable describes a set of instruments used asynchronously to +// record float64 measurements once per collection cycle. Observations of +// these instruments are only made within a callback. +// // Warning: methods may be added to this interface in minor releases. -type Float64Observer interface { +type Float64Observable interface { Asynchronous - // Observe records the measurement value for a set of attributes. - // - // It is only valid to call this within a callback. If called outside of - // the registered callback it should have no effect on the instrument, and - // an error will be reported via the error handler. - Observe(ctx context.Context, value float64, attributes ...attribute.KeyValue) + float64Observable() } // Float64ObservableCounter is an instrument used to asynchronously record -// increasing float64 measurements once per a measurement collection cycle. The -// Observe method is used to record the measured state of the instrument when -// it is called. Implementations will assume the observed value to be the -// cumulative sum of the count. +// increasing float64 measurements once per collection cycle. Observations are +// only made within a callback for this instrument. The value observed is +// assumed the to be the cumulative sum of the count. // // Warning: methods may be added to this interface in minor releases. -type Float64ObservableCounter interface{ Float64Observer } +type Float64ObservableCounter interface{ Float64Observable } // Float64ObservableUpDownCounter is an instrument used to asynchronously -// record float64 measurements once per a measurement collection cycle. The -// Observe method is used to record the measured state of the instrument when -// it is called. Implementations will assume the observed value to be the -// cumulative sum of the count. +// record float64 measurements once per collection cycle. Observations are only +// made within a callback for this instrument. The value observed is assumed +// the to be the cumulative sum of the count. // // Warning: methods may be added to this interface in minor releases. -type Float64ObservableUpDownCounter interface{ Float64Observer } +type Float64ObservableUpDownCounter interface{ Float64Observable } // Float64ObservableGauge is an instrument used to asynchronously record -// instantaneous float64 measurements once per a measurement collection cycle. +// instantaneous float64 measurements once per collection cycle. Observations +// are only made within a callback for this instrument. // // Warning: methods may be added to this interface in minor releases. -type Float64ObservableGauge interface{ Float64Observer } +type Float64ObservableGauge interface{ Float64Observable } + +// Float64Observer is a recorder of float64 measurements. +// +// Warning: methods may be added to this interface in minor releases. +type Float64Observer interface { + Observe(value float64, attributes ...attribute.KeyValue) +} // Float64Callback is a function registered with a Meter that makes -// observations for a Float64Observer it is registered with. +// observations for a Float64Observerable instrument it is registered with. +// Calls to the Float64Observer record measurement values for the +// Float64Observable. // // The function needs to complete in a finite amount of time and the deadline // of the passed context is expected to be honored. diff --git a/metric/instrument/asyncfloat64_test.go b/metric/instrument/asyncfloat64_test.go index ab7d0fe5e13..7f315babaad 100644 --- a/metric/instrument/asyncfloat64_test.go +++ b/metric/instrument/asyncfloat64_test.go @@ -35,8 +35,8 @@ func TestFloat64ObserverOptions(t *testing.T) { got := NewFloat64ObserverConfig( WithDescription(desc), WithUnit(uBytes), - WithFloat64Callback(func(ctx context.Context, o Float64Observer) error { - o.Observe(ctx, token) + WithFloat64Callback(func(ctx context.Context, obsrv Float64Observer) error { + obsrv.Observe(token) return nil }), ) @@ -57,6 +57,6 @@ type float64Observer struct { got float64 } -func (o *float64Observer) Observe(_ context.Context, v float64, _ ...attribute.KeyValue) { +func (o *float64Observer) Observe(v float64, _ ...attribute.KeyValue) { o.got = v } diff --git a/metric/instrument/asyncint64.go b/metric/instrument/asyncint64.go index debba92f0aa..ac0d09d90cd 100644 --- a/metric/instrument/asyncint64.go +++ b/metric/instrument/asyncint64.go @@ -21,46 +21,51 @@ import ( "go.opentelemetry.io/otel/metric/unit" ) -// Int64Observer is a recorder of int64 measurement values. +// Int64Observable describes a set of instruments used asynchronously to record +// int64 measurements once per collection cycle. Observations of these +// instruments are only made within a callback. // // Warning: methods may be added to this interface in minor releases. -type Int64Observer interface { +type Int64Observable interface { Asynchronous - // Observe records the measurement value for a set of attributes. - // - // It is only valid to call this within a callback. If called outside of - // the registered callback it should have no effect on the instrument, and - // an error will be reported via the error handler. - Observe(ctx context.Context, value int64, attributes ...attribute.KeyValue) + int64Observable() } // Int64ObservableCounter is an instrument used to asynchronously record -// increasing int64 measurements once per a measurement collection cycle. The -// Observe method is used to record the measured state of the instrument when -// it is called. Implementations will assume the observed value to be the -// cumulative sum of the count. +// increasing int64 measurements once per collection cycle. Observations are +// only made within a callback for this instrument. The value observed is +// assumed the to be the cumulative sum of the count. // // Warning: methods may be added to this interface in minor releases. -type Int64ObservableCounter interface{ Int64Observer } +type Int64ObservableCounter interface{ Int64Observable } // Int64ObservableUpDownCounter is an instrument used to asynchronously record -// int64 measurements once per a measurement collection cycle. The Observe -// method is used to record the measured state of the instrument when it is -// called. Implementations will assume the observed value to be the cumulative -// sum of the count. +// int64 measurements once per collection cycle. Observations are only made +// within a callback for this instrument. The value observed is assumed the to +// be the cumulative sum of the count. // // Warning: methods may be added to this interface in minor releases. -type Int64ObservableUpDownCounter interface{ Int64Observer } +type Int64ObservableUpDownCounter interface{ Int64Observable } // Int64ObservableGauge is an instrument used to asynchronously record -// instantaneous int64 measurements once per a measurement collection cycle. +// instantaneous int64 measurements once per collection cycle. Observations are +// only made within a callback for this instrument. +// +// Warning: methods may be added to this interface in minor releases. +type Int64ObservableGauge interface{ Int64Observable } + +// Int64Observer is a recorder of int64 measurements. // // Warning: methods may be added to this interface in minor releases. -type Int64ObservableGauge interface{ Int64Observer } +type Int64Observer interface { + Observe(value int64, attributes ...attribute.KeyValue) +} // Int64Callback is a function registered with a Meter that makes -// observations for an Int64Observer it is registered with. +// observations for a Int64Observerable instrument it is registered with. +// Calls to the Int64Observer record measurement values for the +// Int64Observable. // // The function needs to complete in a finite amount of time and the deadline // of the passed context is expected to be honored. diff --git a/metric/instrument/asyncint64_test.go b/metric/instrument/asyncint64_test.go index a9ad527f1ea..bb4309e594a 100644 --- a/metric/instrument/asyncint64_test.go +++ b/metric/instrument/asyncint64_test.go @@ -35,8 +35,8 @@ func TestInt64ObserverOptions(t *testing.T) { got := NewInt64ObserverConfig( WithDescription(desc), WithUnit(uBytes), - WithInt64Callback(func(ctx context.Context, o Int64Observer) error { - o.Observe(ctx, token) + WithInt64Callback(func(_ context.Context, obsrv Int64Observer) error { + obsrv.Observe(token) return nil }), ) @@ -57,6 +57,6 @@ type int64Observer struct { got int64 } -func (o *int64Observer) Observe(_ context.Context, v int64, _ ...attribute.KeyValue) { +func (o *int64Observer) Observe(v int64, _ ...attribute.KeyValue) { o.got = v } diff --git a/metric/internal/global/instruments.go b/metric/internal/global/instruments.go index 1398ada26be..d1480fa5f3e 100644 --- a/metric/internal/global/instruments.go +++ b/metric/internal/global/instruments.go @@ -30,12 +30,12 @@ type unwrapper interface { } type afCounter struct { + instrument.Float64Observable + name string opts []instrument.Float64ObserverOption delegate atomic.Value //instrument.Float64ObservableCounter - - instrument.Asynchronous } var _ unwrapper = (*afCounter)(nil) @@ -50,12 +50,6 @@ func (i *afCounter) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -func (i *afCounter) Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Float64ObservableCounter).Observe(ctx, x, attrs...) - } -} - func (i *afCounter) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Float64ObservableCounter) @@ -64,12 +58,12 @@ func (i *afCounter) Unwrap() instrument.Asynchronous { } type afUpDownCounter struct { + instrument.Float64Observable + name string opts []instrument.Float64ObserverOption delegate atomic.Value //instrument.Float64ObservableUpDownCounter - - instrument.Asynchronous } var _ unwrapper = (*afUpDownCounter)(nil) @@ -84,12 +78,6 @@ func (i *afUpDownCounter) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -func (i *afUpDownCounter) Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Float64ObservableUpDownCounter).Observe(ctx, x, attrs...) - } -} - func (i *afUpDownCounter) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Float64ObservableUpDownCounter) @@ -98,14 +86,17 @@ func (i *afUpDownCounter) Unwrap() instrument.Asynchronous { } type afGauge struct { + instrument.Float64Observable + name string opts []instrument.Float64ObserverOption delegate atomic.Value //instrument.Float64ObservableGauge - - instrument.Asynchronous } +var _ unwrapper = (*afGauge)(nil) +var _ instrument.Float64ObservableGauge = (*afGauge)(nil) + func (i *afGauge) setDelegate(m metric.Meter) { ctr, err := m.Float64ObservableGauge(i.name, i.opts...) if err != nil { @@ -115,15 +106,6 @@ func (i *afGauge) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -var _ unwrapper = (*afGauge)(nil) -var _ instrument.Float64ObservableGauge = (*afGauge)(nil) - -func (i *afGauge) Observe(ctx context.Context, x float64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Float64ObservableGauge).Observe(ctx, x, attrs...) - } -} - func (i *afGauge) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Float64ObservableGauge) @@ -132,12 +114,12 @@ func (i *afGauge) Unwrap() instrument.Asynchronous { } type aiCounter struct { + instrument.Int64Observable + name string opts []instrument.Int64ObserverOption delegate atomic.Value //instrument.Int64ObservableCounter - - instrument.Asynchronous } var _ unwrapper = (*aiCounter)(nil) @@ -152,12 +134,6 @@ func (i *aiCounter) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -func (i *aiCounter) Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Int64ObservableCounter).Observe(ctx, x, attrs...) - } -} - func (i *aiCounter) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Int64ObservableCounter) @@ -166,12 +142,12 @@ func (i *aiCounter) Unwrap() instrument.Asynchronous { } type aiUpDownCounter struct { + instrument.Int64Observable + name string opts []instrument.Int64ObserverOption delegate atomic.Value //instrument.Int64ObservableUpDownCounter - - instrument.Asynchronous } var _ unwrapper = (*aiUpDownCounter)(nil) @@ -186,12 +162,6 @@ func (i *aiUpDownCounter) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -func (i *aiUpDownCounter) Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Int64ObservableUpDownCounter).Observe(ctx, x, attrs...) - } -} - func (i *aiUpDownCounter) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Int64ObservableUpDownCounter) @@ -200,12 +170,12 @@ func (i *aiUpDownCounter) Unwrap() instrument.Asynchronous { } type aiGauge struct { + instrument.Int64Observable + name string opts []instrument.Int64ObserverOption delegate atomic.Value //instrument.Int64ObservableGauge - - instrument.Asynchronous } var _ unwrapper = (*aiGauge)(nil) @@ -220,12 +190,6 @@ func (i *aiGauge) setDelegate(m metric.Meter) { i.delegate.Store(ctr) } -func (i *aiGauge) Observe(ctx context.Context, x int64, attrs ...attribute.KeyValue) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(instrument.Int64ObservableGauge).Observe(ctx, x, attrs...) - } -} - func (i *aiGauge) Unwrap() instrument.Asynchronous { if ctr := i.delegate.Load(); ctr != nil { return ctr.(instrument.Int64ObservableGauge) diff --git a/metric/internal/global/instruments_test.go b/metric/internal/global/instruments_test.go index 24c5eb4322e..18a731c8911 100644 --- a/metric/internal/global/instruments_test.go +++ b/metric/internal/global/instruments_test.go @@ -62,17 +62,20 @@ func TestAsyncInstrumentSetDelegateRace(t *testing.T) { t.Run("Float64", func(t *testing.T) { t.Run("Counter", func(t *testing.T) { delegate := &afCounter{} - testFloat64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testFloat64Race(f, delegate.setDelegate) }) t.Run("UpDownCounter", func(t *testing.T) { delegate := &afUpDownCounter{} - testFloat64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testFloat64Race(f, delegate.setDelegate) }) t.Run("Gauge", func(t *testing.T) { delegate := &afGauge{} - testFloat64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testFloat64Race(f, delegate.setDelegate) }) }) @@ -81,17 +84,20 @@ func TestAsyncInstrumentSetDelegateRace(t *testing.T) { t.Run("Int64", func(t *testing.T) { t.Run("Counter", func(t *testing.T) { delegate := &aiCounter{} - testInt64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testInt64Race(f, delegate.setDelegate) }) t.Run("UpDownCounter", func(t *testing.T) { delegate := &aiUpDownCounter{} - testInt64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testInt64Race(f, delegate.setDelegate) }) t.Run("Gauge", func(t *testing.T) { delegate := &aiGauge{} - testInt64Race(delegate.Observe, delegate.setDelegate) + f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() } + testInt64Race(f, delegate.setDelegate) }) }) } @@ -138,11 +144,11 @@ func TestSyncInstrumentSetDelegateRace(t *testing.T) { type testCountingFloatInstrument struct { count int - instrument.Asynchronous + instrument.Float64Observable instrument.Synchronous } -func (i *testCountingFloatInstrument) Observe(context.Context, float64, ...attribute.KeyValue) { +func (i *testCountingFloatInstrument) observe() { i.count++ } func (i *testCountingFloatInstrument) Add(context.Context, float64, ...attribute.KeyValue) { @@ -155,11 +161,11 @@ func (i *testCountingFloatInstrument) Record(context.Context, float64, ...attrib type testCountingIntInstrument struct { count int - instrument.Asynchronous + instrument.Int64Observable instrument.Synchronous } -func (i *testCountingIntInstrument) Observe(context.Context, int64, ...attribute.KeyValue) { +func (i *testCountingIntInstrument) observe() { i.count++ } func (i *testCountingIntInstrument) Add(context.Context, int64, ...attribute.KeyValue) { diff --git a/metric/internal/global/meter_types_test.go b/metric/internal/global/meter_types_test.go index 84637b286f9..5f172bf8f9e 100644 --- a/metric/internal/global/meter_types_test.go +++ b/metric/internal/global/meter_types_test.go @@ -148,10 +148,16 @@ type observationRecorder struct { ctx context.Context } -func (o observationRecorder) ObserveFloat64(i instrument.Float64Observer, value float64, attr ...attribute.KeyValue) { - i.Observe(o.ctx, value, attr...) +func (o observationRecorder) ObserveFloat64(i instrument.Float64Observable, value float64, attr ...attribute.KeyValue) { + iImpl, ok := i.(*testCountingFloatInstrument) + if ok { + iImpl.observe() + } } -func (o observationRecorder) ObserveInt64(i instrument.Int64Observer, value int64, attr ...attribute.KeyValue) { - i.Observe(o.ctx, value, attr...) +func (o observationRecorder) ObserveInt64(i instrument.Int64Observable, value int64, attr ...attribute.KeyValue) { + iImpl, ok := i.(*testCountingIntInstrument) + if ok { + iImpl.observe() + } } diff --git a/metric/meter.go b/metric/meter.go index fc39f40b3d8..f1e917e9329 100644 --- a/metric/meter.go +++ b/metric/meter.go @@ -123,9 +123,9 @@ type Callback func(context.Context, Observer) error // Observer records measurements for multiple instruments in a Callback. type Observer interface { // ObserveFloat64 records the float64 value with attributes for obsrv. - ObserveFloat64(obsrv instrument.Float64Observer, value float64, attributes ...attribute.KeyValue) + ObserveFloat64(obsrv instrument.Float64Observable, value float64, attributes ...attribute.KeyValue) // ObserveInt64 records the int64 value with attributes for obsrv. - ObserveInt64(obsrv instrument.Int64Observer, value int64, attributes ...attribute.KeyValue) + ObserveInt64(obsrv instrument.Int64Observable, value int64, attributes ...attribute.KeyValue) } // Registration is an token representing the unique registration of a callback diff --git a/metric/noop.go b/metric/noop.go index 409268ecc98..c586627aef8 100644 --- a/metric/noop.go +++ b/metric/noop.go @@ -97,7 +97,7 @@ type noopReg struct{} func (noopReg) Unregister() error { return nil } type nonrecordingAsyncFloat64Instrument struct { - instrument.Asynchronous + instrument.Float64Observable } var ( @@ -118,12 +118,8 @@ func (n nonrecordingAsyncFloat64Instrument) Gauge(string, ...instrument.Float64O return n, nil } -func (nonrecordingAsyncFloat64Instrument) Observe(context.Context, float64, ...attribute.KeyValue) { - -} - type nonrecordingAsyncInt64Instrument struct { - instrument.Asynchronous + instrument.Int64Observable } var ( @@ -144,9 +140,6 @@ func (n nonrecordingAsyncInt64Instrument) Gauge(string, ...instrument.Int64Obser return n, nil } -func (nonrecordingAsyncInt64Instrument) Observe(context.Context, int64, ...attribute.KeyValue) { -} - type nonrecordingSyncFloat64Instrument struct { instrument.Synchronous } diff --git a/metric/noop_test.go b/metric/noop_test.go index 6c75c0198d1..59695ccd5bc 100644 --- a/metric/noop_test.go +++ b/metric/noop_test.go @@ -72,45 +72,3 @@ func TestSyncInt64(t *testing.T) { inst.Record(context.Background(), 1, attribute.String("key", "value")) }) } - -func TestAsyncFloat64(t *testing.T) { - meter := NewNoopMeterProvider().Meter("test instrumentation") - assert.NotPanics(t, func() { - inst, err := meter.Float64ObservableCounter("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), 1.0, attribute.String("key", "value")) - }) - - assert.NotPanics(t, func() { - inst, err := meter.Float64ObservableUpDownCounter("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), -1.0, attribute.String("key", "value")) - }) - - assert.NotPanics(t, func() { - inst, err := meter.Float64ObservableGauge("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), 1.0, attribute.String("key", "value")) - }) -} - -func TestAsyncInt64(t *testing.T) { - meter := NewNoopMeterProvider().Meter("test instrumentation") - assert.NotPanics(t, func() { - inst, err := meter.Int64ObservableCounter("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), 1, attribute.String("key", "value")) - }) - - assert.NotPanics(t, func() { - inst, err := meter.Int64ObservableUpDownCounter("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), -1, attribute.String("key", "value")) - }) - - assert.NotPanics(t, func() { - inst, err := meter.Int64ObservableGauge("test instrument") - require.NoError(t, err) - inst.Observe(context.Background(), 1, attribute.String("key", "value")) - }) -} diff --git a/sdk/metric/instrument.go b/sdk/metric/instrument.go index 2b3c2356d3a..8e0a4b5553c 100644 --- a/sdk/metric/instrument.go +++ b/sdk/metric/instrument.go @@ -20,7 +20,6 @@ import ( "fmt" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/metric/instrument" "go.opentelemetry.io/otel/metric/unit" "go.opentelemetry.io/otel/sdk/instrumentation" @@ -211,6 +210,36 @@ type observablID[N int64 | float64] struct { scope instrumentation.Scope } +type float64Observable struct { + instrument.Float64Observable + *observable[float64] +} + +var _ instrument.Float64ObservableCounter = float64Observable{} +var _ instrument.Float64ObservableUpDownCounter = float64Observable{} +var _ instrument.Float64ObservableGauge = float64Observable{} + +func newFloat64Observable(scope instrumentation.Scope, kind InstrumentKind, name, desc string, u unit.Unit, agg []internal.Aggregator[float64]) float64Observable { + return float64Observable{ + observable: newObservable[float64](scope, kind, name, desc, u, agg), + } +} + +type int64Observable struct { + instrument.Int64Observable + *observable[int64] +} + +var _ instrument.Int64ObservableCounter = int64Observable{} +var _ instrument.Int64ObservableUpDownCounter = int64Observable{} +var _ instrument.Int64ObservableGauge = int64Observable{} + +func newInt64Observable(scope instrumentation.Scope, kind InstrumentKind, name, desc string, u unit.Unit, agg []internal.Aggregator[int64]) int64Observable { + return int64Observable{ + observable: newObservable[int64](scope, kind, name, desc, u, agg), + } +} + type observable[N int64 | float64] struct { instrument.Asynchronous observablID[N] @@ -231,25 +260,6 @@ func newObservable[N int64 | float64](scope instrumentation.Scope, kind Instrume } } -var _ instrument.Float64ObservableCounter = (*observable[float64])(nil) -var _ instrument.Float64ObservableUpDownCounter = (*observable[float64])(nil) -var _ instrument.Float64ObservableGauge = (*observable[float64])(nil) -var _ instrument.Int64ObservableCounter = (*observable[int64])(nil) -var _ instrument.Int64ObservableUpDownCounter = (*observable[int64])(nil) -var _ instrument.Int64ObservableGauge = (*observable[int64])(nil) - -// Observe logs an error. -func (o *observable[N]) Observe(ctx context.Context, val N, attrs ...attribute.KeyValue) { - var zero N - err := errors.New("invalid observation") - global.Error(err, "dropping observation made outside a callback", - "name", o.name, - "description", o.description, - "unit", o.unit, - "number", fmt.Sprintf("%T", zero), - ) -} - // observe records the val for the set of attrs. func (o *observable[N]) observe(val N, attrs []attribute.KeyValue) { for _, agg := range o.aggregators { diff --git a/sdk/metric/meter.go b/sdk/metric/meter.go index e6732ff5ff3..01906364d00 100644 --- a/sdk/metric/meter.go +++ b/sdk/metric/meter.go @@ -232,7 +232,7 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...instrument.Asynchro } switch o := inst.(type) { - case *observable[int64]: + case int64Observable: if err := o.registerable(m.scope); err != nil { if !errors.Is(err, errEmptyAgg) { errs.append(err) @@ -240,7 +240,7 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...instrument.Asynchro continue } reg.registerInt64(o.observablID) - case *observable[float64]: + case float64Observable: if err := o.registerable(m.scope); err != nil { if !errors.Is(err, errEmptyAgg) { errs.append(err) @@ -298,10 +298,10 @@ var ( errUnregObserver = errors.New("observable instrument not registered for callback") ) -func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...attribute.KeyValue) { - var oImpl *observable[float64] +func (r observer) ObserveFloat64(o instrument.Float64Observable, v float64, a ...attribute.KeyValue) { + var oImpl float64Observable switch conv := o.(type) { - case *observable[float64]: + case float64Observable: oImpl = conv case interface { Unwrap() instrument.Asynchronous @@ -309,7 +309,7 @@ func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...a // Unwrap any global. async := conv.Unwrap() var ok bool - if oImpl, ok = async.(*observable[float64]); !ok { + if oImpl, ok = async.(float64Observable); !ok { global.Error(errUnknownObserver, "failed to record asynchronous") return } @@ -330,10 +330,10 @@ func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...a oImpl.observe(v, a) } -func (r observer) ObserveInt64(o instrument.Int64Observer, v int64, a ...attribute.KeyValue) { - var oImpl *observable[int64] +func (r observer) ObserveInt64(o instrument.Int64Observable, v int64, a ...attribute.KeyValue) { + var oImpl int64Observable switch conv := o.(type) { - case *observable[int64]: + case int64Observable: oImpl = conv case interface { Unwrap() instrument.Asynchronous @@ -341,7 +341,7 @@ func (r observer) ObserveInt64(o instrument.Int64Observer, v int64, a ...attribu // Unwrap any global. async := conv.Unwrap() var ok bool - if oImpl, ok = async.(*observable[int64]); !ok { + if oImpl, ok = async.(int64Observable); !ok { global.Error(errUnknownObserver, "failed to record asynchronous") return } @@ -398,13 +398,13 @@ func (p *instProvider[N]) lookup(kind InstrumentKind, name, desc string, u unit. type int64ObservProvider struct{ *instProvider[int64] } -func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc string, u unit.Unit) (*observable[int64], error) { +func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc string, u unit.Unit) (int64Observable, error) { aggs, err := p.aggs(kind, name, desc, u) - return newObservable(p.scope, kind, name, desc, u, aggs), err + return newInt64Observable(p.scope, kind, name, desc, u, aggs), err } -func (p int64ObservProvider) registerCallbacks(inst *observable[int64], cBacks []instrument.Int64Callback) { - if inst == nil { +func (p int64ObservProvider) registerCallbacks(inst int64Observable, cBacks []instrument.Int64Callback) { + if inst.observable == nil || len(inst.aggregators) == 0 { // Drop aggregator. return } @@ -414,20 +414,28 @@ func (p int64ObservProvider) registerCallbacks(inst *observable[int64], cBacks [ } } -func (p int64ObservProvider) callback(i *observable[int64], f instrument.Int64Callback) func(context.Context) error { - inst := callbackObserver[int64]{i} +func (p int64ObservProvider) callback(i int64Observable, f instrument.Int64Callback) func(context.Context) error { + inst := int64Observer{i} return func(ctx context.Context) error { return f(ctx, inst) } } +type int64Observer struct { + int64Observable +} + +func (o int64Observer) Observe(val int64, attrs ...attribute.KeyValue) { + o.observe(val, attrs) +} + type float64ObservProvider struct{ *instProvider[float64] } -func (p float64ObservProvider) lookup(kind InstrumentKind, name, desc string, u unit.Unit) (*observable[float64], error) { +func (p float64ObservProvider) lookup(kind InstrumentKind, name, desc string, u unit.Unit) (float64Observable, error) { aggs, err := p.aggs(kind, name, desc, u) - return newObservable(p.scope, kind, name, desc, u, aggs), err + return newFloat64Observable(p.scope, kind, name, desc, u, aggs), err } -func (p float64ObservProvider) registerCallbacks(inst *observable[float64], cBacks []instrument.Float64Callback) { - if inst == nil { +func (p float64ObservProvider) registerCallbacks(inst float64Observable, cBacks []instrument.Float64Callback) { + if inst.observable == nil || len(inst.aggregators) == 0 { // Drop aggregator. return } @@ -437,17 +445,15 @@ func (p float64ObservProvider) registerCallbacks(inst *observable[float64], cBac } } -func (p float64ObservProvider) callback(i *observable[float64], f instrument.Float64Callback) func(context.Context) error { - inst := callbackObserver[float64]{i} +func (p float64ObservProvider) callback(i float64Observable, f instrument.Float64Callback) func(context.Context) error { + inst := float64Observer{i} return func(ctx context.Context) error { return f(ctx, inst) } } -// callbackObserver is an observer that records values for a wrapped -// observable. -type callbackObserver[N int64 | float64] struct { - *observable[N] +type float64Observer struct { + float64Observable } -func (o callbackObserver[N]) Observe(_ context.Context, val N, attrs ...attribute.KeyValue) { +func (o float64Observer) Observe(val float64, attrs ...attribute.KeyValue) { o.observe(val, attrs) } diff --git a/sdk/metric/meter_test.go b/sdk/metric/meter_test.go index 190528e3c51..a5248bedfb0 100644 --- a/sdk/metric/meter_test.go +++ b/sdk/metric/meter_test.go @@ -179,8 +179,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableInt64Count", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Int64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Int64Observer) error { + o.Observe(4, attrs...) return nil } ctr, err := m.Int64ObservableCounter("aint", instrument.WithInt64Callback(cback)) @@ -190,9 +190,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, ctr) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - ctr.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "aint", @@ -209,8 +206,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableInt64UpDownCount", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Int64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Int64Observer) error { + o.Observe(4, attrs...) return nil } ctr, err := m.Int64ObservableUpDownCounter("aint", instrument.WithInt64Callback(cback)) @@ -220,9 +217,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, ctr) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - ctr.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "aint", @@ -239,8 +233,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableInt64Gauge", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Int64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Int64Observer) error { + o.Observe(4, attrs...) return nil } gauge, err := m.Int64ObservableGauge("agauge", instrument.WithInt64Callback(cback)) @@ -250,9 +244,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, gauge) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - gauge.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "agauge", @@ -267,8 +258,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableFloat64Count", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Float64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Float64Observer) error { + o.Observe(4, attrs...) return nil } ctr, err := m.Float64ObservableCounter("afloat", instrument.WithFloat64Callback(cback)) @@ -278,9 +269,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, ctr) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - ctr.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "afloat", @@ -297,8 +285,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableFloat64UpDownCount", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Float64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Float64Observer) error { + o.Observe(4, attrs...) return nil } ctr, err := m.Float64ObservableUpDownCounter("afloat", instrument.WithFloat64Callback(cback)) @@ -308,9 +296,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, ctr) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - ctr.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "afloat", @@ -327,8 +312,8 @@ func TestMeterCreatesInstruments(t *testing.T) { { name: "ObservableFloat64Gauge", fn: func(t *testing.T, m metric.Meter) { - cback := func(ctx context.Context, o instrument.Float64Observer) error { - o.Observe(ctx, 4, attrs...) + cback := func(_ context.Context, o instrument.Float64Observer) error { + o.Observe(4, attrs...) return nil } gauge, err := m.Float64ObservableGauge("agauge", instrument.WithFloat64Callback(cback)) @@ -338,9 +323,6 @@ func TestMeterCreatesInstruments(t *testing.T) { return nil }, gauge) assert.NoError(t, err) - - // Observed outside of a callback, it should be ignored. - gauge.Observe(context.Background(), 19) }, want: metricdata.Metrics{ Name: "agauge", @@ -564,10 +546,9 @@ func TestCallbackObserverNonRegistered(t *testing.T) { fCtr, err := m2.Float64ObservableCounter("float64 ctr") require.NoError(t, err) - // Panics if Observe is called. - type int64Obsrv struct{ instrument.Int64Observer } + type int64Obsrv struct{ instrument.Int64Observable } int64Foreign := int64Obsrv{} - type float64Obsrv struct{ instrument.Float64Observer } + type float64Obsrv struct{ instrument.Float64Observable } float64Foreign := float64Obsrv{} _, err = m1.RegisterCallback( @@ -1311,9 +1292,9 @@ func TestAsynchronousExample(t *testing.T) { observations := make(map[attribute.Set]int64) _, err := meter.Int64ObservableCounter(instName, instrument.WithInt64Callback( - func(ctx context.Context, o instrument.Int64Observer) error { + func(_ context.Context, o instrument.Int64Observer) error { for attrSet, val := range observations { - o.Observe(ctx, val, attrSet.ToSlice()...) + o.Observe(val, attrSet.ToSlice()...) } return nil },