1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-12-16 00:11:27 +02:00

Make Meter a struct, simplify the global Meter (#709)

* Tests pass

* Precommit pass

* More lint

* Remove a few interfaces

* Final edits

* Fix comments

* Indentation

* registry->unique

* Comments
This commit is contained in:
Joshua MacDonald
2020-05-11 20:29:06 -07:00
committed by GitHub
parent 64afb05e53
commit 32ddc16e1b
7 changed files with 175 additions and 307 deletions

View File

@@ -37,7 +37,7 @@ func (*testTraceProvider) Tracer(_ string) trace.Tracer {
} }
func (*testMeterProvider) Meter(_ string) metric.Meter { func (*testMeterProvider) Meter(_ string) metric.Meter {
return &metric.NoopMeter{} return metric.Meter{}
} }
func TestMultipleGlobalTracerProvider(t *testing.T) { func TestMultipleGlobalTracerProvider(t *testing.T) {

View File

@@ -49,22 +49,27 @@ import (
type meterProvider struct { type meterProvider struct {
delegate metric.Provider delegate metric.Provider
// lock protects `delegate` and `meters`.
lock sync.Mutex lock sync.Mutex
meters map[string]*meter
// meters maintains a unique entry for every named Meter
// that has been registered through the global instance.
meters map[string]*meterEntry
} }
type meter struct { type meterImpl struct {
delegate unsafe.Pointer // (*metric.Meter) delegate unsafe.Pointer // (*metric.MeterImpl)
provider *meterProvider
name string
lock sync.Mutex lock sync.Mutex
registry map[string]metric.InstrumentImpl
syncInsts []*syncImpl syncInsts []*syncImpl
asyncInsts []*asyncImpl asyncInsts []*asyncImpl
} }
type meterEntry struct {
unique metric.MeterImpl
impl meterImpl
}
type instrument struct { type instrument struct {
descriptor metric.Descriptor descriptor metric.Descriptor
} }
@@ -73,8 +78,6 @@ type syncImpl struct {
delegate unsafe.Pointer // (*metric.SyncImpl) delegate unsafe.Pointer // (*metric.SyncImpl)
instrument instrument
constructor func(metric.Meter) (metric.SyncImpl, error)
} }
type asyncImpl struct { type asyncImpl struct {
@@ -82,7 +85,7 @@ type asyncImpl struct {
instrument instrument
constructor func(metric.Meter) (metric.AsyncImpl, error) callback func(func(metric.Number, []core.KeyValue))
} }
// SyncImpler is implemented by all of the sync metric // SyncImpler is implemented by all of the sync metric
@@ -107,7 +110,7 @@ type syncHandle struct {
} }
var _ metric.Provider = &meterProvider{} var _ metric.Provider = &meterProvider{}
var _ metric.Meter = &meter{} var _ metric.MeterImpl = &meterImpl{}
var _ metric.InstrumentImpl = &syncImpl{} var _ metric.InstrumentImpl = &syncImpl{}
var _ metric.BoundSyncImpl = &syncHandle{} var _ metric.BoundSyncImpl = &syncHandle{}
var _ metric.AsyncImpl = &asyncImpl{} var _ metric.AsyncImpl = &asyncImpl{}
@@ -120,7 +123,7 @@ func (inst *instrument) Descriptor() metric.Descriptor {
func newMeterProvider() *meterProvider { func newMeterProvider() *meterProvider {
return &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() defer p.lock.Unlock()
p.delegate = provider p.delegate = provider
for _, m := range p.meters { for name, entry := range p.meters {
m.setDelegate(provider) entry.impl.setDelegate(name, provider)
} }
p.meters = nil p.meters = nil
} }
@@ -143,29 +146,24 @@ func (p *meterProvider) Meter(name string) metric.Meter {
return p.delegate.Meter(name) return p.delegate.Meter(name)
} }
if exm, ok := p.meters[name]; ok { entry, ok := p.meters[name]
return exm 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 metric.WrapMeterImpl(entry.unique, name)
return m
} }
// Meter interface and delegation // Meter interface and delegation
func (m *meter) setDelegate(provider metric.Provider) { func (m *meterImpl) setDelegate(name string, provider metric.Provider) {
m.lock.Lock() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
d := new(metric.Meter) d := new(metric.MeterImpl)
*d = provider.Meter(m.name) *d = provider.Meter(name).MeterImpl()
m.delegate = unsafe.Pointer(d) m.delegate = unsafe.Pointer(d)
for _, inst := range m.syncInsts { for _, inst := range m.syncInsts {
@@ -178,49 +176,30 @@ func (m *meter) setDelegate(provider metric.Provider) {
m.asyncInsts = nil 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() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil {
return constructor(*meterPtr) return (*meterPtr).NewSyncInstrument(desc)
}
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
} }
inst := &syncImpl{ inst := &syncImpl{
instrument: instrument{ instrument: instrument{
descriptor: desc, descriptor: desc,
}, },
constructor: constructor,
} }
m.syncInsts = append(m.syncInsts, inst) m.syncInsts = append(m.syncInsts, inst)
m.registry[desc.Name()] = inst
return inst, nil 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 // Synchronous delegation
func (inst *syncImpl) setDelegate(d metric.Meter) { func (inst *syncImpl) setDelegate(d metric.MeterImpl) {
implPtr := new(metric.SyncImpl) implPtr := new(metric.SyncImpl)
var err error var err error
*implPtr, err = inst.constructor(d) *implPtr, err = d.NewSyncInstrument(inst.descriptor)
if err != nil { if err != nil {
// TODO: There is no standard way to deliver this error to the user. // TODO: There is no standard way to deliver this error to the user.
@@ -264,29 +243,25 @@ func (bound *syncHandle) Unbind() {
// Async delegation // 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() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil {
return constructor(*meterPtr) return (*meterPtr).NewAsyncInstrument(desc, callback)
}
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
} }
inst := &asyncImpl{ inst := &asyncImpl{
instrument: instrument{ instrument: instrument{
descriptor: desc, descriptor: desc,
}, },
constructor: constructor, callback: callback,
} }
m.asyncInsts = append(m.asyncInsts, inst) m.asyncInsts = append(m.asyncInsts, inst)
m.registry[desc.Name()] = inst
return inst, nil return inst, nil
} }
@@ -297,21 +272,11 @@ func (obs *asyncImpl) Implementation() interface{} {
return obs return obs
} }
func asyncCheck(has AsyncImpler, err error) (metric.AsyncImpl, error) { func (obs *asyncImpl) setDelegate(d metric.MeterImpl) {
if has != nil {
return has.AsyncImpl(), err
}
if err == nil {
err = metric.ErrSDKReturnedNilImpl
}
return nil, err
}
func (obs *asyncImpl) setDelegate(d metric.Meter) {
implPtr := new(metric.AsyncImpl) implPtr := new(metric.AsyncImpl)
var err error var err error
*implPtr, err = obs.constructor(d) *implPtr, err = d.NewAsyncInstrument(obs.descriptor, obs.callback)
if err != nil { if err != nil {
// TODO: There is no standard way to deliver this error to the user. // 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 // Metric updates
func (m *meter) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) { func (m *meterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) {
if delegatePtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil {
(*delegatePtr).RecordBatch(ctx, labels, measurements...) (*delegatePtr).RecordBatch(ctx, labels, measurements...)
} }
} }
@@ -363,64 +328,10 @@ func (bound *syncHandle) RecordOne(ctx context.Context, number metric.Number) {
(*implPtr).RecordOne(ctx, 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 { func AtomicFieldOffsets() map[string]uintptr {
return map[string]uintptr{ return map[string]uintptr{
"meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate), "meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate),
"meter.delegate": unsafe.Offsetof(meter{}.delegate), "meterImpl.delegate": unsafe.Offsetof(meterImpl{}.delegate),
"syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate), "syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate),
"asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate), "asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate),
"syncHandle.delegate": unsafe.Offsetof(syncHandle{}.delegate), "syncHandle.delegate": unsafe.Offsetof(syncHandle{}.delegate),

View File

@@ -280,15 +280,15 @@ type meterProviderWithConstructorError struct {
} }
type meterWithConstructorError struct { type meterWithConstructorError struct {
metric.Meter metric.MeterImpl
} }
func (m *meterProviderWithConstructorError) Meter(name string) metric.Meter { 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) { func (m *meterWithConstructorError) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) {
return metric.Int64Counter{}, errors.New("constructor error") return metric.NoopSync{}, errors.New("constructor error")
} }
func TestErrorInDeferredConstructor(t *testing.T) { func TestErrorInDeferredConstructor(t *testing.T) {

View File

@@ -135,38 +135,99 @@ func (d Descriptor) LibraryName() string {
return d.config.LibraryName return d.config.LibraryName
} }
// Meter is an interface to the metrics portion of the OpenTelemetry SDK. // Meter is the OpenTelemetry metric API, based on a `MeterImpl`
type Meter interface { // implementation and the `Meter` library name.
//
// An uninitialized Meter is a no-op implementation.
type Meter struct {
impl MeterImpl
libraryName string
}
// RecordBatch atomically records a batch of measurements. // RecordBatch atomically records a batch of measurements.
RecordBatch(context.Context, []core.KeyValue, ...Measurement) func (m Meter) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) {
if m.impl == nil {
return
}
m.impl.RecordBatch(ctx, ls, ms...)
}
// All instrument constructors may return an error for // NewInt64Counter creates a new integer Counter instrument with the
// conditions such as: // given name, customized with options. May return an error if the
// `name` is an empty string // name is invalid (e.g., empty) or improperly registered (e.g.,
// `name` was previously registered as a different kind of instrument // duplicate registration).
// for a given named `Meter`. func (m Meter) NewInt64Counter(name string, options ...Option) (Int64Counter, error) {
return wrapInt64CounterInstrument(
m.newSync(name, CounterKind, Int64NumberKind, options))
}
// NewInt64Counter creates a new integral counter with a given // NewFloat64Counter creates a new floating point Counter with the
// name and customized with passed options. // given name, customized with options. May return an error if the
NewInt64Counter(name string, opts ...Option) (Int64Counter, error) // name is invalid (e.g., empty) or improperly registered (e.g.,
// NewFloat64Counter creates a new floating point counter with // duplicate registration).
// a given name and customized with passed options. func (m Meter) NewFloat64Counter(name string, options ...Option) (Float64Counter, error) {
NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) return wrapFloat64CounterInstrument(
// NewInt64Measure creates a new integral measure with a given m.newSync(name, CounterKind, Float64NumberKind, options))
// 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)
// RegisterInt64Observer creates a new integral observer with a // NewInt64Measure creates a new integer Measure instrument with the
// given name, running a given callback, and customized with passed // given name, customized with options. May return an error if the
// options. Callback may be nil. // name is invalid (e.g., empty) or improperly registered (e.g.,
RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) // duplicate registration).
// RegisterFloat64Observer creates a new floating point observer func (m Meter) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) {
// with a given name, running a given callback, and customized with return wrapInt64MeasureInstrument(
// passed options. Callback may be nil. m.newSync(name, MeasureKind, Int64NumberKind, opts))
RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) }
// 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. // WithDescription applies provided description.

View File

@@ -21,7 +21,6 @@ import (
) )
type NoopProvider struct{} type NoopProvider struct{}
type NoopMeter struct{}
type noopInstrument struct{} type noopInstrument struct{}
type noopBoundInstrument struct{} type noopBoundInstrument struct{}
@@ -29,13 +28,12 @@ type NoopSync struct{ noopInstrument }
type NoopAsync struct{ noopInstrument } type NoopAsync struct{ noopInstrument }
var _ Provider = NoopProvider{} var _ Provider = NoopProvider{}
var _ Meter = NoopMeter{}
var _ SyncImpl = NoopSync{} var _ SyncImpl = NoopSync{}
var _ BoundSyncImpl = noopBoundInstrument{} var _ BoundSyncImpl = noopBoundInstrument{}
var _ AsyncImpl = NoopAsync{} var _ AsyncImpl = NoopAsync{}
func (NoopProvider) Meter(name string) Meter { func (NoopProvider) Meter(name string) Meter {
return NoopMeter{} return Meter{}
} }
func (noopInstrument) Implementation() interface{} { func (noopInstrument) Implementation() interface{} {
@@ -58,30 +56,3 @@ func (NoopSync) Bind([]core.KeyValue) BoundSyncImpl {
func (NoopSync) RecordOne(context.Context, Number, []core.KeyValue) { 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
}

View File

@@ -14,20 +14,6 @@
package metric 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 // Int64ObserverCallback is a type of callback that integral
// observers run. // observers run.
type Int64ObserverCallback func(result Int64ObserverResult) type Int64ObserverCallback func(result Int64ObserverResult)

View File

@@ -20,10 +20,8 @@ import (
"go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/core"
) )
// MeterImpl is a convenient interface for SDK and test // MeterImpl is the interface an SDK must implement to supply a Meter
// implementations that would provide a `Meter` but do not wish to // implementation.
// re-implement the API's type-safe interfaces. Helpers provided in
// this package will construct a `Meter` given a `MeterImpl`.
type MeterImpl interface { type MeterImpl interface {
// RecordBatch atomically records a batch of measurements. // RecordBatch atomically records a batch of measurements.
RecordBatch(context.Context, []core.KeyValue, ...Measurement) RecordBatch(context.Context, []core.KeyValue, ...Measurement)
@@ -83,35 +81,20 @@ type BoundSyncImpl interface {
// asynchronous instrument (e.g., Observer instruments). // asynchronous instrument (e.g., Observer instruments).
type AsyncImpl interface { type AsyncImpl interface {
InstrumentImpl InstrumentImpl
// Note: An `Unregister()` API could be supported here.
} }
// wrappedMeterImpl implements the `Meter` interface given a // Int64ObserverResult is passed to an observer callback to capture
// `MeterImpl` implementation. // observations for one asynchronous integer metric instrument.
type wrappedMeterImpl struct { type Int64ObserverResult struct {
impl MeterImpl
libraryName string
}
// int64ObserverResult is an adapter for int64-valued asynchronous
// callbacks.
type int64ObserverResult struct {
observe func(Number, []core.KeyValue) observe func(Number, []core.KeyValue)
} }
// float64ObserverResult is an adapter for float64-valued asynchronous // Float64ObserverResult is passed to an observer callback to capture
// callbacks. // observations for one asynchronous floating point metric instrument.
type float64ObserverResult struct { type Float64ObserverResult struct {
observe func(Number, []core.KeyValue) 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. // Configure is a helper that applies all the options to a Config.
func Configure(opts []Option) Config { func Configure(opts []Option) Config {
var config Config var config Config
@@ -124,131 +107,87 @@ func Configure(opts []Option) Config {
// WrapMeterImpl constructs a `Meter` implementation from a // WrapMeterImpl constructs a `Meter` implementation from a
// `MeterImpl` implementation. // `MeterImpl` implementation.
func WrapMeterImpl(impl MeterImpl, libraryName string) Meter { func WrapMeterImpl(impl MeterImpl, libraryName string) Meter {
return &wrappedMeterImpl{ return Meter{
impl: impl, impl: impl,
libraryName: libraryName, libraryName: libraryName,
} }
} }
func (m *wrappedMeterImpl) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) { // MeterImpl returns the underlying MeterImpl of this Meter.
m.impl.RecordBatch(ctx, ls, ms...) 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 := NewDescriptor(name, metricKind, numberKind, opts...)
desc.config.LibraryName = m.libraryName desc.config.LibraryName = m.libraryName
return m.impl.NewSyncInstrument(desc) return m.impl.NewSyncInstrument(desc)
} }
func (m *wrappedMeterImpl) NewInt64Counter(name string, opts ...Option) (Int64Counter, error) { // wrapInt64CounterInstrument returns an `Int64Counter` from a
return WrapInt64CounterInstrument(
m.newSync(name, CounterKind, Int64NumberKind, opts))
}
// WrapInt64CounterInstrument returns an `Int64Counter` from a
// `SyncImpl`. An error will be generated if the // `SyncImpl`. An error will be generated if the
// `SyncImpl` is nil (in which case a No-op is substituted), // `SyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewSync(syncInst, err)
return Int64Counter{syncInstrument: common}, err return Int64Counter{syncInstrument: common}, err
} }
func (m *wrappedMeterImpl) NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) { // wrapFloat64CounterInstrument returns an `Float64Counter` from a
return WrapFloat64CounterInstrument(
m.newSync(name, CounterKind, Float64NumberKind, opts))
}
// WrapFloat64CounterInstrument returns an `Float64Counter` from a
// `SyncImpl`. An error will be generated if the // `SyncImpl`. An error will be generated if the
// `SyncImpl` is nil (in which case a No-op is substituted), // `SyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewSync(syncInst, err)
return Float64Counter{syncInstrument: common}, err return Float64Counter{syncInstrument: common}, err
} }
func (m *wrappedMeterImpl) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { // wrapInt64MeasureInstrument returns an `Int64Measure` from a
return WrapInt64MeasureInstrument(
m.newSync(name, MeasureKind, Int64NumberKind, opts))
}
// WrapInt64MeasureInstrument returns an `Int64Measure` from a
// `SyncImpl`. An error will be generated if the // `SyncImpl`. An error will be generated if the
// `SyncImpl` is nil (in which case a No-op is substituted), // `SyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewSync(syncInst, err)
return Int64Measure{syncInstrument: common}, err return Int64Measure{syncInstrument: common}, err
} }
func (m *wrappedMeterImpl) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { // wrapFloat64MeasureInstrument returns an `Float64Measure` from a
return WrapFloat64MeasureInstrument(
m.newSync(name, MeasureKind, Float64NumberKind, opts))
}
// WrapFloat64MeasureInstrument returns an `Float64Measure` from a
// `SyncImpl`. An error will be generated if the // `SyncImpl`. An error will be generated if the
// `SyncImpl` is nil (in which case a No-op is substituted), // `SyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewSync(syncInst, err)
return Float64Measure{syncInstrument: common}, 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 := NewDescriptor(name, mkind, nkind, opts...)
desc.config.LibraryName = m.libraryName desc.config.LibraryName = m.libraryName
return m.impl.NewAsyncInstrument(desc, callback) return m.impl.NewAsyncInstrument(desc, callback)
} }
func (m *wrappedMeterImpl) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { // wrapInt64ObserverInstrument returns an `Int64Observer` from a
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
// `AsyncImpl`. An error will be generated if the // `AsyncImpl`. An error will be generated if the
// `AsyncImpl` is nil (in which case a No-op is substituted), // `AsyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewAsync(asyncInst, err)
return Int64Observer{asyncInstrument: common}, err return Int64Observer{asyncInstrument: common}, err
} }
func (m *wrappedMeterImpl) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { // wrapFloat64ObserverInstrument returns an `Float64Observer` from a
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
// `AsyncImpl`. An error will be generated if the // `AsyncImpl`. An error will be generated if the
// `AsyncImpl` is nil (in which case a No-op is substituted), // `AsyncImpl` is nil (in which case a No-op is substituted),
// otherwise the error passes through. // 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) common, err := checkNewAsync(asyncInst, err)
return Float64Observer{asyncInstrument: common}, 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)
}