1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-07-15 01:04:25 +02:00

Remove the unneeded Observe method from the async instruments (#3586)

* Update RegisterCallback and Callback decls

RegisterCallback accept variadic Asynchronous instruments instead of a
slice.

Callback accept an observation result recorder to ensure instruments
that are observed by a callback.

* Update global impl

* Update noop impl

* Update SDK impl

* Fix prometheus example

* Fix metric API example_test

* Remove unused registerabler

* Rename ObservationRecorder to MultiObserver

* Update Callback documentation about MultiObserver

* Remove the Observe method from async inst

* Revert to iface for Observers

* Fix async inst docs

* Update global async delegate race test

* Restore removed observe doc

* Remove TODO

* Remove stale comment

* Update changelog
This commit is contained in:
Tyler Yahn
2023-01-25 12:58:09 -08:00
committed by GitHub
parent c7e2679529
commit c0fb8dec4c
15 changed files with 186 additions and 251 deletions

View File

@ -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. - 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) 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`. - 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` - `Float64ObservableCounter` replaces the `asyncfloat64.Counter`
- `Float64ObservableUpDownCounter` replaces the `asyncfloat64.UpDownCounter` - `Float64ObservableUpDownCounter` replaces the `asyncfloat64.UpDownCounter`
- `Float64ObservableGauge` replaces the `asyncfloat64.Gauge` - `Float64ObservableGauge` replaces the `asyncfloat64.Gauge`

View File

@ -55,7 +55,7 @@ func ExampleMeter_asynchronous_single() {
_, err := meter.Int64ObservableGauge( _, err := meter.Int64ObservableGauge(
"DiskUsage", "DiskUsage",
instrument.WithUnit(unit.Bytes), 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, // Do the real work here to get the real disk usage. For example,
// //
// usage, err := GetDiskUsage(diskID) // usage, err := GetDiskUsage(diskID)
@ -69,7 +69,7 @@ func ExampleMeter_asynchronous_single() {
// //
// For demonstration purpose, a static value is used here. // For demonstration purpose, a static value is used here.
usage := 75000 usage := 75000
inst.Observe(ctx, int64(usage), attribute.Int("disk.id", 3)) obsrv.Observe(int64(usage), attribute.Int("disk.id", 3))
return nil return nil
}), }),
) )

View File

@ -21,45 +21,51 @@ import (
"go.opentelemetry.io/otel/metric/unit" "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. // Warning: methods may be added to this interface in minor releases.
type Float64Observer interface { type Float64Observable interface {
Asynchronous Asynchronous
// Observe records the measurement value for a set of attributes. float64Observable()
//
// 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)
} }
// Float64ObservableCounter is an instrument used to asynchronously record // Float64ObservableCounter is an instrument used to asynchronously record
// increasing float64 measurements once per a measurement collection cycle. The // increasing float64 measurements once per collection cycle. Observations are
// Observe method is used to record the measured state of the instrument when // only made within a callback for this instrument. The value observed is
// it is called. Implementations will assume the observed value to be the // assumed the to be the cumulative sum of the count.
// cumulative sum of the count.
// //
// Warning: methods may be added to this interface in minor releases. // 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 // Float64ObservableUpDownCounter is an instrument used to asynchronously
// record float64 measurements once per a measurement collection cycle. The // record float64 measurements once per collection cycle. Observations are only
// Observe method is used to record the measured state of the instrument when // made within a callback for this instrument. The value observed is assumed
// it is called. Implementations will assume the observed value to be the // the to be the cumulative sum of the count.
// cumulative sum of the count.
// //
// Warning: methods may be added to this interface in minor releases. // 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 // 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. // 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 // 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 // The function needs to complete in a finite amount of time and the deadline
// of the passed context is expected to be honored. // of the passed context is expected to be honored.

View File

@ -35,8 +35,8 @@ func TestFloat64ObserverOptions(t *testing.T) {
got := NewFloat64ObserverConfig( got := NewFloat64ObserverConfig(
WithDescription(desc), WithDescription(desc),
WithUnit(uBytes), WithUnit(uBytes),
WithFloat64Callback(func(ctx context.Context, o Float64Observer) error { WithFloat64Callback(func(ctx context.Context, obsrv Float64Observer) error {
o.Observe(ctx, token) obsrv.Observe(token)
return nil return nil
}), }),
) )
@ -57,6 +57,6 @@ type float64Observer struct {
got float64 got float64
} }
func (o *float64Observer) Observe(_ context.Context, v float64, _ ...attribute.KeyValue) { func (o *float64Observer) Observe(v float64, _ ...attribute.KeyValue) {
o.got = v o.got = v
} }

View File

@ -21,46 +21,51 @@ import (
"go.opentelemetry.io/otel/metric/unit" "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. // Warning: methods may be added to this interface in minor releases.
type Int64Observer interface { type Int64Observable interface {
Asynchronous Asynchronous
// Observe records the measurement value for a set of attributes. int64Observable()
//
// 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)
} }
// Int64ObservableCounter is an instrument used to asynchronously record // Int64ObservableCounter is an instrument used to asynchronously record
// increasing int64 measurements once per a measurement collection cycle. The // increasing int64 measurements once per collection cycle. Observations are
// Observe method is used to record the measured state of the instrument when // only made within a callback for this instrument. The value observed is
// it is called. Implementations will assume the observed value to be the // assumed the to be the cumulative sum of the count.
// cumulative sum of the count.
// //
// Warning: methods may be added to this interface in minor releases. // 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 // Int64ObservableUpDownCounter is an instrument used to asynchronously record
// int64 measurements once per a measurement collection cycle. The Observe // int64 measurements once per collection cycle. Observations are only made
// method is used to record the measured state of the instrument when it is // within a callback for this instrument. The value observed is assumed the to
// called. Implementations will assume the observed value to be the cumulative // be the cumulative sum of the count.
// sum of the count.
// //
// Warning: methods may be added to this interface in minor releases. // 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 // 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. // Warning: methods may be added to this interface in minor releases.
type Int64ObservableGauge interface{ Int64Observer } type Int64ObservableGauge interface{ Int64Observable }
// Int64Observer is a recorder of int64 measurements.
//
// Warning: methods may be added to this interface in minor releases.
type Int64Observer interface {
Observe(value int64, attributes ...attribute.KeyValue)
}
// Int64Callback is a function registered with a Meter that makes // 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 // The function needs to complete in a finite amount of time and the deadline
// of the passed context is expected to be honored. // of the passed context is expected to be honored.

View File

@ -35,8 +35,8 @@ func TestInt64ObserverOptions(t *testing.T) {
got := NewInt64ObserverConfig( got := NewInt64ObserverConfig(
WithDescription(desc), WithDescription(desc),
WithUnit(uBytes), WithUnit(uBytes),
WithInt64Callback(func(ctx context.Context, o Int64Observer) error { WithInt64Callback(func(_ context.Context, obsrv Int64Observer) error {
o.Observe(ctx, token) obsrv.Observe(token)
return nil return nil
}), }),
) )
@ -57,6 +57,6 @@ type int64Observer struct {
got int64 got int64
} }
func (o *int64Observer) Observe(_ context.Context, v int64, _ ...attribute.KeyValue) { func (o *int64Observer) Observe(v int64, _ ...attribute.KeyValue) {
o.got = v o.got = v
} }

View File

@ -30,12 +30,12 @@ type unwrapper interface {
} }
type afCounter struct { type afCounter struct {
instrument.Float64Observable
name string name string
opts []instrument.Float64ObserverOption opts []instrument.Float64ObserverOption
delegate atomic.Value //instrument.Float64ObservableCounter delegate atomic.Value //instrument.Float64ObservableCounter
instrument.Asynchronous
} }
var _ unwrapper = (*afCounter)(nil) var _ unwrapper = (*afCounter)(nil)
@ -50,12 +50,6 @@ func (i *afCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *afCounter) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Float64ObservableCounter) return ctr.(instrument.Float64ObservableCounter)
@ -64,12 +58,12 @@ func (i *afCounter) Unwrap() instrument.Asynchronous {
} }
type afUpDownCounter struct { type afUpDownCounter struct {
instrument.Float64Observable
name string name string
opts []instrument.Float64ObserverOption opts []instrument.Float64ObserverOption
delegate atomic.Value //instrument.Float64ObservableUpDownCounter delegate atomic.Value //instrument.Float64ObservableUpDownCounter
instrument.Asynchronous
} }
var _ unwrapper = (*afUpDownCounter)(nil) var _ unwrapper = (*afUpDownCounter)(nil)
@ -84,12 +78,6 @@ func (i *afUpDownCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *afUpDownCounter) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Float64ObservableUpDownCounter) return ctr.(instrument.Float64ObservableUpDownCounter)
@ -98,14 +86,17 @@ func (i *afUpDownCounter) Unwrap() instrument.Asynchronous {
} }
type afGauge struct { type afGauge struct {
instrument.Float64Observable
name string name string
opts []instrument.Float64ObserverOption opts []instrument.Float64ObserverOption
delegate atomic.Value //instrument.Float64ObservableGauge delegate atomic.Value //instrument.Float64ObservableGauge
instrument.Asynchronous
} }
var _ unwrapper = (*afGauge)(nil)
var _ instrument.Float64ObservableGauge = (*afGauge)(nil)
func (i *afGauge) setDelegate(m metric.Meter) { func (i *afGauge) setDelegate(m metric.Meter) {
ctr, err := m.Float64ObservableGauge(i.name, i.opts...) ctr, err := m.Float64ObservableGauge(i.name, i.opts...)
if err != nil { if err != nil {
@ -115,15 +106,6 @@ func (i *afGauge) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *afGauge) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Float64ObservableGauge) return ctr.(instrument.Float64ObservableGauge)
@ -132,12 +114,12 @@ func (i *afGauge) Unwrap() instrument.Asynchronous {
} }
type aiCounter struct { type aiCounter struct {
instrument.Int64Observable
name string name string
opts []instrument.Int64ObserverOption opts []instrument.Int64ObserverOption
delegate atomic.Value //instrument.Int64ObservableCounter delegate atomic.Value //instrument.Int64ObservableCounter
instrument.Asynchronous
} }
var _ unwrapper = (*aiCounter)(nil) var _ unwrapper = (*aiCounter)(nil)
@ -152,12 +134,6 @@ func (i *aiCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *aiCounter) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Int64ObservableCounter) return ctr.(instrument.Int64ObservableCounter)
@ -166,12 +142,12 @@ func (i *aiCounter) Unwrap() instrument.Asynchronous {
} }
type aiUpDownCounter struct { type aiUpDownCounter struct {
instrument.Int64Observable
name string name string
opts []instrument.Int64ObserverOption opts []instrument.Int64ObserverOption
delegate atomic.Value //instrument.Int64ObservableUpDownCounter delegate atomic.Value //instrument.Int64ObservableUpDownCounter
instrument.Asynchronous
} }
var _ unwrapper = (*aiUpDownCounter)(nil) var _ unwrapper = (*aiUpDownCounter)(nil)
@ -186,12 +162,6 @@ func (i *aiUpDownCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *aiUpDownCounter) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Int64ObservableUpDownCounter) return ctr.(instrument.Int64ObservableUpDownCounter)
@ -200,12 +170,12 @@ func (i *aiUpDownCounter) Unwrap() instrument.Asynchronous {
} }
type aiGauge struct { type aiGauge struct {
instrument.Int64Observable
name string name string
opts []instrument.Int64ObserverOption opts []instrument.Int64ObserverOption
delegate atomic.Value //instrument.Int64ObservableGauge delegate atomic.Value //instrument.Int64ObservableGauge
instrument.Asynchronous
} }
var _ unwrapper = (*aiGauge)(nil) var _ unwrapper = (*aiGauge)(nil)
@ -220,12 +190,6 @@ func (i *aiGauge) setDelegate(m metric.Meter) {
i.delegate.Store(ctr) 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 { func (i *aiGauge) Unwrap() instrument.Asynchronous {
if ctr := i.delegate.Load(); ctr != nil { if ctr := i.delegate.Load(); ctr != nil {
return ctr.(instrument.Int64ObservableGauge) return ctr.(instrument.Int64ObservableGauge)

View File

@ -62,17 +62,20 @@ func TestAsyncInstrumentSetDelegateRace(t *testing.T) {
t.Run("Float64", func(t *testing.T) { t.Run("Float64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) { t.Run("Counter", func(t *testing.T) {
delegate := &afCounter{} 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) { t.Run("UpDownCounter", func(t *testing.T) {
delegate := &afUpDownCounter{} 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) { t.Run("Gauge", func(t *testing.T) {
delegate := &afGauge{} 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("Int64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) { t.Run("Counter", func(t *testing.T) {
delegate := &aiCounter{} 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) { t.Run("UpDownCounter", func(t *testing.T) {
delegate := &aiUpDownCounter{} 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) { t.Run("Gauge", func(t *testing.T) {
delegate := &aiGauge{} 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 { type testCountingFloatInstrument struct {
count int count int
instrument.Asynchronous instrument.Float64Observable
instrument.Synchronous instrument.Synchronous
} }
func (i *testCountingFloatInstrument) Observe(context.Context, float64, ...attribute.KeyValue) { func (i *testCountingFloatInstrument) observe() {
i.count++ i.count++
} }
func (i *testCountingFloatInstrument) Add(context.Context, float64, ...attribute.KeyValue) { func (i *testCountingFloatInstrument) Add(context.Context, float64, ...attribute.KeyValue) {
@ -155,11 +161,11 @@ func (i *testCountingFloatInstrument) Record(context.Context, float64, ...attrib
type testCountingIntInstrument struct { type testCountingIntInstrument struct {
count int count int
instrument.Asynchronous instrument.Int64Observable
instrument.Synchronous instrument.Synchronous
} }
func (i *testCountingIntInstrument) Observe(context.Context, int64, ...attribute.KeyValue) { func (i *testCountingIntInstrument) observe() {
i.count++ i.count++
} }
func (i *testCountingIntInstrument) Add(context.Context, int64, ...attribute.KeyValue) { func (i *testCountingIntInstrument) Add(context.Context, int64, ...attribute.KeyValue) {

View File

@ -148,10 +148,16 @@ type observationRecorder struct {
ctx context.Context ctx context.Context
} }
func (o observationRecorder) ObserveFloat64(i instrument.Float64Observer, value float64, attr ...attribute.KeyValue) { func (o observationRecorder) ObserveFloat64(i instrument.Float64Observable, value float64, attr ...attribute.KeyValue) {
i.Observe(o.ctx, value, attr...) iImpl, ok := i.(*testCountingFloatInstrument)
if ok {
iImpl.observe()
}
} }
func (o observationRecorder) ObserveInt64(i instrument.Int64Observer, value int64, attr ...attribute.KeyValue) { func (o observationRecorder) ObserveInt64(i instrument.Int64Observable, value int64, attr ...attribute.KeyValue) {
i.Observe(o.ctx, value, attr...) iImpl, ok := i.(*testCountingIntInstrument)
if ok {
iImpl.observe()
}
} }

View File

@ -123,9 +123,9 @@ type Callback func(context.Context, Observer) error
// Observer records measurements for multiple instruments in a Callback. // Observer records measurements for multiple instruments in a Callback.
type Observer interface { type Observer interface {
// ObserveFloat64 records the float64 value with attributes for obsrv. // 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 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 // Registration is an token representing the unique registration of a callback

View File

@ -97,7 +97,7 @@ type noopReg struct{}
func (noopReg) Unregister() error { return nil } func (noopReg) Unregister() error { return nil }
type nonrecordingAsyncFloat64Instrument struct { type nonrecordingAsyncFloat64Instrument struct {
instrument.Asynchronous instrument.Float64Observable
} }
var ( var (
@ -118,12 +118,8 @@ func (n nonrecordingAsyncFloat64Instrument) Gauge(string, ...instrument.Float64O
return n, nil return n, nil
} }
func (nonrecordingAsyncFloat64Instrument) Observe(context.Context, float64, ...attribute.KeyValue) {
}
type nonrecordingAsyncInt64Instrument struct { type nonrecordingAsyncInt64Instrument struct {
instrument.Asynchronous instrument.Int64Observable
} }
var ( var (
@ -144,9 +140,6 @@ func (n nonrecordingAsyncInt64Instrument) Gauge(string, ...instrument.Int64Obser
return n, nil return n, nil
} }
func (nonrecordingAsyncInt64Instrument) Observe(context.Context, int64, ...attribute.KeyValue) {
}
type nonrecordingSyncFloat64Instrument struct { type nonrecordingSyncFloat64Instrument struct {
instrument.Synchronous instrument.Synchronous
} }

View File

@ -72,45 +72,3 @@ func TestSyncInt64(t *testing.T) {
inst.Record(context.Background(), 1, attribute.String("key", "value")) 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"))
})
}

View File

@ -20,7 +20,6 @@ import (
"fmt" "fmt"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/metric/instrument" "go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/metric/unit" "go.opentelemetry.io/otel/metric/unit"
"go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/instrumentation"
@ -211,6 +210,36 @@ type observablID[N int64 | float64] struct {
scope instrumentation.Scope 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 { type observable[N int64 | float64] struct {
instrument.Asynchronous instrument.Asynchronous
observablID[N] 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. // observe records the val for the set of attrs.
func (o *observable[N]) observe(val N, attrs []attribute.KeyValue) { func (o *observable[N]) observe(val N, attrs []attribute.KeyValue) {
for _, agg := range o.aggregators { for _, agg := range o.aggregators {

View File

@ -232,7 +232,7 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...instrument.Asynchro
} }
switch o := inst.(type) { switch o := inst.(type) {
case *observable[int64]: case int64Observable:
if err := o.registerable(m.scope); err != nil { if err := o.registerable(m.scope); err != nil {
if !errors.Is(err, errEmptyAgg) { if !errors.Is(err, errEmptyAgg) {
errs.append(err) errs.append(err)
@ -240,7 +240,7 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...instrument.Asynchro
continue continue
} }
reg.registerInt64(o.observablID) reg.registerInt64(o.observablID)
case *observable[float64]: case float64Observable:
if err := o.registerable(m.scope); err != nil { if err := o.registerable(m.scope); err != nil {
if !errors.Is(err, errEmptyAgg) { if !errors.Is(err, errEmptyAgg) {
errs.append(err) errs.append(err)
@ -298,10 +298,10 @@ var (
errUnregObserver = errors.New("observable instrument not registered for callback") errUnregObserver = errors.New("observable instrument not registered for callback")
) )
func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...attribute.KeyValue) { func (r observer) ObserveFloat64(o instrument.Float64Observable, v float64, a ...attribute.KeyValue) {
var oImpl *observable[float64] var oImpl float64Observable
switch conv := o.(type) { switch conv := o.(type) {
case *observable[float64]: case float64Observable:
oImpl = conv oImpl = conv
case interface { case interface {
Unwrap() instrument.Asynchronous Unwrap() instrument.Asynchronous
@ -309,7 +309,7 @@ func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...a
// Unwrap any global. // Unwrap any global.
async := conv.Unwrap() async := conv.Unwrap()
var ok bool var ok bool
if oImpl, ok = async.(*observable[float64]); !ok { if oImpl, ok = async.(float64Observable); !ok {
global.Error(errUnknownObserver, "failed to record asynchronous") global.Error(errUnknownObserver, "failed to record asynchronous")
return return
} }
@ -330,10 +330,10 @@ func (r observer) ObserveFloat64(o instrument.Float64Observer, v float64, a ...a
oImpl.observe(v, a) oImpl.observe(v, a)
} }
func (r observer) ObserveInt64(o instrument.Int64Observer, v int64, a ...attribute.KeyValue) { func (r observer) ObserveInt64(o instrument.Int64Observable, v int64, a ...attribute.KeyValue) {
var oImpl *observable[int64] var oImpl int64Observable
switch conv := o.(type) { switch conv := o.(type) {
case *observable[int64]: case int64Observable:
oImpl = conv oImpl = conv
case interface { case interface {
Unwrap() instrument.Asynchronous Unwrap() instrument.Asynchronous
@ -341,7 +341,7 @@ func (r observer) ObserveInt64(o instrument.Int64Observer, v int64, a ...attribu
// Unwrap any global. // Unwrap any global.
async := conv.Unwrap() async := conv.Unwrap()
var ok bool var ok bool
if oImpl, ok = async.(*observable[int64]); !ok { if oImpl, ok = async.(int64Observable); !ok {
global.Error(errUnknownObserver, "failed to record asynchronous") global.Error(errUnknownObserver, "failed to record asynchronous")
return return
} }
@ -398,13 +398,13 @@ func (p *instProvider[N]) lookup(kind InstrumentKind, name, desc string, u unit.
type int64ObservProvider struct{ *instProvider[int64] } 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) 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) { func (p int64ObservProvider) registerCallbacks(inst int64Observable, cBacks []instrument.Int64Callback) {
if inst == nil { if inst.observable == nil || len(inst.aggregators) == 0 {
// Drop aggregator. // Drop aggregator.
return 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 { func (p int64ObservProvider) callback(i int64Observable, f instrument.Int64Callback) func(context.Context) error {
inst := callbackObserver[int64]{i} inst := int64Observer{i}
return func(ctx context.Context) error { return f(ctx, inst) } 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] } 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) 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) { func (p float64ObservProvider) registerCallbacks(inst float64Observable, cBacks []instrument.Float64Callback) {
if inst == nil { if inst.observable == nil || len(inst.aggregators) == 0 {
// Drop aggregator. // Drop aggregator.
return 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 { func (p float64ObservProvider) callback(i float64Observable, f instrument.Float64Callback) func(context.Context) error {
inst := callbackObserver[float64]{i} inst := float64Observer{i}
return func(ctx context.Context) error { return f(ctx, inst) } return func(ctx context.Context) error { return f(ctx, inst) }
} }
// callbackObserver is an observer that records values for a wrapped type float64Observer struct {
// observable. float64Observable
type callbackObserver[N int64 | float64] struct {
*observable[N]
} }
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) o.observe(val, attrs)
} }

View File

@ -179,8 +179,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableInt64Count", name: "ObservableInt64Count",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error { cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
ctr, err := m.Int64ObservableCounter("aint", instrument.WithInt64Callback(cback)) ctr, err := m.Int64ObservableCounter("aint", instrument.WithInt64Callback(cback))
@ -190,9 +190,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, ctr) }, ctr)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "aint", Name: "aint",
@ -209,8 +206,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableInt64UpDownCount", name: "ObservableInt64UpDownCount",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error { cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
ctr, err := m.Int64ObservableUpDownCounter("aint", instrument.WithInt64Callback(cback)) ctr, err := m.Int64ObservableUpDownCounter("aint", instrument.WithInt64Callback(cback))
@ -220,9 +217,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, ctr) }, ctr)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "aint", Name: "aint",
@ -239,8 +233,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableInt64Gauge", name: "ObservableInt64Gauge",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Int64Observer) error { cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
gauge, err := m.Int64ObservableGauge("agauge", instrument.WithInt64Callback(cback)) gauge, err := m.Int64ObservableGauge("agauge", instrument.WithInt64Callback(cback))
@ -250,9 +244,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, gauge) }, gauge)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
gauge.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "agauge", Name: "agauge",
@ -267,8 +258,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableFloat64Count", name: "ObservableFloat64Count",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error { cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
ctr, err := m.Float64ObservableCounter("afloat", instrument.WithFloat64Callback(cback)) ctr, err := m.Float64ObservableCounter("afloat", instrument.WithFloat64Callback(cback))
@ -278,9 +269,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, ctr) }, ctr)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "afloat", Name: "afloat",
@ -297,8 +285,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableFloat64UpDownCount", name: "ObservableFloat64UpDownCount",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error { cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
ctr, err := m.Float64ObservableUpDownCounter("afloat", instrument.WithFloat64Callback(cback)) ctr, err := m.Float64ObservableUpDownCounter("afloat", instrument.WithFloat64Callback(cback))
@ -308,9 +296,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, ctr) }, ctr)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
ctr.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "afloat", Name: "afloat",
@ -327,8 +312,8 @@ func TestMeterCreatesInstruments(t *testing.T) {
{ {
name: "ObservableFloat64Gauge", name: "ObservableFloat64Gauge",
fn: func(t *testing.T, m metric.Meter) { fn: func(t *testing.T, m metric.Meter) {
cback := func(ctx context.Context, o instrument.Float64Observer) error { cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(ctx, 4, attrs...) o.Observe(4, attrs...)
return nil return nil
} }
gauge, err := m.Float64ObservableGauge("agauge", instrument.WithFloat64Callback(cback)) gauge, err := m.Float64ObservableGauge("agauge", instrument.WithFloat64Callback(cback))
@ -338,9 +323,6 @@ func TestMeterCreatesInstruments(t *testing.T) {
return nil return nil
}, gauge) }, gauge)
assert.NoError(t, err) assert.NoError(t, err)
// Observed outside of a callback, it should be ignored.
gauge.Observe(context.Background(), 19)
}, },
want: metricdata.Metrics{ want: metricdata.Metrics{
Name: "agauge", Name: "agauge",
@ -564,10 +546,9 @@ func TestCallbackObserverNonRegistered(t *testing.T) {
fCtr, err := m2.Float64ObservableCounter("float64 ctr") fCtr, err := m2.Float64ObservableCounter("float64 ctr")
require.NoError(t, err) require.NoError(t, err)
// Panics if Observe is called. type int64Obsrv struct{ instrument.Int64Observable }
type int64Obsrv struct{ instrument.Int64Observer }
int64Foreign := int64Obsrv{} int64Foreign := int64Obsrv{}
type float64Obsrv struct{ instrument.Float64Observer } type float64Obsrv struct{ instrument.Float64Observable }
float64Foreign := float64Obsrv{} float64Foreign := float64Obsrv{}
_, err = m1.RegisterCallback( _, err = m1.RegisterCallback(
@ -1311,9 +1292,9 @@ func TestAsynchronousExample(t *testing.T) {
observations := make(map[attribute.Set]int64) observations := make(map[attribute.Set]int64)
_, err := meter.Int64ObservableCounter(instName, instrument.WithInt64Callback( _, 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 { for attrSet, val := range observations {
o.Observe(ctx, val, attrSet.ToSlice()...) o.Observe(val, attrSet.ToSlice()...)
} }
return nil return nil
}, },