diff --git a/api/global/global_test.go b/api/global/global_test.go index 3265c1d2b..974077aa6 100644 --- a/api/global/global_test.go +++ b/api/global/global_test.go @@ -37,7 +37,7 @@ func (*testTraceProvider) Tracer(_ string) trace.Tracer { } func (*testMeterProvider) Meter(_ string) metric.Meter { - return &metric.NoopMeter{} + return metric.Meter{} } func TestMultipleGlobalTracerProvider(t *testing.T) { diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index f744331e7..df75d3ae0 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -49,22 +49,27 @@ import ( type meterProvider struct { delegate metric.Provider - lock sync.Mutex - meters map[string]*meter + // lock protects `delegate` and `meters`. + lock sync.Mutex + + // meters maintains a unique entry for every named Meter + // that has been registered through the global instance. + meters map[string]*meterEntry } -type meter struct { - delegate unsafe.Pointer // (*metric.Meter) - - provider *meterProvider - name string +type meterImpl struct { + delegate unsafe.Pointer // (*metric.MeterImpl) lock sync.Mutex - registry map[string]metric.InstrumentImpl syncInsts []*syncImpl asyncInsts []*asyncImpl } +type meterEntry struct { + unique metric.MeterImpl + impl meterImpl +} + type instrument struct { descriptor metric.Descriptor } @@ -73,8 +78,6 @@ type syncImpl struct { delegate unsafe.Pointer // (*metric.SyncImpl) instrument - - constructor func(metric.Meter) (metric.SyncImpl, error) } type asyncImpl struct { @@ -82,7 +85,7 @@ type asyncImpl struct { instrument - constructor func(metric.Meter) (metric.AsyncImpl, error) + callback func(func(metric.Number, []core.KeyValue)) } // SyncImpler is implemented by all of the sync metric @@ -107,7 +110,7 @@ type syncHandle struct { } var _ metric.Provider = &meterProvider{} -var _ metric.Meter = &meter{} +var _ metric.MeterImpl = &meterImpl{} var _ metric.InstrumentImpl = &syncImpl{} var _ metric.BoundSyncImpl = &syncHandle{} var _ metric.AsyncImpl = &asyncImpl{} @@ -120,7 +123,7 @@ func (inst *instrument) Descriptor() metric.Descriptor { func newMeterProvider() *meterProvider { return &meterProvider{ - meters: map[string]*meter{}, + meters: map[string]*meterEntry{}, } } @@ -129,8 +132,8 @@ func (p *meterProvider) setDelegate(provider metric.Provider) { defer p.lock.Unlock() p.delegate = provider - for _, m := range p.meters { - m.setDelegate(provider) + for name, entry := range p.meters { + entry.impl.setDelegate(name, provider) } p.meters = nil } @@ -143,29 +146,24 @@ func (p *meterProvider) Meter(name string) metric.Meter { return p.delegate.Meter(name) } - if exm, ok := p.meters[name]; ok { - return exm - } + entry, ok := p.meters[name] + if !ok { + entry = &meterEntry{} + entry.unique = registry.NewUniqueInstrumentMeterImpl(&entry.impl) + p.meters[name] = entry - m := &meter{ - provider: p, - name: name, - registry: map[string]metric.InstrumentImpl{}, - syncInsts: []*syncImpl{}, - asyncInsts: []*asyncImpl{}, } - p.meters[name] = m - return m + return metric.WrapMeterImpl(entry.unique, name) } // Meter interface and delegation -func (m *meter) setDelegate(provider metric.Provider) { +func (m *meterImpl) setDelegate(name string, provider metric.Provider) { m.lock.Lock() defer m.lock.Unlock() - d := new(metric.Meter) - *d = provider.Meter(m.name) + d := new(metric.MeterImpl) + *d = provider.Meter(name).MeterImpl() m.delegate = unsafe.Pointer(d) for _, inst := range m.syncInsts { @@ -178,49 +176,30 @@ func (m *meter) setDelegate(provider metric.Provider) { m.asyncInsts = nil } -func (m *meter) newSync(desc metric.Descriptor, constructor func(metric.Meter) (metric.SyncImpl, error)) (metric.SyncImpl, error) { +func (m *meterImpl) NewSyncInstrument(desc metric.Descriptor) (metric.SyncImpl, error) { m.lock.Lock() defer m.lock.Unlock() - if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return constructor(*meterPtr) - } - - if ex, ok := m.registry[desc.Name()]; ok { - if !registry.Compatible(desc, ex.Descriptor()) { - return nil, registry.NewMetricKindMismatchError(ex.Descriptor()) - } - return ex.(metric.SyncImpl), nil + if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return (*meterPtr).NewSyncInstrument(desc) } inst := &syncImpl{ instrument: instrument{ descriptor: desc, }, - constructor: constructor, } m.syncInsts = append(m.syncInsts, inst) - m.registry[desc.Name()] = inst return inst, nil } -func syncCheck(has SyncImpler, err error) (metric.SyncImpl, error) { - if has != nil { - return has.SyncImpl(), err - } - if err == nil { - err = metric.ErrSDKReturnedNilImpl - } - return nil, err -} - // Synchronous delegation -func (inst *syncImpl) setDelegate(d metric.Meter) { +func (inst *syncImpl) setDelegate(d metric.MeterImpl) { implPtr := new(metric.SyncImpl) var err error - *implPtr, err = inst.constructor(d) + *implPtr, err = d.NewSyncInstrument(inst.descriptor) if err != nil { // TODO: There is no standard way to deliver this error to the user. @@ -264,29 +243,25 @@ func (bound *syncHandle) Unbind() { // Async delegation -func (m *meter) newAsync(desc metric.Descriptor, constructor func(metric.Meter) (metric.AsyncImpl, error)) (metric.AsyncImpl, error) { +func (m *meterImpl) NewAsyncInstrument( + desc metric.Descriptor, + callback func(func(metric.Number, []core.KeyValue)), +) (metric.AsyncImpl, error) { + m.lock.Lock() defer m.lock.Unlock() - if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return constructor(*meterPtr) - } - - if ex, ok := m.registry[desc.Name()]; ok { - if !registry.Compatible(desc, ex.Descriptor()) { - return nil, registry.NewMetricKindMismatchError(ex.Descriptor()) - } - return ex.(metric.AsyncImpl), nil + if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return (*meterPtr).NewAsyncInstrument(desc, callback) } inst := &asyncImpl{ instrument: instrument{ descriptor: desc, }, - constructor: constructor, + callback: callback, } m.asyncInsts = append(m.asyncInsts, inst) - m.registry[desc.Name()] = inst return inst, nil } @@ -297,21 +272,11 @@ func (obs *asyncImpl) Implementation() interface{} { return obs } -func asyncCheck(has AsyncImpler, err error) (metric.AsyncImpl, error) { - if has != nil { - return has.AsyncImpl(), err - } - if err == nil { - err = metric.ErrSDKReturnedNilImpl - } - return nil, err -} - -func (obs *asyncImpl) setDelegate(d metric.Meter) { +func (obs *asyncImpl) setDelegate(d metric.MeterImpl) { implPtr := new(metric.AsyncImpl) var err error - *implPtr, err = obs.constructor(d) + *implPtr, err = d.NewAsyncInstrument(obs.descriptor, obs.callback) if err != nil { // TODO: There is no standard way to deliver this error to the user. @@ -326,8 +291,8 @@ func (obs *asyncImpl) setDelegate(d metric.Meter) { // Metric updates -func (m *meter) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) { - if delegatePtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { +func (m *meterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) { + if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { (*delegatePtr).RecordBatch(ctx, labels, measurements...) } } @@ -363,64 +328,10 @@ func (bound *syncHandle) RecordOne(ctx context.Context, number metric.Number) { (*implPtr).RecordOne(ctx, number) } -// Constructors - -func (m *meter) withName(opts []metric.Option) []metric.Option { - return append(opts, metric.WithLibraryName(m.name)) -} - -func (m *meter) NewInt64Counter(name string, opts ...metric.Option) (metric.Int64Counter, error) { - return metric.WrapInt64CounterInstrument(m.newSync( - metric.NewDescriptor(name, metric.CounterKind, metric.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewInt64Counter(name, opts...)) - })) -} - -func (m *meter) NewFloat64Counter(name string, opts ...metric.Option) (metric.Float64Counter, error) { - return metric.WrapFloat64CounterInstrument(m.newSync( - metric.NewDescriptor(name, metric.CounterKind, metric.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewFloat64Counter(name, opts...)) - })) -} - -func (m *meter) NewInt64Measure(name string, opts ...metric.Option) (metric.Int64Measure, error) { - return metric.WrapInt64MeasureInstrument(m.newSync( - metric.NewDescriptor(name, metric.MeasureKind, metric.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewInt64Measure(name, opts...)) - })) -} - -func (m *meter) NewFloat64Measure(name string, opts ...metric.Option) (metric.Float64Measure, error) { - return metric.WrapFloat64MeasureInstrument(m.newSync( - metric.NewDescriptor(name, metric.MeasureKind, metric.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewFloat64Measure(name, opts...)) - })) -} - -func (m *meter) RegisterInt64Observer(name string, callback metric.Int64ObserverCallback, opts ...metric.Option) (metric.Int64Observer, error) { - return metric.WrapInt64ObserverInstrument(m.newAsync( - metric.NewDescriptor(name, metric.ObserverKind, metric.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.AsyncImpl, error) { - return asyncCheck(other.RegisterInt64Observer(name, callback, opts...)) - })) -} - -func (m *meter) RegisterFloat64Observer(name string, callback metric.Float64ObserverCallback, opts ...metric.Option) (metric.Float64Observer, error) { - return metric.WrapFloat64ObserverInstrument(m.newAsync( - metric.NewDescriptor(name, metric.ObserverKind, metric.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.AsyncImpl, error) { - return asyncCheck(other.RegisterFloat64Observer(name, callback, opts...)) - })) -} - func AtomicFieldOffsets() map[string]uintptr { return map[string]uintptr{ "meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate), - "meter.delegate": unsafe.Offsetof(meter{}.delegate), + "meterImpl.delegate": unsafe.Offsetof(meterImpl{}.delegate), "syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate), "asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate), "syncHandle.delegate": unsafe.Offsetof(syncHandle{}.delegate), diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 9862a60eb..41066689d 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -280,15 +280,15 @@ type meterProviderWithConstructorError struct { } type meterWithConstructorError struct { - metric.Meter + metric.MeterImpl } func (m *meterProviderWithConstructorError) Meter(name string) metric.Meter { - return &meterWithConstructorError{m.Provider.Meter(name)} + return metric.WrapMeterImpl(&meterWithConstructorError{m.Provider.Meter(name).MeterImpl()}, name) } -func (m *meterWithConstructorError) NewInt64Counter(name string, opts ...metric.Option) (metric.Int64Counter, error) { - return metric.Int64Counter{}, errors.New("constructor error") +func (m *meterWithConstructorError) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) { + return metric.NoopSync{}, errors.New("constructor error") } func TestErrorInDeferredConstructor(t *testing.T) { diff --git a/api/metric/api.go b/api/metric/api.go index 5580a14f5..d932a764f 100644 --- a/api/metric/api.go +++ b/api/metric/api.go @@ -135,38 +135,99 @@ func (d Descriptor) LibraryName() string { return d.config.LibraryName } -// Meter is an interface to the metrics portion of the OpenTelemetry SDK. -type Meter interface { - // RecordBatch atomically records a batch of measurements. - RecordBatch(context.Context, []core.KeyValue, ...Measurement) +// Meter is the OpenTelemetry metric API, based on a `MeterImpl` +// implementation and the `Meter` library name. +// +// An uninitialized Meter is a no-op implementation. +type Meter struct { + impl MeterImpl + libraryName string +} - // All instrument constructors may return an error for - // conditions such as: - // `name` is an empty string - // `name` was previously registered as a different kind of instrument - // for a given named `Meter`. +// RecordBatch atomically records a batch of measurements. +func (m Meter) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) { + if m.impl == nil { + return + } + m.impl.RecordBatch(ctx, ls, ms...) +} - // NewInt64Counter creates a new integral counter with a given - // name and customized with passed options. - NewInt64Counter(name string, opts ...Option) (Int64Counter, error) - // NewFloat64Counter creates a new floating point counter with - // a given name and customized with passed options. - NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) - // NewInt64Measure creates a new integral measure with a given - // name and customized with passed options. - NewInt64Measure(name string, opts ...Option) (Int64Measure, error) - // NewFloat64Measure creates a new floating point measure with - // a given name and customized with passed options. - NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) +// NewInt64Counter creates a new integer Counter instrument with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewInt64Counter(name string, options ...Option) (Int64Counter, error) { + return wrapInt64CounterInstrument( + m.newSync(name, CounterKind, Int64NumberKind, options)) +} - // RegisterInt64Observer creates a new integral observer with a - // given name, running a given callback, and customized with passed - // options. Callback may be nil. - RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) - // RegisterFloat64Observer creates a new floating point observer - // with a given name, running a given callback, and customized with - // passed options. Callback may be nil. - RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) +// NewFloat64Counter creates a new floating point Counter with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewFloat64Counter(name string, options ...Option) (Float64Counter, error) { + return wrapFloat64CounterInstrument( + m.newSync(name, CounterKind, Float64NumberKind, options)) +} + +// NewInt64Measure creates a new integer Measure instrument with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { + return wrapInt64MeasureInstrument( + m.newSync(name, MeasureKind, Int64NumberKind, opts)) +} + +// NewFloat64Measure creates a new floating point Measure with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { + return wrapFloat64MeasureInstrument( + m.newSync(name, MeasureKind, Float64NumberKind, opts)) +} + +// RegisterInt64Observer creates a new integer Observer instrument +// with the given name, running a given callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (m Meter) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { + if callback == nil { + return wrapInt64ObserverInstrument(NoopAsync{}, nil) + } + return wrapInt64ObserverInstrument( + m.newAsync(name, ObserverKind, Int64NumberKind, opts, + func(observe func(Number, []core.KeyValue)) { + callback(Int64ObserverResult{observe}) + })) +} + +// RegisterFloat64Observer creates a new floating point Observer with +// the given name, running a given callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (m Meter) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { + if callback == nil { + return wrapFloat64ObserverInstrument(NoopAsync{}, nil) + } + return wrapFloat64ObserverInstrument( + m.newAsync(name, ObserverKind, Float64NumberKind, opts, + func(observe func(Number, []core.KeyValue)) { + callback(Float64ObserverResult{observe}) + })) +} + +// Observe captures a single integer value from the associated +// instrument callback, with the given labels. +func (io Int64ObserverResult) Observe(value int64, labels ...core.KeyValue) { + io.observe(NewInt64Number(value), labels) +} + +// Observe captures a single floating point value from the associated +// instrument callback, with the given labels. +func (fo Float64ObserverResult) Observe(value float64, labels ...core.KeyValue) { + fo.observe(NewFloat64Number(value), labels) } // WithDescription applies provided description. diff --git a/api/metric/noop.go b/api/metric/noop.go index 2a74ba635..74dd53268 100644 --- a/api/metric/noop.go +++ b/api/metric/noop.go @@ -21,7 +21,6 @@ import ( ) type NoopProvider struct{} -type NoopMeter struct{} type noopInstrument struct{} type noopBoundInstrument struct{} @@ -29,13 +28,12 @@ type NoopSync struct{ noopInstrument } type NoopAsync struct{ noopInstrument } var _ Provider = NoopProvider{} -var _ Meter = NoopMeter{} var _ SyncImpl = NoopSync{} var _ BoundSyncImpl = noopBoundInstrument{} var _ AsyncImpl = NoopAsync{} func (NoopProvider) Meter(name string) Meter { - return NoopMeter{} + return Meter{} } func (noopInstrument) Implementation() interface{} { @@ -58,30 +56,3 @@ func (NoopSync) Bind([]core.KeyValue) BoundSyncImpl { func (NoopSync) RecordOne(context.Context, Number, []core.KeyValue) { } - -func (NoopMeter) RecordBatch(context.Context, []core.KeyValue, ...Measurement) { -} - -func (NoopMeter) NewInt64Counter(string, ...Option) (Int64Counter, error) { - return Int64Counter{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewFloat64Counter(string, ...Option) (Float64Counter, error) { - return Float64Counter{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewInt64Measure(string, ...Option) (Int64Measure, error) { - return Int64Measure{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewFloat64Measure(string, ...Option) (Float64Measure, error) { - return Float64Measure{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) RegisterInt64Observer(string, Int64ObserverCallback, ...Option) (Int64Observer, error) { - return Int64Observer{asyncInstrument{NoopAsync{}}}, nil -} - -func (NoopMeter) RegisterFloat64Observer(string, Float64ObserverCallback, ...Option) (Float64Observer, error) { - return Float64Observer{asyncInstrument{NoopAsync{}}}, nil -} diff --git a/api/metric/observer.go b/api/metric/observer.go index 0ad9421a4..e4b5b47c8 100644 --- a/api/metric/observer.go +++ b/api/metric/observer.go @@ -14,20 +14,6 @@ package metric -import "go.opentelemetry.io/otel/api/core" - -// Int64ObserverResult is an interface for reporting integral -// observations. -type Int64ObserverResult interface { - Observe(value int64, labels ...core.KeyValue) -} - -// Float64ObserverResult is an interface for reporting floating point -// observations. -type Float64ObserverResult interface { - Observe(value float64, labels ...core.KeyValue) -} - // Int64ObserverCallback is a type of callback that integral // observers run. type Int64ObserverCallback func(result Int64ObserverResult) diff --git a/api/metric/sdkhelpers.go b/api/metric/sdkhelpers.go index 231ad4fdc..ad881235f 100644 --- a/api/metric/sdkhelpers.go +++ b/api/metric/sdkhelpers.go @@ -20,10 +20,8 @@ import ( "go.opentelemetry.io/otel/api/core" ) -// MeterImpl is a convenient interface for SDK and test -// implementations that would provide a `Meter` but do not wish to -// re-implement the API's type-safe interfaces. Helpers provided in -// this package will construct a `Meter` given a `MeterImpl`. +// MeterImpl is the interface an SDK must implement to supply a Meter +// implementation. type MeterImpl interface { // RecordBatch atomically records a batch of measurements. RecordBatch(context.Context, []core.KeyValue, ...Measurement) @@ -83,35 +81,20 @@ type BoundSyncImpl interface { // asynchronous instrument (e.g., Observer instruments). type AsyncImpl interface { InstrumentImpl - - // Note: An `Unregister()` API could be supported here. } -// wrappedMeterImpl implements the `Meter` interface given a -// `MeterImpl` implementation. -type wrappedMeterImpl struct { - impl MeterImpl - libraryName string -} - -// int64ObserverResult is an adapter for int64-valued asynchronous -// callbacks. -type int64ObserverResult struct { +// Int64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous integer metric instrument. +type Int64ObserverResult struct { observe func(Number, []core.KeyValue) } -// float64ObserverResult is an adapter for float64-valued asynchronous -// callbacks. -type float64ObserverResult struct { +// Float64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous floating point metric instrument. +type Float64ObserverResult struct { observe func(Number, []core.KeyValue) } -var ( - _ Meter = (*wrappedMeterImpl)(nil) - _ Int64ObserverResult = int64ObserverResult{} - _ Float64ObserverResult = float64ObserverResult{} -) - // Configure is a helper that applies all the options to a Config. func Configure(opts []Option) Config { var config Config @@ -124,131 +107,87 @@ func Configure(opts []Option) Config { // WrapMeterImpl constructs a `Meter` implementation from a // `MeterImpl` implementation. func WrapMeterImpl(impl MeterImpl, libraryName string) Meter { - return &wrappedMeterImpl{ + return Meter{ impl: impl, libraryName: libraryName, } } -func (m *wrappedMeterImpl) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) { - m.impl.RecordBatch(ctx, ls, ms...) +// MeterImpl returns the underlying MeterImpl of this Meter. +func (m Meter) MeterImpl() MeterImpl { + return m.impl } -func (m *wrappedMeterImpl) newSync(name string, metricKind Kind, numberKind NumberKind, opts []Option) (SyncImpl, error) { +// newSync constructs one new synchronous instrument. +func (m Meter) newSync(name string, metricKind Kind, numberKind NumberKind, opts []Option) (SyncImpl, error) { + if m.impl == nil { + return NoopSync{}, nil + } desc := NewDescriptor(name, metricKind, numberKind, opts...) desc.config.LibraryName = m.libraryName return m.impl.NewSyncInstrument(desc) } -func (m *wrappedMeterImpl) NewInt64Counter(name string, opts ...Option) (Int64Counter, error) { - return WrapInt64CounterInstrument( - m.newSync(name, CounterKind, Int64NumberKind, opts)) -} - -// WrapInt64CounterInstrument returns an `Int64Counter` from a +// wrapInt64CounterInstrument returns an `Int64Counter` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { +func wrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { common, err := checkNewSync(syncInst, err) return Int64Counter{syncInstrument: common}, err } -func (m *wrappedMeterImpl) NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) { - return WrapFloat64CounterInstrument( - m.newSync(name, CounterKind, Float64NumberKind, opts)) -} - -// WrapFloat64CounterInstrument returns an `Float64Counter` from a +// wrapFloat64CounterInstrument returns an `Float64Counter` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { +func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { common, err := checkNewSync(syncInst, err) return Float64Counter{syncInstrument: common}, err } -func (m *wrappedMeterImpl) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { - return WrapInt64MeasureInstrument( - m.newSync(name, MeasureKind, Int64NumberKind, opts)) -} - -// WrapInt64MeasureInstrument returns an `Int64Measure` from a +// wrapInt64MeasureInstrument returns an `Int64Measure` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapInt64MeasureInstrument(syncInst SyncImpl, err error) (Int64Measure, error) { +func wrapInt64MeasureInstrument(syncInst SyncImpl, err error) (Int64Measure, error) { common, err := checkNewSync(syncInst, err) return Int64Measure{syncInstrument: common}, err } -func (m *wrappedMeterImpl) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { - return WrapFloat64MeasureInstrument( - m.newSync(name, MeasureKind, Float64NumberKind, opts)) -} - -// WrapFloat64MeasureInstrument returns an `Float64Measure` from a +// wrapFloat64MeasureInstrument returns an `Float64Measure` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure, error) { +func wrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure, error) { common, err := checkNewSync(syncInst, err) return Float64Measure{syncInstrument: common}, err } -func (m *wrappedMeterImpl) newAsync(name string, mkind Kind, nkind NumberKind, opts []Option, callback func(func(Number, []core.KeyValue))) (AsyncImpl, error) { +// newAsync constructs one new asynchronous instrument. +func (m Meter) newAsync(name string, mkind Kind, nkind NumberKind, opts []Option, callback func(func(Number, []core.KeyValue))) (AsyncImpl, error) { + if m.impl == nil { + return NoopAsync{}, nil + } desc := NewDescriptor(name, mkind, nkind, opts...) desc.config.LibraryName = m.libraryName return m.impl.NewAsyncInstrument(desc, callback) } -func (m *wrappedMeterImpl) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { - if callback == nil { - return NoopMeter{}.RegisterInt64Observer("", nil) - } - return WrapInt64ObserverInstrument( - m.newAsync(name, ObserverKind, Int64NumberKind, opts, - func(observe func(Number, []core.KeyValue)) { - // Note: this memory allocation could be avoided by - // using a pointer to this object and mutating it - // on each collection interval. - callback(int64ObserverResult{observe}) - })) -} - -// WrapInt64ObserverInstrument returns an `Int64Observer` from a +// wrapInt64ObserverInstrument returns an `Int64Observer` from a // `AsyncImpl`. An error will be generated if the // `AsyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapInt64ObserverInstrument(asyncInst AsyncImpl, err error) (Int64Observer, error) { +func wrapInt64ObserverInstrument(asyncInst AsyncImpl, err error) (Int64Observer, error) { common, err := checkNewAsync(asyncInst, err) return Int64Observer{asyncInstrument: common}, err } -func (m *wrappedMeterImpl) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { - if callback == nil { - return NoopMeter{}.RegisterFloat64Observer("", nil) - } - return WrapFloat64ObserverInstrument( - m.newAsync(name, ObserverKind, Float64NumberKind, opts, - func(observe func(Number, []core.KeyValue)) { - callback(float64ObserverResult{observe}) - })) -} - -// WrapFloat64ObserverInstrument returns an `Float64Observer` from a +// wrapFloat64ObserverInstrument returns an `Float64Observer` from a // `AsyncImpl`. An error will be generated if the // `AsyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func WrapFloat64ObserverInstrument(asyncInst AsyncImpl, err error) (Float64Observer, error) { +func wrapFloat64ObserverInstrument(asyncInst AsyncImpl, err error) (Float64Observer, error) { common, err := checkNewAsync(asyncInst, err) return Float64Observer{asyncInstrument: common}, err } - -func (io int64ObserverResult) Observe(value int64, labels ...core.KeyValue) { - io.observe(NewInt64Number(value), labels) -} - -func (fo float64ObserverResult) Observe(value float64, labels ...core.KeyValue) { - fo.observe(NewFloat64Number(value), labels) -}