You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	Refactor the SDK helpers, create MeterImpl (#560)
* Create MeterImpl interface * Checkpoint w/ sdk.go building * Checkpoint working on global * api/global builds (test fails) * Test fix * All tests pass * Comments * Add two tests * Comments and uncomment tests * Precommit part 1 * Still working on tests * Lint * Add a test and a TODO * Cleanup * Lint * Interface()->Implementation() * Apply some feedback * From feedback * (A)Synchronous -> (A)Sync * Add a missing comment * Apply suggestions from code review Co-Authored-By: Krzesimir Nowak <qdlacz@gmail.com> * Rename a variable Co-authored-by: Krzesimir Nowak <qdlacz@gmail.com>
This commit is contained in:
		| @@ -23,8 +23,9 @@ var Must = metric.Must | ||||
| // benchFixture is copied from sdk/metric/benchmark_test.go. | ||||
| // TODO refactor to share this code. | ||||
| type benchFixture struct { | ||||
| 	sdk *sdk.SDK | ||||
| 	B   *testing.B | ||||
| 	sdk   *sdk.SDK | ||||
| 	meter metric.Meter | ||||
| 	B     *testing.B | ||||
| } | ||||
|  | ||||
| var _ metric.Provider = &benchFixture{} | ||||
| @@ -35,14 +36,15 @@ func newFixture(b *testing.B) *benchFixture { | ||||
| 		B: b, | ||||
| 	} | ||||
| 	bf.sdk = sdk.New(bf, sdk.NewDefaultLabelEncoder()) | ||||
| 	bf.meter = metric.WrapMeterImpl(bf.sdk) | ||||
| 	return bf | ||||
| } | ||||
|  | ||||
| func (*benchFixture) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (*benchFixture) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	switch descriptor.MetricKind() { | ||||
| 	case export.CounterKind: | ||||
| 	case metric.CounterKind: | ||||
| 		return sum.New() | ||||
| 	case export.MeasureKind: | ||||
| 	case metric.MeasureKind: | ||||
| 		if strings.HasSuffix(descriptor.Name(), "minmaxsumcount") { | ||||
| 			return minmaxsumcount.New(descriptor) | ||||
| 		} else if strings.HasSuffix(descriptor.Name(), "ddsketch") { | ||||
| @@ -66,7 +68,7 @@ func (*benchFixture) FinishedCollection() { | ||||
| } | ||||
|  | ||||
| func (fix *benchFixture) Meter(name string) metric.Meter { | ||||
| 	return fix.sdk | ||||
| 	return fix.meter | ||||
| } | ||||
|  | ||||
| func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package internal | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"unsafe" | ||||
| @@ -32,13 +31,6 @@ import ( | ||||
| // instrument after it is registered, with a sync.Once initializer to | ||||
| // protect against races with Release(). | ||||
|  | ||||
| type metricKind int8 | ||||
|  | ||||
| const ( | ||||
| 	counterKind metricKind = iota | ||||
| 	measureKind | ||||
| ) | ||||
|  | ||||
| type meterProvider struct { | ||||
| 	delegate metric.Provider | ||||
|  | ||||
| @@ -52,50 +44,41 @@ type meter struct { | ||||
| 	provider *meterProvider | ||||
| 	name     string | ||||
|  | ||||
| 	lock          sync.Mutex | ||||
| 	instruments   []*instImpl | ||||
| 	liveObservers map[*obsImpl]struct{} | ||||
| 	// orderedObservers slice contains observers in their order of | ||||
| 	// registration. It may also contain unregistered | ||||
| 	// observers. The liveObservers map should be consulted to | ||||
| 	// check if the observer is registered or not. | ||||
| 	orderedObservers []*obsImpl | ||||
| 	lock       sync.Mutex | ||||
| 	syncInsts  []*syncImpl | ||||
| 	asyncInsts []*obsImpl | ||||
| } | ||||
|  | ||||
| type instImpl struct { | ||||
| 	delegate unsafe.Pointer // (*metric.InstrumentImpl) | ||||
| type instrument struct { | ||||
| 	descriptor metric.Descriptor | ||||
| } | ||||
|  | ||||
| 	name  string | ||||
| 	mkind metricKind | ||||
| 	nkind core.NumberKind | ||||
| 	opts  []metric.Option | ||||
| type syncImpl struct { | ||||
| 	delegate unsafe.Pointer // (*metric.SyncImpl) | ||||
|  | ||||
| 	instrument | ||||
|  | ||||
| 	constructor func(metric.Meter) (metric.SyncImpl, error) | ||||
| } | ||||
|  | ||||
| type obsImpl struct { | ||||
| 	delegate unsafe.Pointer // (*metric.Int64Observer or *metric.Float64Observer) | ||||
| 	delegate unsafe.Pointer // (*metric.AsyncImpl) | ||||
|  | ||||
| 	name     string | ||||
| 	nkind    core.NumberKind | ||||
| 	opts     []metric.Option | ||||
| 	meter    *meter | ||||
| 	callback interface{} | ||||
| 	instrument | ||||
|  | ||||
| 	constructor func(metric.Meter) (metric.AsyncImpl, error) | ||||
| } | ||||
|  | ||||
| type hasImpl interface { | ||||
| 	Impl() metric.InstrumentImpl | ||||
| // SyncImpler is implemented by all of the sync metric | ||||
| // instruments. | ||||
| type SyncImpler interface { | ||||
| 	SyncImpl() metric.SyncImpl | ||||
| } | ||||
|  | ||||
| type int64ObsImpl struct { | ||||
| 	observer *obsImpl | ||||
| } | ||||
|  | ||||
| type float64ObsImpl struct { | ||||
| 	observer *obsImpl | ||||
| } | ||||
|  | ||||
| // this is a common subset of the metric observers interfaces | ||||
| type observerUnregister interface { | ||||
| 	Unregister() | ||||
| // AsyncImpler is implemented by all of the async | ||||
| // metric instruments. | ||||
| type AsyncImpler interface { | ||||
| 	AsyncImpl() metric.AsyncImpl | ||||
| } | ||||
|  | ||||
| type labelSet struct { | ||||
| @@ -107,10 +90,10 @@ type labelSet struct { | ||||
| 	initialize sync.Once | ||||
| } | ||||
|  | ||||
| type instHandle struct { | ||||
| type syncHandle struct { | ||||
| 	delegate unsafe.Pointer // (*metric.HandleImpl) | ||||
|  | ||||
| 	inst   *instImpl | ||||
| 	inst   *syncImpl | ||||
| 	labels metric.LabelSet | ||||
|  | ||||
| 	initialize sync.Once | ||||
| @@ -120,14 +103,13 @@ var _ metric.Provider = &meterProvider{} | ||||
| var _ metric.Meter = &meter{} | ||||
| var _ metric.LabelSet = &labelSet{} | ||||
| var _ metric.LabelSetDelegate = &labelSet{} | ||||
| var _ metric.InstrumentImpl = &instImpl{} | ||||
| var _ metric.BoundInstrumentImpl = &instHandle{} | ||||
| var _ metric.Int64Observer = int64ObsImpl{} | ||||
| var _ metric.Float64Observer = float64ObsImpl{} | ||||
| var _ observerUnregister = (metric.Int64Observer)(nil) | ||||
| var _ observerUnregister = (metric.Float64Observer)(nil) | ||||
| var _ metric.InstrumentImpl = &syncImpl{} | ||||
| var _ metric.BoundSyncImpl = &syncHandle{} | ||||
| var _ metric.AsyncImpl = &obsImpl{} | ||||
|  | ||||
| var errInvalidMetricKind = errors.New("Invalid Metric kind") | ||||
| func (inst *instrument) Descriptor() metric.Descriptor { | ||||
| 	return inst.descriptor | ||||
| } | ||||
|  | ||||
| // Provider interface and delegation | ||||
|  | ||||
| @@ -168,40 +150,37 @@ func (m *meter) setDelegate(provider metric.Provider) { | ||||
| 	*d = provider.Meter(m.name) | ||||
| 	m.delegate = unsafe.Pointer(d) | ||||
|  | ||||
| 	for _, inst := range m.instruments { | ||||
| 	for _, inst := range m.syncInsts { | ||||
| 		inst.setDelegate(*d) | ||||
| 	} | ||||
| 	m.instruments = nil | ||||
| 	for _, obs := range m.orderedObservers { | ||||
| 		if _, ok := m.liveObservers[obs]; ok { | ||||
| 			obs.setDelegate(*d) | ||||
| 		} | ||||
| 	m.syncInsts = nil | ||||
| 	for _, obs := range m.asyncInsts { | ||||
| 		obs.setDelegate(*d) | ||||
| 	} | ||||
| 	m.liveObservers = nil | ||||
| 	m.orderedObservers = nil | ||||
| 	m.asyncInsts = nil | ||||
| } | ||||
|  | ||||
| func (m *meter) newInst(name string, mkind metricKind, nkind core.NumberKind, opts []metric.Option) (metric.InstrumentImpl, error) { | ||||
| func (m *meter) newSync(desc metric.Descriptor, constructor func(metric.Meter) (metric.SyncImpl, error)) (metric.SyncImpl, error) { | ||||
| 	m.lock.Lock() | ||||
| 	defer m.lock.Unlock() | ||||
|  | ||||
| 	if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||
| 		return newInstDelegate(*meterPtr, name, mkind, nkind, opts) | ||||
| 		return constructor(*meterPtr) | ||||
| 	} | ||||
|  | ||||
| 	inst := &instImpl{ | ||||
| 		name:  name, | ||||
| 		mkind: mkind, | ||||
| 		nkind: nkind, | ||||
| 		opts:  opts, | ||||
| 	inst := &syncImpl{ | ||||
| 		instrument: instrument{ | ||||
| 			descriptor: desc, | ||||
| 		}, | ||||
| 		constructor: constructor, | ||||
| 	} | ||||
| 	m.instruments = append(m.instruments, inst) | ||||
| 	m.syncInsts = append(m.syncInsts, inst) | ||||
| 	return inst, nil | ||||
| } | ||||
|  | ||||
| func delegateCheck(has hasImpl, err error) (metric.InstrumentImpl, error) { | ||||
| func syncCheck(has SyncImpler, err error) (metric.SyncImpl, error) { | ||||
| 	if has != nil { | ||||
| 		return has.Impl(), err | ||||
| 		return has.SyncImpl(), err | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		err = metric.ErrSDKReturnedNilImpl | ||||
| @@ -209,29 +188,13 @@ func delegateCheck(has hasImpl, err error) (metric.InstrumentImpl, error) { | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| func newInstDelegate(m metric.Meter, name string, mkind metricKind, nkind core.NumberKind, opts []metric.Option) (metric.InstrumentImpl, error) { | ||||
| 	switch mkind { | ||||
| 	case counterKind: | ||||
| 		if nkind == core.Int64NumberKind { | ||||
| 			return delegateCheck(m.NewInt64Counter(name, opts...)) | ||||
| 		} | ||||
| 		return delegateCheck(m.NewFloat64Counter(name, opts...)) | ||||
| 	case measureKind: | ||||
| 		if nkind == core.Int64NumberKind { | ||||
| 			return delegateCheck(m.NewInt64Measure(name, opts...)) | ||||
| 		} | ||||
| 		return delegateCheck(m.NewFloat64Measure(name, opts...)) | ||||
| 	} | ||||
| 	return nil, errInvalidMetricKind | ||||
| } | ||||
| // Synchronous delegation | ||||
|  | ||||
| // Instrument delegation | ||||
|  | ||||
| func (inst *instImpl) setDelegate(d metric.Meter) { | ||||
| 	implPtr := new(metric.InstrumentImpl) | ||||
| func (inst *syncImpl) setDelegate(d metric.Meter) { | ||||
| 	implPtr := new(metric.SyncImpl) | ||||
|  | ||||
| 	var err error | ||||
| 	*implPtr, err = newInstDelegate(d, inst.name, inst.mkind, inst.nkind, inst.opts) | ||||
| 	*implPtr, err = inst.constructor(d) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		// TODO: There is no standard way to deliver this error to the user. | ||||
| @@ -244,20 +207,27 @@ func (inst *instImpl) setDelegate(d metric.Meter) { | ||||
| 	atomic.StorePointer(&inst.delegate, unsafe.Pointer(implPtr)) | ||||
| } | ||||
|  | ||||
| func (inst *instImpl) Bind(labels metric.LabelSet) metric.BoundInstrumentImpl { | ||||
| 	if implPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { | ||||
| func (inst *syncImpl) Implementation() interface{} { | ||||
| 	if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { | ||||
| 		return (*implPtr).Implementation() | ||||
| 	} | ||||
| 	return inst | ||||
| } | ||||
|  | ||||
| func (inst *syncImpl) Bind(labels metric.LabelSet) metric.BoundSyncImpl { | ||||
| 	if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { | ||||
| 		return (*implPtr).Bind(labels) | ||||
| 	} | ||||
| 	return &instHandle{ | ||||
| 	return &syncHandle{ | ||||
| 		inst:   inst, | ||||
| 		labels: labels, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (bound *instHandle) Unbind() { | ||||
| func (bound *syncHandle) Unbind() { | ||||
| 	bound.initialize.Do(func() {}) | ||||
|  | ||||
| 	implPtr := (*metric.BoundInstrumentImpl)(atomic.LoadPointer(&bound.delegate)) | ||||
| 	implPtr := (*metric.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate)) | ||||
|  | ||||
| 	if implPtr == nil { | ||||
| 		return | ||||
| @@ -266,50 +236,48 @@ func (bound *instHandle) Unbind() { | ||||
| 	(*implPtr).Unbind() | ||||
| } | ||||
|  | ||||
| // Any Observer delegation | ||||
| // Async delegation | ||||
|  | ||||
| func (m *meter) newAsync(desc metric.Descriptor, constructor func(metric.Meter) (metric.AsyncImpl, error)) (metric.AsyncImpl, error) { | ||||
| 	m.lock.Lock() | ||||
| 	defer m.lock.Unlock() | ||||
|  | ||||
| 	if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||
| 		return constructor(*meterPtr) | ||||
| 	} | ||||
|  | ||||
| 	inst := &obsImpl{ | ||||
| 		instrument: instrument{ | ||||
| 			descriptor: desc, | ||||
| 		}, | ||||
| 		constructor: constructor, | ||||
| 	} | ||||
| 	m.asyncInsts = append(m.asyncInsts, inst) | ||||
| 	return inst, nil | ||||
| } | ||||
|  | ||||
| func (obs *obsImpl) Implementation() interface{} { | ||||
| 	if implPtr := (*metric.AsyncImpl)(atomic.LoadPointer(&obs.delegate)); implPtr != nil { | ||||
| 		return (*implPtr).Implementation() | ||||
| 	} | ||||
| 	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 *obsImpl) setDelegate(d metric.Meter) { | ||||
| 	if obs.nkind == core.Int64NumberKind { | ||||
| 		obs.setInt64Delegate(d) | ||||
| 	} else { | ||||
| 		obs.setFloat64Delegate(d) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (obs *obsImpl) unregister() { | ||||
| 	unreg := obs.getUnregister() | ||||
| 	if unreg != nil { | ||||
| 		unreg.Unregister() | ||||
| 		return | ||||
| 	} | ||||
| 	obs.meter.lock.Lock() | ||||
| 	defer obs.meter.lock.Unlock() | ||||
| 	delete(obs.meter.liveObservers, obs) | ||||
| 	if len(obs.meter.liveObservers) == 0 { | ||||
| 		obs.meter.liveObservers = nil | ||||
| 		obs.meter.orderedObservers = nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (obs *obsImpl) getUnregister() observerUnregister { | ||||
| 	ptr := atomic.LoadPointer(&obs.delegate) | ||||
| 	if ptr == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if obs.nkind == core.Int64NumberKind { | ||||
| 		return *(*metric.Int64Observer)(ptr) | ||||
| 	} | ||||
| 	return *(*metric.Float64Observer)(ptr) | ||||
| } | ||||
|  | ||||
| // Int64Observer delegation | ||||
|  | ||||
| func (obs *obsImpl) setInt64Delegate(d metric.Meter) { | ||||
| 	obsPtr := new(metric.Int64Observer) | ||||
| 	cb := obs.callback.(metric.Int64ObserverCallback) | ||||
| 	implPtr := new(metric.AsyncImpl) | ||||
|  | ||||
| 	var err error | ||||
| 	*obsPtr, err = d.RegisterInt64Observer(obs.name, cb, obs.opts...) | ||||
| 	*implPtr, err = obs.constructor(d) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		// TODO: There is no standard way to deliver this error to the user. | ||||
| @@ -319,34 +287,7 @@ func (obs *obsImpl) setInt64Delegate(d metric.Meter) { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	atomic.StorePointer(&obs.delegate, unsafe.Pointer(obsPtr)) | ||||
| } | ||||
|  | ||||
| func (obs int64ObsImpl) Unregister() { | ||||
| 	obs.observer.unregister() | ||||
| } | ||||
|  | ||||
| // Float64Observer delegation | ||||
|  | ||||
| func (obs *obsImpl) setFloat64Delegate(d metric.Meter) { | ||||
| 	obsPtr := new(metric.Float64Observer) | ||||
| 	cb := obs.callback.(metric.Float64ObserverCallback) | ||||
|  | ||||
| 	var err error | ||||
| 	*obsPtr, err = d.RegisterFloat64Observer(obs.name, cb, obs.opts...) | ||||
| 	if err != nil { | ||||
| 		// TODO: There is no standard way to deliver this error to the user. | ||||
| 		// See https://github.com/open-telemetry/opentelemetry-go/issues/514 | ||||
| 		// Note that the default SDK will not generate any errors yet, this is | ||||
| 		// only for added safety. | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	atomic.StorePointer(&obs.delegate, unsafe.Pointer(obsPtr)) | ||||
| } | ||||
|  | ||||
| func (obs float64ObsImpl) Unregister() { | ||||
| 	obs.observer.unregister() | ||||
| 	atomic.StorePointer(&obs.delegate, unsafe.Pointer(implPtr)) | ||||
| } | ||||
|  | ||||
| // Metric updates | ||||
| @@ -357,27 +298,27 @@ func (m *meter) RecordBatch(ctx context.Context, labels metric.LabelSet, measure | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (inst *instImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { | ||||
| 	if instPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { | ||||
| func (inst *syncImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { | ||||
| 	if instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { | ||||
| 		(*instPtr).RecordOne(ctx, number, labels) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Bound instrument initialization | ||||
|  | ||||
| func (bound *instHandle) RecordOne(ctx context.Context, number core.Number) { | ||||
| 	instPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&bound.inst.delegate)) | ||||
| func (bound *syncHandle) RecordOne(ctx context.Context, number core.Number) { | ||||
| 	instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&bound.inst.delegate)) | ||||
| 	if instPtr == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var implPtr *metric.BoundInstrumentImpl | ||||
| 	var implPtr *metric.BoundSyncImpl | ||||
| 	bound.initialize.Do(func() { | ||||
| 		implPtr = new(metric.BoundInstrumentImpl) | ||||
| 		implPtr = new(metric.BoundSyncImpl) | ||||
| 		*implPtr = (*instPtr).Bind(bound.labels) | ||||
| 		atomic.StorePointer(&bound.delegate, unsafe.Pointer(implPtr)) | ||||
| 	}) | ||||
| 	if implPtr == nil { | ||||
| 		implPtr = (*metric.BoundInstrumentImpl)(atomic.LoadPointer(&bound.delegate)) | ||||
| 		implPtr = (*metric.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate)) | ||||
| 	} | ||||
| 	// This may still be nil if instrument was created and bound | ||||
| 	// without a delegate, then the instrument was set to have a | ||||
| @@ -420,78 +361,60 @@ func (labels *labelSet) Delegate() metric.LabelSet { | ||||
| // Constructors | ||||
|  | ||||
| func (m *meter) NewInt64Counter(name string, opts ...metric.Option) (metric.Int64Counter, error) { | ||||
| 	return metric.WrapInt64CounterInstrument(m.newInst(name, counterKind, core.Int64NumberKind, opts)) | ||||
| 	return metric.WrapInt64CounterInstrument(m.newSync( | ||||
| 		metric.NewDescriptor(name, metric.CounterKind, core.Int64NumberKind, 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.newInst(name, counterKind, core.Float64NumberKind, opts)) | ||||
| 	return metric.WrapFloat64CounterInstrument(m.newSync( | ||||
| 		metric.NewDescriptor(name, metric.CounterKind, core.Float64NumberKind, 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.newInst(name, measureKind, core.Int64NumberKind, opts)) | ||||
| 	return metric.WrapInt64MeasureInstrument(m.newSync( | ||||
| 		metric.NewDescriptor(name, metric.MeasureKind, core.Int64NumberKind, 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.newInst(name, measureKind, core.Float64NumberKind, opts)) | ||||
| 	return metric.WrapFloat64MeasureInstrument(m.newSync( | ||||
| 		metric.NewDescriptor(name, metric.MeasureKind, core.Float64NumberKind, 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) { | ||||
| 	m.lock.Lock() | ||||
| 	defer m.lock.Unlock() | ||||
|  | ||||
| 	if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||
| 		return (*meterPtr).RegisterInt64Observer(name, callback, opts...) | ||||
| 	} | ||||
|  | ||||
| 	obs := &obsImpl{ | ||||
| 		name:     name, | ||||
| 		nkind:    core.Int64NumberKind, | ||||
| 		opts:     opts, | ||||
| 		meter:    m, | ||||
| 		callback: callback, | ||||
| 	} | ||||
| 	m.addObserver(obs) | ||||
| 	return int64ObsImpl{ | ||||
| 		observer: obs, | ||||
| 	}, nil | ||||
| 	return metric.WrapInt64ObserverInstrument(m.newAsync( | ||||
| 		metric.NewDescriptor(name, metric.ObserverKind, core.Int64NumberKind, 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) { | ||||
| 	m.lock.Lock() | ||||
| 	defer m.lock.Unlock() | ||||
|  | ||||
| 	if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||
| 		return (*meterPtr).RegisterFloat64Observer(name, callback, opts...) | ||||
| 	} | ||||
|  | ||||
| 	obs := &obsImpl{ | ||||
| 		name:     name, | ||||
| 		nkind:    core.Float64NumberKind, | ||||
| 		opts:     opts, | ||||
| 		meter:    m, | ||||
| 		callback: callback, | ||||
| 	} | ||||
| 	m.addObserver(obs) | ||||
| 	return float64ObsImpl{ | ||||
| 		observer: obs, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (m *meter) addObserver(obs *obsImpl) { | ||||
| 	if m.liveObservers == nil { | ||||
| 		m.liveObservers = make(map[*obsImpl]struct{}) | ||||
| 	} | ||||
| 	m.liveObservers[obs] = struct{}{} | ||||
| 	m.orderedObservers = append(m.orderedObservers, obs) | ||||
| 	return metric.WrapFloat64ObserverInstrument(m.newAsync( | ||||
| 		metric.NewDescriptor(name, metric.ObserverKind, core.Float64NumberKind, 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), | ||||
| 		"instImpl.delegate":      unsafe.Offsetof(instImpl{}.delegate), | ||||
| 		"syncImpl.delegate":      unsafe.Offsetof(syncImpl{}.delegate), | ||||
| 		"obsImpl.delegate":       unsafe.Offsetof(obsImpl{}.delegate), | ||||
| 		"labelSet.delegate":      unsafe.Offsetof(labelSet{}.delegate), | ||||
| 		"instHandle.delegate":    unsafe.Offsetof(instHandle{}.delegate), | ||||
| 		"syncHandle.delegate":    unsafe.Offsetof(syncHandle{}.delegate), | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -60,8 +60,9 @@ func TestDirect(t *testing.T) { | ||||
| 	measure.Record(ctx, 3, labels1) | ||||
| 	second.Record(ctx, 3, labels3) | ||||
|  | ||||
| 	mock := sdk.Meter("test1").(*metrictest.Meter) | ||||
| 	mock.RunObservers() | ||||
| 	mockImpl, _ := metric.UnwrapImpl(sdk.Meter("test1")) | ||||
| 	mock := mockImpl.(*metrictest.Meter) | ||||
| 	mock.RunAsyncInstruments() | ||||
| 	require.Len(t, mock.MeasurementBatches, 6) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| @@ -71,7 +72,7 @@ func TestDirect(t *testing.T) { | ||||
| 	require.Equal(t, int64(1), | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Number.AsInt64()) | ||||
| 	require.Equal(t, "test.counter", | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals1.Key: lvals1.Value, | ||||
| @@ -81,7 +82,7 @@ func TestDirect(t *testing.T) { | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Number.AsFloat64(), | ||||
| 		0.01) | ||||
| 	require.Equal(t, "test.measure", | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals1.Key: lvals1.Value, | ||||
| @@ -91,7 +92,7 @@ func TestDirect(t *testing.T) { | ||||
| 		mock.MeasurementBatches[2].Measurements[0].Number.AsFloat64(), | ||||
| 		0.01) | ||||
| 	require.Equal(t, "test.observer.float", | ||||
| 		mock.MeasurementBatches[2].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[2].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals2.Key: lvals2.Value, | ||||
| @@ -101,7 +102,7 @@ func TestDirect(t *testing.T) { | ||||
| 		mock.MeasurementBatches[3].Measurements[0].Number.AsFloat64(), | ||||
| 		0.01) | ||||
| 	require.Equal(t, "test.observer.float", | ||||
| 		mock.MeasurementBatches[3].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[3].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals1.Key: lvals1.Value, | ||||
| @@ -110,7 +111,7 @@ func TestDirect(t *testing.T) { | ||||
| 	require.Equal(t, int64(1), | ||||
| 		mock.MeasurementBatches[4].Measurements[0].Number.AsInt64()) | ||||
| 	require.Equal(t, "test.observer.int", | ||||
| 		mock.MeasurementBatches[4].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[4].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals2.Key: lvals2.Value, | ||||
| @@ -119,10 +120,11 @@ func TestDirect(t *testing.T) { | ||||
| 	require.Equal(t, int64(2), | ||||
| 		mock.MeasurementBatches[5].Measurements[0].Number.AsInt64()) | ||||
| 	require.Equal(t, "test.observer.int", | ||||
| 		mock.MeasurementBatches[5].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[5].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	// This tests the second Meter instance | ||||
| 	mock = sdk.Meter("test2").(*metrictest.Meter) | ||||
| 	mockImpl, _ = metric.UnwrapImpl(sdk.Meter("test2")) | ||||
| 	mock = mockImpl.(*metrictest.Meter) | ||||
| 	require.Len(t, mock.MeasurementBatches, 1) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| @@ -133,7 +135,7 @@ func TestDirect(t *testing.T) { | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Number.AsFloat64(), | ||||
| 		0.01) | ||||
| 	require.Equal(t, "test.second", | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Descriptor().Name()) | ||||
| } | ||||
|  | ||||
| func TestBound(t *testing.T) { | ||||
| @@ -162,7 +164,8 @@ func TestBound(t *testing.T) { | ||||
| 	boundC.Add(ctx, 1) | ||||
| 	boundM.Record(ctx, 3) | ||||
|  | ||||
| 	mock := sdk.Meter("test").(*metrictest.Meter) | ||||
| 	mockImpl, _ := metric.UnwrapImpl(sdk.Meter("test")) | ||||
| 	mock := mockImpl.(*metrictest.Meter) | ||||
| 	require.Len(t, mock.MeasurementBatches, 2) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| @@ -173,7 +176,7 @@ func TestBound(t *testing.T) { | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Number.AsFloat64(), | ||||
| 		0.01) | ||||
| 	require.Equal(t, "test.counter", | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[0].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	require.Equal(t, map[core.Key]core.Value{ | ||||
| 		lvals1.Key: lvals1.Value, | ||||
| @@ -182,7 +185,7 @@ func TestBound(t *testing.T) { | ||||
| 	require.Equal(t, int64(3), | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Number.AsInt64()) | ||||
| 	require.Equal(t, "test.measure", | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Instrument.Name) | ||||
| 		mock.MeasurementBatches[1].Measurements[0].Instrument.Descriptor().Name()) | ||||
|  | ||||
| 	boundC.Unbind() | ||||
| 	boundM.Unbind() | ||||
| @@ -202,13 +205,8 @@ func TestUnbind(t *testing.T) { | ||||
| 	measure := Must(glob).NewInt64Measure("test.measure") | ||||
| 	boundM := measure.Bind(labels1) | ||||
|  | ||||
| 	observerInt := Must(glob).RegisterInt64Observer("test.observer.int", nil) | ||||
| 	observerFloat := Must(glob).RegisterFloat64Observer("test.observer.float", nil) | ||||
|  | ||||
| 	boundC.Unbind() | ||||
| 	boundM.Unbind() | ||||
| 	observerInt.Unregister() | ||||
| 	observerFloat.Unregister() | ||||
| } | ||||
|  | ||||
| func TestDefaultSDK(t *testing.T) { | ||||
| @@ -262,7 +260,8 @@ func TestUnbindThenRecordOne(t *testing.T) { | ||||
| 	require.NotPanics(t, func() { | ||||
| 		boundC.Add(ctx, 1) | ||||
| 	}) | ||||
| 	mock := global.Meter("test").(*metrictest.Meter) | ||||
| 	mockImpl, _ := metric.UnwrapImpl(global.Meter("test")) | ||||
| 	mock := mockImpl.(*metrictest.Meter) | ||||
| 	require.Equal(t, 0, len(mock.MeasurementBatches)) | ||||
| } | ||||
|  | ||||
| @@ -300,3 +299,54 @@ func TestErrorInDeferredConstructor(t *testing.T) { | ||||
| 	c1.Add(ctx, 1, meter.Labels()) | ||||
| 	c2.Add(ctx, 2, meter.Labels()) | ||||
| } | ||||
|  | ||||
| func TestImplementationIndirection(t *testing.T) { | ||||
| 	internal.ResetForTest() | ||||
|  | ||||
| 	// Test that Implementation() does the proper indirection, i.e., | ||||
| 	// returns the implementation interface not the global, after | ||||
| 	// registered. | ||||
|  | ||||
| 	meter1 := global.Meter("test1") | ||||
|  | ||||
| 	// Sync: no SDK yet | ||||
| 	counter := Must(meter1).NewInt64Counter("interface.counter") | ||||
|  | ||||
| 	ival := counter.Measurement(1).SyncImpl().Implementation() | ||||
| 	require.NotNil(t, ival) | ||||
|  | ||||
| 	_, ok := ival.(*metrictest.Sync) | ||||
| 	require.False(t, ok) | ||||
|  | ||||
| 	// Async: no SDK yet | ||||
| 	observer := Must(meter1).RegisterFloat64Observer( | ||||
| 		"interface.observer", | ||||
| 		func(result metric.Float64ObserverResult) {}, | ||||
| 	) | ||||
|  | ||||
| 	ival = observer.AsyncImpl().Implementation() | ||||
| 	require.NotNil(t, ival) | ||||
|  | ||||
| 	_, ok = ival.(*metrictest.Async) | ||||
| 	require.False(t, ok) | ||||
|  | ||||
| 	// Register the SDK | ||||
| 	sdk := metrictest.NewProvider() | ||||
| 	global.SetMeterProvider(sdk) | ||||
|  | ||||
| 	// Repeat the above tests | ||||
|  | ||||
| 	// Sync | ||||
| 	ival = counter.Measurement(1).SyncImpl().Implementation() | ||||
| 	require.NotNil(t, ival) | ||||
|  | ||||
| 	_, ok = ival.(*metrictest.Sync) | ||||
| 	require.True(t, ok) | ||||
|  | ||||
| 	// Async | ||||
| 	ival = observer.AsyncImpl().Implementation() | ||||
| 	require.NotNil(t, ival) | ||||
|  | ||||
| 	_, ok = ival.(*metrictest.Async) | ||||
| 	require.True(t, ok) | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,8 @@ | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| //go:generate stringer -type=Kind | ||||
|  | ||||
| package metric | ||||
|  | ||||
| import ( | ||||
| @@ -57,13 +59,13 @@ type Option interface { | ||||
| type Measurement struct { | ||||
| 	// number needs to be aligned for 64-bit atomic operations. | ||||
| 	number     core.Number | ||||
| 	instrument InstrumentImpl | ||||
| 	instrument SyncImpl | ||||
| } | ||||
|  | ||||
| // Instrument returns the instrument that created this measurement. | ||||
| // SyncImpl returns the instrument that created this measurement. | ||||
| // This returns an implementation-level object for use by the SDK, | ||||
| // users should not refer to this. | ||||
| func (m Measurement) InstrumentImpl() InstrumentImpl { | ||||
| func (m Measurement) SyncImpl() SyncImpl { | ||||
| 	return m.instrument | ||||
| } | ||||
|  | ||||
| @@ -72,6 +74,73 @@ func (m Measurement) Number() core.Number { | ||||
| 	return m.number | ||||
| } | ||||
|  | ||||
| // Kind describes the kind of instrument. | ||||
| type Kind int8 | ||||
|  | ||||
| const ( | ||||
| 	// MeasureKind indicates a Measure instrument. | ||||
| 	MeasureKind Kind = iota | ||||
| 	// ObserverKind indicates an Observer instrument. | ||||
| 	ObserverKind | ||||
| 	// CounterKind indicates a Counter instrument. | ||||
| 	CounterKind | ||||
| ) | ||||
|  | ||||
| // Descriptor contains all the settings that describe an instrument, | ||||
| // including its name, metric kind, number kind, and the configurable | ||||
| // options. | ||||
| type Descriptor struct { | ||||
| 	name       string | ||||
| 	kind       Kind | ||||
| 	numberKind core.NumberKind | ||||
| 	config     Config | ||||
| } | ||||
|  | ||||
| // NewDescriptor returns a Descriptor with the given contents. | ||||
| func NewDescriptor(name string, mkind Kind, nkind core.NumberKind, opts ...Option) Descriptor { | ||||
| 	return Descriptor{ | ||||
| 		name:       name, | ||||
| 		kind:       mkind, | ||||
| 		numberKind: nkind, | ||||
| 		config:     Configure(opts), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Name returns the metric instrument's name. | ||||
| func (d Descriptor) Name() string { | ||||
| 	return d.name | ||||
| } | ||||
|  | ||||
| // MetricKind returns the specific kind of instrument. | ||||
| func (d Descriptor) MetricKind() Kind { | ||||
| 	return d.kind | ||||
| } | ||||
|  | ||||
| // Keys returns the recommended keys included in the metric | ||||
| // definition.  These keys may be used by a Batcher as a default set | ||||
| // of grouping keys for the metric instrument. | ||||
| func (d Descriptor) Keys() []core.Key { | ||||
| 	return d.config.Keys | ||||
| } | ||||
|  | ||||
| // Description provides a human-readable description of the metric | ||||
| // instrument. | ||||
| func (d Descriptor) Description() string { | ||||
| 	return d.config.Description | ||||
| } | ||||
|  | ||||
| // Unit describes the units of the metric instrument.  Unitless | ||||
| // metrics return the empty string. | ||||
| func (d Descriptor) Unit() unit.Unit { | ||||
| 	return d.config.Unit | ||||
| } | ||||
|  | ||||
| // NumberKind returns whether this instrument is declared over int64, | ||||
| // float64, or uint64 values. | ||||
| func (d Descriptor) NumberKind() core.NumberKind { | ||||
| 	return d.numberKind | ||||
| } | ||||
|  | ||||
| // Meter is an interface to the metrics portion of the OpenTelemetry SDK. | ||||
| type Meter interface { | ||||
| 	// Labels returns a reference to a set of labels that cannot | ||||
| @@ -110,38 +179,6 @@ type Meter interface { | ||||
| 	RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) | ||||
| } | ||||
|  | ||||
| // Int64ObserverResult is an interface for reporting integral | ||||
| // observations. | ||||
| type Int64ObserverResult interface { | ||||
| 	Observe(value int64, labels LabelSet) | ||||
| } | ||||
|  | ||||
| // Float64ObserverResult is an interface for reporting floating point | ||||
| // observations. | ||||
| type Float64ObserverResult interface { | ||||
| 	Observe(value float64, labels LabelSet) | ||||
| } | ||||
|  | ||||
| // Int64ObserverCallback is a type of callback that integral | ||||
| // observers run. | ||||
| type Int64ObserverCallback func(result Int64ObserverResult) | ||||
|  | ||||
| // Float64ObserverCallback is a type of callback that floating point | ||||
| // observers run. | ||||
| type Float64ObserverCallback func(result Float64ObserverResult) | ||||
|  | ||||
| // Int64Observer is a metric that captures a set of int64 values at a | ||||
| // point in time. | ||||
| type Int64Observer interface { | ||||
| 	Unregister() | ||||
| } | ||||
|  | ||||
| // Float64Observer is a metric that captures a set of float64 values | ||||
| // at a point in time. | ||||
| type Float64Observer interface { | ||||
| 	Unregister() | ||||
| } | ||||
|  | ||||
| // WithDescription applies provided description. | ||||
| func WithDescription(desc string) Option { | ||||
| 	return descriptionOption(desc) | ||||
|   | ||||
| @@ -24,7 +24,7 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/api/unit" | ||||
| 	mock "go.opentelemetry.io/otel/internal/metric" | ||||
| 	mockTest "go.opentelemetry.io/otel/internal/metric" | ||||
|  | ||||
| 	"github.com/google/go-cmp/cmp" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -117,7 +117,7 @@ func TestOptions(t *testing.T) { | ||||
|  | ||||
| func TestCounter(t *testing.T) { | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		c := Must(meter).NewFloat64Counter("test.counter.float") | ||||
| 		ctx := context.Background() | ||||
| 		labels := meter.Labels() | ||||
| @@ -126,10 +126,10 @@ func TestCounter(t *testing.T) { | ||||
| 		boundInstrument.Add(ctx, 42) | ||||
| 		meter.RecordBatch(ctx, labels, c.Measurement(42)) | ||||
| 		t.Log("Testing float counter") | ||||
| 		checkBatches(t, ctx, labels, meter, core.Float64NumberKind, c.Impl()) | ||||
| 		checkBatches(t, ctx, labels, mockSDK, core.Float64NumberKind, c.SyncImpl()) | ||||
| 	} | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		c := Must(meter).NewInt64Counter("test.counter.int") | ||||
| 		ctx := context.Background() | ||||
| 		labels := meter.Labels() | ||||
| @@ -138,13 +138,13 @@ func TestCounter(t *testing.T) { | ||||
| 		boundInstrument.Add(ctx, 42) | ||||
| 		meter.RecordBatch(ctx, labels, c.Measurement(42)) | ||||
| 		t.Log("Testing int counter") | ||||
| 		checkBatches(t, ctx, labels, meter, core.Int64NumberKind, c.Impl()) | ||||
| 		checkBatches(t, ctx, labels, mockSDK, core.Int64NumberKind, c.SyncImpl()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMeasure(t *testing.T) { | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		m := Must(meter).NewFloat64Measure("test.measure.float") | ||||
| 		ctx := context.Background() | ||||
| 		labels := meter.Labels() | ||||
| @@ -153,10 +153,10 @@ func TestMeasure(t *testing.T) { | ||||
| 		boundInstrument.Record(ctx, 42) | ||||
| 		meter.RecordBatch(ctx, labels, m.Measurement(42)) | ||||
| 		t.Log("Testing float measure") | ||||
| 		checkBatches(t, ctx, labels, meter, core.Float64NumberKind, m.Impl()) | ||||
| 		checkBatches(t, ctx, labels, mockSDK, core.Float64NumberKind, m.SyncImpl()) | ||||
| 	} | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		m := Must(meter).NewInt64Measure("test.measure.int") | ||||
| 		ctx := context.Background() | ||||
| 		labels := meter.Labels() | ||||
| @@ -165,46 +165,47 @@ func TestMeasure(t *testing.T) { | ||||
| 		boundInstrument.Record(ctx, 42) | ||||
| 		meter.RecordBatch(ctx, labels, m.Measurement(42)) | ||||
| 		t.Log("Testing int measure") | ||||
| 		checkBatches(t, ctx, labels, meter, core.Int64NumberKind, m.Impl()) | ||||
| 		checkBatches(t, ctx, labels, mockSDK, core.Int64NumberKind, m.SyncImpl()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestObserver(t *testing.T) { | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		labels := meter.Labels() | ||||
| 		o := Must(meter).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) { | ||||
| 			result.Observe(42, labels) | ||||
| 		}) | ||||
| 		t.Log("Testing float observer") | ||||
| 		meter.RunObservers() | ||||
| 		checkObserverBatch(t, labels, meter, core.Float64NumberKind, o) | ||||
|  | ||||
| 		mockSDK.RunAsyncInstruments() | ||||
| 		checkObserverBatch(t, labels, mockSDK, core.Float64NumberKind, o.AsyncImpl()) | ||||
| 	} | ||||
| 	{ | ||||
| 		meter := mock.NewMeter() | ||||
| 		mockSDK, meter := mockTest.NewMeter() | ||||
| 		labels := meter.Labels() | ||||
| 		o := Must(meter).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) { | ||||
| 			result.Observe(42, labels) | ||||
| 		}) | ||||
| 		t.Log("Testing int observer") | ||||
| 		meter.RunObservers() | ||||
| 		checkObserverBatch(t, labels, meter, core.Int64NumberKind, o) | ||||
| 		mockSDK.RunAsyncInstruments() | ||||
| 		checkObserverBatch(t, labels, mockSDK, core.Int64NumberKind, o.AsyncImpl()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func checkBatches(t *testing.T, ctx context.Context, labels metric.LabelSet, meter *mock.Meter, kind core.NumberKind, instrument metric.InstrumentImpl) { | ||||
| func checkBatches(t *testing.T, ctx context.Context, labels metric.LabelSet, mock *mockTest.Meter, kind core.NumberKind, instrument metric.InstrumentImpl) { | ||||
| 	t.Helper() | ||||
| 	if len(meter.MeasurementBatches) != 3 { | ||||
| 		t.Errorf("Expected 3 recorded measurement batches, got %d", len(meter.MeasurementBatches)) | ||||
| 	if len(mock.MeasurementBatches) != 3 { | ||||
| 		t.Errorf("Expected 3 recorded measurement batches, got %d", len(mock.MeasurementBatches)) | ||||
| 	} | ||||
| 	ourInstrument := instrument.(*mock.Instrument) | ||||
| 	ourLabelSet := labels.(*mock.LabelSet) | ||||
| 	ourInstrument := instrument.Implementation().(*mockTest.Sync) | ||||
| 	ourLabelSet := labels.(*mockTest.LabelSet) | ||||
| 	minLen := 3 | ||||
| 	if minLen > len(meter.MeasurementBatches) { | ||||
| 		minLen = len(meter.MeasurementBatches) | ||||
| 	if minLen > len(mock.MeasurementBatches) { | ||||
| 		minLen = len(mock.MeasurementBatches) | ||||
| 	} | ||||
| 	for i := 0; i < minLen; i++ { | ||||
| 		got := meter.MeasurementBatches[i] | ||||
| 		got := mock.MeasurementBatches[i] | ||||
| 		if got.Ctx != ctx { | ||||
| 			d := func(c context.Context) string { | ||||
| 				return fmt.Sprintf("(ptr: %p, ctx %#v)", c, c) | ||||
| @@ -212,7 +213,7 @@ func checkBatches(t *testing.T, ctx context.Context, labels metric.LabelSet, met | ||||
| 			t.Errorf("Wrong recorded context in batch %d, expected %s, got %s", i, d(ctx), d(got.Ctx)) | ||||
| 		} | ||||
| 		if got.LabelSet != ourLabelSet { | ||||
| 			d := func(l *mock.LabelSet) string { | ||||
| 			d := func(l *mockTest.LabelSet) string { | ||||
| 				return fmt.Sprintf("(ptr: %p, labels %#v)", l, l.Labels) | ||||
| 			} | ||||
| 			t.Errorf("Wrong recorded label set in batch %d, expected %s, got %s", i, d(ourLabelSet), d(got.LabelSet)) | ||||
| @@ -226,11 +227,12 @@ func checkBatches(t *testing.T, ctx context.Context, labels metric.LabelSet, met | ||||
| 		} | ||||
| 		for j := 0; j < minMLen; j++ { | ||||
| 			measurement := got.Measurements[j] | ||||
| 			if measurement.Instrument != ourInstrument { | ||||
| 				d := func(i *mock.Instrument) string { | ||||
| 			if measurement.Instrument.Implementation() != ourInstrument { | ||||
| 				d := func(iface interface{}) string { | ||||
| 					i := iface.(*mockTest.Instrument) | ||||
| 					return fmt.Sprintf("(ptr: %p, instrument %#v)", i, i) | ||||
| 				} | ||||
| 				t.Errorf("Wrong recorded instrument in measurement %d in batch %d, expected %s, got %s", j, i, d(ourInstrument), d(measurement.Instrument)) | ||||
| 				t.Errorf("Wrong recorded instrument in measurement %d in batch %d, expected %s, got %s", j, i, d(ourInstrument), d(measurement.Instrument.Implementation())) | ||||
| 			} | ||||
| 			ft := fortyTwo(t, kind) | ||||
| 			if measurement.Number.CompareNumber(kind, ft) != 0 { | ||||
| @@ -240,25 +242,25 @@ func checkBatches(t *testing.T, ctx context.Context, labels metric.LabelSet, met | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func checkObserverBatch(t *testing.T, labels metric.LabelSet, meter *mock.Meter, kind core.NumberKind, observer interface{}) { | ||||
| func checkObserverBatch(t *testing.T, labels metric.LabelSet, mock *mockTest.Meter, kind core.NumberKind, observer metric.AsyncImpl) { | ||||
| 	t.Helper() | ||||
| 	assert.Len(t, meter.MeasurementBatches, 1) | ||||
| 	if len(meter.MeasurementBatches) < 1 { | ||||
| 	assert.Len(t, mock.MeasurementBatches, 1) | ||||
| 	if len(mock.MeasurementBatches) < 1 { | ||||
| 		return | ||||
| 	} | ||||
| 	o := observer.(*mock.Observer) | ||||
| 	o := observer.Implementation().(*mockTest.Async) | ||||
| 	if !assert.NotNil(t, o) { | ||||
| 		return | ||||
| 	} | ||||
| 	ourLabelSet := labels.(*mock.LabelSet) | ||||
| 	got := meter.MeasurementBatches[0] | ||||
| 	ourLabelSet := labels.(*mockTest.LabelSet) | ||||
| 	got := mock.MeasurementBatches[0] | ||||
| 	assert.Equal(t, ourLabelSet, got.LabelSet) | ||||
| 	assert.Len(t, got.Measurements, 1) | ||||
| 	if len(got.Measurements) < 1 { | ||||
| 		return | ||||
| 	} | ||||
| 	measurement := got.Measurements[0] | ||||
| 	assert.Equal(t, o.Instrument, measurement.Instrument) | ||||
| 	assert.Equal(t, o, measurement.Instrument.Implementation().(*mockTest.Async)) | ||||
| 	ft := fortyTwo(t, kind) | ||||
| 	assert.Equal(t, 0, measurement.Number.CompareNumber(kind, ft)) | ||||
| } | ||||
| @@ -275,36 +277,47 @@ func fortyTwo(t *testing.T, kind core.NumberKind) core.Number { | ||||
| 	return core.NewInt64Number(0) | ||||
| } | ||||
|  | ||||
| type testWrappedInst struct{} | ||||
|  | ||||
| func (*testWrappedInst) Bind(labels metric.LabelSet) metric.BoundInstrumentImpl { | ||||
| 	panic("Not called") | ||||
| type testWrappedMeter struct { | ||||
| } | ||||
|  | ||||
| func (*testWrappedInst) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { | ||||
| 	panic("Not called") | ||||
| var _ metric.MeterImpl = testWrappedMeter{} | ||||
|  | ||||
| func (testWrappedMeter) Labels(...core.KeyValue) metric.LabelSet { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (testWrappedMeter) RecordBatch(context.Context, metric.LabelSet, ...metric.Measurement) { | ||||
| } | ||||
|  | ||||
| func (testWrappedMeter) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| func (testWrappedMeter) NewAsyncInstrument(_ metric.Descriptor, _ func(func(core.Number, metric.LabelSet))) (metric.AsyncImpl, error) { | ||||
| 	return nil, errors.New("Test wrap error") | ||||
| } | ||||
|  | ||||
| func TestWrappedInstrumentError(t *testing.T) { | ||||
| 	i0 := &testWrappedInst{} | ||||
| 	e0 := errors.New("Test wrap error") | ||||
| 	inst, err := metric.WrapInt64MeasureInstrument(i0, e0) | ||||
| 	impl := &testWrappedMeter{} | ||||
| 	meter := metric.WrapMeterImpl(impl) | ||||
|  | ||||
| 	// Check that error passes through w/o modifying instrument. | ||||
| 	require.Equal(t, inst.Impl().(*testWrappedInst), i0) | ||||
| 	require.Equal(t, err, e0) | ||||
| 	measure, err := meter.NewInt64Measure("test.measure") | ||||
|  | ||||
| 	// Check that nil instrument is handled. | ||||
| 	inst, err = metric.WrapInt64MeasureInstrument(nil, e0) | ||||
| 	require.Equal(t, err, metric.ErrSDKReturnedNilImpl) | ||||
| 	require.NotNil(t, measure.SyncImpl()) | ||||
|  | ||||
| 	require.Equal(t, err, e0) | ||||
| 	require.NotNil(t, inst) | ||||
| 	require.NotNil(t, inst.Impl()) | ||||
|  | ||||
| 	// Check that nil instrument generates an error. | ||||
| 	inst, err = metric.WrapInt64MeasureInstrument(nil, nil) | ||||
| 	observer, err := meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) {}) | ||||
|  | ||||
| 	require.NotNil(t, err) | ||||
| 	require.NotNil(t, inst) | ||||
| 	require.NotNil(t, inst.Impl()) | ||||
| 	require.NotNil(t, observer.AsyncImpl()) | ||||
| } | ||||
|  | ||||
| func TestNilCallbackObserverNoop(t *testing.T) { | ||||
| 	// Tests that a nil callback yields a no-op observer without error. | ||||
| 	_, meter := mockTest.NewMeter() | ||||
|  | ||||
| 	observer := Must(meter).RegisterInt64Observer("test.observer", nil) | ||||
|  | ||||
| 	_, ok := observer.AsyncImpl().(metric.NoopAsync) | ||||
| 	require.True(t, ok) | ||||
| } | ||||
|   | ||||
| @@ -21,45 +21,56 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| ) | ||||
|  | ||||
| type commonMetric struct { | ||||
| 	instrument InstrumentImpl | ||||
| type syncInstrument struct { | ||||
| 	instrument SyncImpl | ||||
| } | ||||
|  | ||||
| type commonBoundInstrument struct { | ||||
| 	boundInstrument BoundInstrumentImpl | ||||
| type syncBoundInstrument struct { | ||||
| 	boundInstrument BoundSyncImpl | ||||
| } | ||||
|  | ||||
| type asyncInstrument struct { | ||||
| 	instrument AsyncImpl | ||||
| } | ||||
|  | ||||
| var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") | ||||
|  | ||||
| func (m commonMetric) bind(labels LabelSet) commonBoundInstrument { | ||||
| 	return newCommonBoundInstrument(m.instrument.Bind(labels)) | ||||
| func (s syncInstrument) bind(labels LabelSet) syncBoundInstrument { | ||||
| 	return newSyncBoundInstrument(s.instrument.Bind(labels)) | ||||
| } | ||||
|  | ||||
| func (m commonMetric) float64Measurement(value float64) Measurement { | ||||
| 	return newMeasurement(m.instrument, core.NewFloat64Number(value)) | ||||
| func (s syncInstrument) float64Measurement(value float64) Measurement { | ||||
| 	return newMeasurement(s.instrument, core.NewFloat64Number(value)) | ||||
| } | ||||
|  | ||||
| func (m commonMetric) int64Measurement(value int64) Measurement { | ||||
| 	return newMeasurement(m.instrument, core.NewInt64Number(value)) | ||||
| func (s syncInstrument) int64Measurement(value int64) Measurement { | ||||
| 	return newMeasurement(s.instrument, core.NewInt64Number(value)) | ||||
| } | ||||
|  | ||||
| func (m commonMetric) directRecord(ctx context.Context, number core.Number, labels LabelSet) { | ||||
| 	m.instrument.RecordOne(ctx, number, labels) | ||||
| func (s syncInstrument) directRecord(ctx context.Context, number core.Number, labels LabelSet) { | ||||
| 	s.instrument.RecordOne(ctx, number, labels) | ||||
| } | ||||
|  | ||||
| func (m commonMetric) Impl() InstrumentImpl { | ||||
| 	return m.instrument | ||||
| func (s syncInstrument) SyncImpl() SyncImpl { | ||||
| 	return s.instrument | ||||
| } | ||||
|  | ||||
| func (h commonBoundInstrument) directRecord(ctx context.Context, number core.Number) { | ||||
| func (h syncBoundInstrument) directRecord(ctx context.Context, number core.Number) { | ||||
| 	h.boundInstrument.RecordOne(ctx, number) | ||||
| } | ||||
|  | ||||
| func (h commonBoundInstrument) Unbind() { | ||||
| func (h syncBoundInstrument) Unbind() { | ||||
| 	h.boundInstrument.Unbind() | ||||
| } | ||||
|  | ||||
| func newCommonMetric(instrument InstrumentImpl, err error) (commonMetric, error) { | ||||
| func (a asyncInstrument) AsyncImpl() AsyncImpl { | ||||
| 	return a.instrument | ||||
| } | ||||
|  | ||||
| // checkNewSync receives an SyncImpl and potential | ||||
| // error, and returns the same types, checking for and ensuring that | ||||
| // the returned interface is not nil. | ||||
| func checkNewSync(instrument SyncImpl, err error) (syncInstrument, error) { | ||||
| 	if instrument == nil { | ||||
| 		if err == nil { | ||||
| 			err = ErrSDKReturnedNilImpl | ||||
| @@ -69,22 +80,37 @@ func newCommonMetric(instrument InstrumentImpl, err error) (commonMetric, error) | ||||
| 		// together and use a tag for the original name, e.g., | ||||
| 		//   name = 'invalid.counter.int64' | ||||
| 		//   label = 'original-name=duplicate-counter-name' | ||||
| 		instrument = noopInstrument{} | ||||
| 		instrument = NoopSync{} | ||||
| 	} | ||||
| 	return commonMetric{ | ||||
| 	return syncInstrument{ | ||||
| 		instrument: instrument, | ||||
| 	}, err | ||||
| } | ||||
|  | ||||
| func newCommonBoundInstrument(boundInstrument BoundInstrumentImpl) commonBoundInstrument { | ||||
| 	return commonBoundInstrument{ | ||||
| func newSyncBoundInstrument(boundInstrument BoundSyncImpl) syncBoundInstrument { | ||||
| 	return syncBoundInstrument{ | ||||
| 		boundInstrument: boundInstrument, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newMeasurement(instrument InstrumentImpl, number core.Number) Measurement { | ||||
| func newMeasurement(instrument SyncImpl, number core.Number) Measurement { | ||||
| 	return Measurement{ | ||||
| 		instrument: instrument, | ||||
| 		number:     number, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // checkNewAsync receives an AsyncImpl and potential | ||||
| // error, and returns the same types, checking for and ensuring that | ||||
| // the returned interface is not nil. | ||||
| func checkNewAsync(instrument AsyncImpl, err error) (asyncInstrument, error) { | ||||
| 	if instrument == nil { | ||||
| 		if err == nil { | ||||
| 			err = ErrSDKReturnedNilImpl | ||||
| 		} | ||||
| 		instrument = NoopAsync{} | ||||
| 	} | ||||
| 	return asyncInstrument{ | ||||
| 		instrument: instrument, | ||||
| 	}, err | ||||
| } | ||||
|   | ||||
| @@ -22,26 +22,26 @@ import ( | ||||
|  | ||||
| // Float64Counter is a metric that accumulates float64 values. | ||||
| type Float64Counter struct { | ||||
| 	commonMetric | ||||
| 	syncInstrument | ||||
| } | ||||
|  | ||||
| // Int64Counter is a metric that accumulates int64 values. | ||||
| type Int64Counter struct { | ||||
| 	commonMetric | ||||
| 	syncInstrument | ||||
| } | ||||
|  | ||||
| // BoundFloat64Counter is a bound instrument for Float64Counter. | ||||
| // | ||||
| // It inherits the Unbind function from commonBoundInstrument. | ||||
| // It inherits the Unbind function from syncBoundInstrument. | ||||
| type BoundFloat64Counter struct { | ||||
| 	commonBoundInstrument | ||||
| 	syncBoundInstrument | ||||
| } | ||||
|  | ||||
| // BoundInt64Counter is a boundInstrument for Int64Counter. | ||||
| // | ||||
| // It inherits the Unbind function from commonBoundInstrument. | ||||
| // It inherits the Unbind function from syncBoundInstrument. | ||||
| type BoundInt64Counter struct { | ||||
| 	commonBoundInstrument | ||||
| 	syncBoundInstrument | ||||
| } | ||||
|  | ||||
| // Bind creates a bound instrument for this counter. The labels should | ||||
| @@ -52,7 +52,7 @@ type BoundInt64Counter struct { | ||||
| // counter with the WithKeys option, then the missing value will be | ||||
| // treated as unspecified. | ||||
| func (c Float64Counter) Bind(labels LabelSet) (h BoundFloat64Counter) { | ||||
| 	h.commonBoundInstrument = c.bind(labels) | ||||
| 	h.syncBoundInstrument = c.bind(labels) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -64,7 +64,7 @@ func (c Float64Counter) Bind(labels LabelSet) (h BoundFloat64Counter) { | ||||
| // counter with the WithKeys option, then the missing value will be | ||||
| // treated as unspecified. | ||||
| func (c Int64Counter) Bind(labels LabelSet) (h BoundInt64Counter) { | ||||
| 	h.commonBoundInstrument = c.bind(labels) | ||||
| 	h.syncBoundInstrument = c.bind(labels) | ||||
| 	return | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -61,8 +61,7 @@ | ||||
| // function - this permits the reported values only to go | ||||
| // up. Reporting of the new values happens asynchronously, with the | ||||
| // use of a callback passed to the Register*Observer function. The | ||||
| // callback can report multiple values. To unregister the observer, | ||||
| // call Unregister on it. | ||||
| // callback can report multiple values. There is no unregister function. | ||||
| // | ||||
| // Counters and measures support creating bound instruments for a | ||||
| // potentially more efficient reporting. The bound instruments have | ||||
|   | ||||
| @@ -8,14 +8,14 @@ func _() { | ||||
| 	// An "invalid array index" compiler error signifies that the constant values have changed. | ||||
| 	// Re-run the stringer command to generate them again. | ||||
| 	var x [1]struct{} | ||||
| 	_ = x[CounterKind-0] | ||||
| 	_ = x[MeasureKind-1] | ||||
| 	_ = x[ObserverKind-2] | ||||
| 	_ = x[MeasureKind-0] | ||||
| 	_ = x[ObserverKind-1] | ||||
| 	_ = x[CounterKind-2] | ||||
| } | ||||
| 
 | ||||
| const _Kind_name = "CounterKindMeasureKindObserverKind" | ||||
| const _Kind_name = "MeasureKindObserverKindCounterKind" | ||||
| 
 | ||||
| var _Kind_index = [...]uint8{0, 11, 22, 34} | ||||
| var _Kind_index = [...]uint8{0, 11, 23, 34} | ||||
| 
 | ||||
| func (i Kind) String() string { | ||||
| 	if i < 0 || i >= Kind(len(_Kind_index)-1) { | ||||
| @@ -22,26 +22,26 @@ import ( | ||||
|  | ||||
| // Float64Measure is a metric that records float64 values. | ||||
| type Float64Measure struct { | ||||
| 	commonMetric | ||||
| 	syncInstrument | ||||
| } | ||||
|  | ||||
| // Int64Measure is a metric that records int64 values. | ||||
| type Int64Measure struct { | ||||
| 	commonMetric | ||||
| 	syncInstrument | ||||
| } | ||||
|  | ||||
| // BoundFloat64Measure is a bound instrument for Float64Measure. | ||||
| // | ||||
| // It inherits the Unbind function from commonBoundInstrument. | ||||
| // It inherits the Unbind function from syncBoundInstrument. | ||||
| type BoundFloat64Measure struct { | ||||
| 	commonBoundInstrument | ||||
| 	syncBoundInstrument | ||||
| } | ||||
|  | ||||
| // BoundInt64Measure is a bound instrument for Int64Measure. | ||||
| // | ||||
| // It inherits the Unbind function from commonBoundInstrument. | ||||
| // It inherits the Unbind function from syncBoundInstrument. | ||||
| type BoundInt64Measure struct { | ||||
| 	commonBoundInstrument | ||||
| 	syncBoundInstrument | ||||
| } | ||||
|  | ||||
| // Bind creates a bound instrument for this measure. The labels should | ||||
| @@ -52,7 +52,7 @@ type BoundInt64Measure struct { | ||||
| // measure with the WithKeys option, then the missing value will be | ||||
| // treated as unspecified. | ||||
| func (c Float64Measure) Bind(labels LabelSet) (h BoundFloat64Measure) { | ||||
| 	h.commonBoundInstrument = c.bind(labels) | ||||
| 	h.syncBoundInstrument = c.bind(labels) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -64,7 +64,7 @@ func (c Float64Measure) Bind(labels LabelSet) (h BoundFloat64Measure) { | ||||
| // measure with the WithKeys option, then the missing value will be | ||||
| // treated as unspecified. | ||||
| func (c Int64Measure) Bind(labels LabelSet) (h BoundInt64Measure) { | ||||
| 	h.commonBoundInstrument = c.bind(labels) | ||||
| 	h.syncBoundInstrument = c.bind(labels) | ||||
| 	return | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -7,49 +7,44 @@ import ( | ||||
| ) | ||||
|  | ||||
| type NoopProvider struct{} | ||||
| type NoopMeter struct{} | ||||
|  | ||||
| type NoopMeter struct { | ||||
| } | ||||
|  | ||||
| type noopBoundInstrument struct{} | ||||
| type noopLabelSet struct{} | ||||
| type noopInstrument struct{} | ||||
| type noopInt64Observer struct{} | ||||
| type noopFloat64Observer struct{} | ||||
| type noopBoundInstrument struct{} | ||||
| type NoopSync struct{ noopInstrument } | ||||
| type NoopAsync struct{ noopInstrument } | ||||
|  | ||||
| var _ Provider = NoopProvider{} | ||||
| var _ Meter = NoopMeter{} | ||||
| var _ InstrumentImpl = noopInstrument{} | ||||
| var _ BoundInstrumentImpl = noopBoundInstrument{} | ||||
| var _ SyncImpl = NoopSync{} | ||||
| var _ BoundSyncImpl = noopBoundInstrument{} | ||||
| var _ LabelSet = noopLabelSet{} | ||||
| var _ Int64Observer = noopInt64Observer{} | ||||
| var _ Float64Observer = noopFloat64Observer{} | ||||
| var _ AsyncImpl = NoopAsync{} | ||||
|  | ||||
| func (NoopProvider) Meter(name string) Meter { | ||||
| 	return NoopMeter{} | ||||
| } | ||||
|  | ||||
| func (noopInstrument) Implementation() interface{} { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (noopInstrument) Descriptor() Descriptor { | ||||
| 	return Descriptor{} | ||||
| } | ||||
|  | ||||
| func (noopBoundInstrument) RecordOne(context.Context, core.Number) { | ||||
| } | ||||
|  | ||||
| func (noopBoundInstrument) Unbind() { | ||||
| } | ||||
|  | ||||
| func (noopInstrument) Bind(LabelSet) BoundInstrumentImpl { | ||||
| func (NoopSync) Bind(LabelSet) BoundSyncImpl { | ||||
| 	return noopBoundInstrument{} | ||||
| } | ||||
|  | ||||
| func (noopInstrument) RecordOne(context.Context, core.Number, LabelSet) { | ||||
| } | ||||
|  | ||||
| func (noopInstrument) Meter() Meter { | ||||
| 	return NoopMeter{} | ||||
| } | ||||
|  | ||||
| func (noopInt64Observer) Unregister() { | ||||
| } | ||||
|  | ||||
| func (noopFloat64Observer) Unregister() { | ||||
| func (NoopSync) RecordOne(context.Context, core.Number, LabelSet) { | ||||
| } | ||||
|  | ||||
| func (NoopMeter) Labels(...core.KeyValue) LabelSet { | ||||
| @@ -59,26 +54,26 @@ func (NoopMeter) Labels(...core.KeyValue) LabelSet { | ||||
| func (NoopMeter) RecordBatch(context.Context, LabelSet, ...Measurement) { | ||||
| } | ||||
|  | ||||
| func (NoopMeter) NewInt64Counter(name string, cos ...Option) (Int64Counter, error) { | ||||
| 	return WrapInt64CounterInstrument(noopInstrument{}, nil) | ||||
| func (NoopMeter) NewInt64Counter(string, ...Option) (Int64Counter, error) { | ||||
| 	return Int64Counter{syncInstrument{NoopSync{}}}, nil | ||||
| } | ||||
|  | ||||
| func (NoopMeter) NewFloat64Counter(name string, cos ...Option) (Float64Counter, error) { | ||||
| 	return WrapFloat64CounterInstrument(noopInstrument{}, nil) | ||||
| func (NoopMeter) NewFloat64Counter(string, ...Option) (Float64Counter, error) { | ||||
| 	return Float64Counter{syncInstrument{NoopSync{}}}, nil | ||||
| } | ||||
|  | ||||
| func (NoopMeter) NewInt64Measure(name string, mos ...Option) (Int64Measure, error) { | ||||
| 	return WrapInt64MeasureInstrument(noopInstrument{}, nil) | ||||
| func (NoopMeter) NewInt64Measure(string, ...Option) (Int64Measure, error) { | ||||
| 	return Int64Measure{syncInstrument{NoopSync{}}}, nil | ||||
| } | ||||
|  | ||||
| func (NoopMeter) NewFloat64Measure(name string, mos ...Option) (Float64Measure, error) { | ||||
| 	return WrapFloat64MeasureInstrument(noopInstrument{}, nil) | ||||
| func (NoopMeter) NewFloat64Measure(string, ...Option) (Float64Measure, error) { | ||||
| 	return Float64Measure{syncInstrument{NoopSync{}}}, nil | ||||
| } | ||||
|  | ||||
| func (NoopMeter) RegisterInt64Observer(name string, callback Int64ObserverCallback, oos ...Option) (Int64Observer, error) { | ||||
| 	return noopInt64Observer{}, nil | ||||
| func (NoopMeter) RegisterInt64Observer(string, Int64ObserverCallback, ...Option) (Int64Observer, error) { | ||||
| 	return Int64Observer{asyncInstrument{NoopAsync{}}}, nil | ||||
| } | ||||
|  | ||||
| func (NoopMeter) RegisterFloat64Observer(name string, callback Float64ObserverCallback, oos ...Option) (Float64Observer, error) { | ||||
| 	return noopFloat64Observer{}, nil | ||||
| func (NoopMeter) RegisterFloat64Observer(string, Float64ObserverCallback, ...Option) (Float64Observer, error) { | ||||
| 	return Float64Observer{asyncInstrument{NoopAsync{}}}, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										47
									
								
								api/metric/observer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								api/metric/observer.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| // Copyright 2020, OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package metric | ||||
|  | ||||
| // Int64ObserverResult is an interface for reporting integral | ||||
| // observations. | ||||
| type Int64ObserverResult interface { | ||||
| 	Observe(value int64, labels LabelSet) | ||||
| } | ||||
|  | ||||
| // Float64ObserverResult is an interface for reporting floating point | ||||
| // observations. | ||||
| type Float64ObserverResult interface { | ||||
| 	Observe(value float64, labels LabelSet) | ||||
| } | ||||
|  | ||||
| // Int64ObserverCallback is a type of callback that integral | ||||
| // observers run. | ||||
| type Int64ObserverCallback func(result Int64ObserverResult) | ||||
|  | ||||
| // Float64ObserverCallback is a type of callback that floating point | ||||
| // observers run. | ||||
| type Float64ObserverCallback func(result Float64ObserverResult) | ||||
|  | ||||
| // Int64Observer is a metric that captures a set of int64 values at a | ||||
| // point in time. | ||||
| type Int64Observer struct { | ||||
| 	asyncInstrument | ||||
| } | ||||
|  | ||||
| // Float64Observer is a metric that captures a set of float64 values | ||||
| // at a point in time. | ||||
| type Float64Observer struct { | ||||
| 	asyncInstrument | ||||
| } | ||||
| @@ -20,6 +20,32 @@ 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`. | ||||
| type MeterImpl interface { | ||||
| 	// Labels returns a reference to a set of labels that cannot | ||||
| 	// be read by the application. | ||||
| 	Labels(...core.KeyValue) LabelSet | ||||
|  | ||||
| 	// RecordBatch atomically records a batch of measurements. | ||||
| 	RecordBatch(context.Context, LabelSet, ...Measurement) | ||||
|  | ||||
| 	// NewSyncInstrument returns a newly constructed | ||||
| 	// synchronous instrument implementation or an error, should | ||||
| 	// one occur. | ||||
| 	NewSyncInstrument(descriptor Descriptor) (SyncImpl, error) | ||||
|  | ||||
| 	// NewAsyncInstrument returns a newly constructed | ||||
| 	// asynchronous instrument implementation or an error, should | ||||
| 	// one occur. | ||||
| 	NewAsyncInstrument( | ||||
| 		descriptor Descriptor, | ||||
| 		callback func(func(core.Number, LabelSet)), | ||||
| 	) (AsyncImpl, error) | ||||
| } | ||||
|  | ||||
| // LabelSetDelegate is a general-purpose delegating implementation of | ||||
| // the LabelSet interface.  This is implemented by the default | ||||
| // Provider returned by api/global.SetMeterProvider(), and should be | ||||
| @@ -29,21 +55,36 @@ type LabelSetDelegate interface { | ||||
| 	Delegate() LabelSet | ||||
| } | ||||
|  | ||||
| // InstrumentImpl is the implementation-level interface Set/Add/Record | ||||
| // individual metrics without precomputed labels. | ||||
| // InstrumentImpl is a common interface for synchronous and | ||||
| // asynchronous instruments. | ||||
| type InstrumentImpl interface { | ||||
| 	// Bind creates a Bound Instrument to record metrics with | ||||
| 	// precomputed labels. | ||||
| 	Bind(labels LabelSet) BoundInstrumentImpl | ||||
| 	// Implementation returns the underlying implementation of the | ||||
| 	// instrument, which allows the implementation to gain access | ||||
| 	// to its own representation especially from a `Measurement`. | ||||
| 	Implementation() interface{} | ||||
|  | ||||
| 	// RecordOne allows the SDK to observe a single metric event. | ||||
| 	// Descriptor returns a copy of the instrument's Descriptor. | ||||
| 	Descriptor() Descriptor | ||||
| } | ||||
|  | ||||
| // SyncImpl is the implementation-level interface to a generic | ||||
| // synchronous instrument (e.g., Measure and Counter instruments). | ||||
| type SyncImpl interface { | ||||
| 	InstrumentImpl | ||||
|  | ||||
| 	// Bind creates an implementation-level bound instrument, | ||||
| 	// binding a label set with this instrument implementation. | ||||
| 	Bind(labels LabelSet) BoundSyncImpl | ||||
|  | ||||
| 	// RecordOne captures a single synchronous metric event. | ||||
| 	RecordOne(ctx context.Context, number core.Number, labels LabelSet) | ||||
| } | ||||
|  | ||||
| // BoundInstrumentImpl is the implementation-level interface to Set/Add/Record | ||||
| // individual metrics with precomputed labels. | ||||
| type BoundInstrumentImpl interface { | ||||
| 	// RecordOne allows the SDK to observe a single metric event. | ||||
| // BoundSyncImpl is the implementation-level interface to a | ||||
| // generic bound synchronous instrument | ||||
| type BoundSyncImpl interface { | ||||
|  | ||||
| 	// RecordOne captures a single synchronous metric event. | ||||
| 	RecordOne(ctx context.Context, number core.Number) | ||||
|  | ||||
| 	// Unbind frees the resources associated with this bound instrument. It | ||||
| @@ -51,42 +92,38 @@ type BoundInstrumentImpl interface { | ||||
| 	Unbind() | ||||
| } | ||||
|  | ||||
| // WrapInt64CounterInstrument wraps the instrument in the type-safe | ||||
| // wrapper as an integral counter. | ||||
| // | ||||
| // It is mostly intended for SDKs. | ||||
| func WrapInt64CounterInstrument(instrument InstrumentImpl, err error) (Int64Counter, error) { | ||||
| 	common, err := newCommonMetric(instrument, err) | ||||
| 	return Int64Counter{commonMetric: common}, err | ||||
| // AsyncImpl is an implementation-level interface to an | ||||
| // asynchronous instrument (e.g., Observer instruments). | ||||
| type AsyncImpl interface { | ||||
| 	InstrumentImpl | ||||
|  | ||||
| 	// Note: An `Unregister()` API could be supported here. | ||||
| } | ||||
|  | ||||
| // WrapFloat64CounterInstrument wraps the instrument in the type-safe | ||||
| // wrapper as an floating point counter. | ||||
| // | ||||
| // It is mostly intended for SDKs. | ||||
| func WrapFloat64CounterInstrument(instrument InstrumentImpl, err error) (Float64Counter, error) { | ||||
| 	common, err := newCommonMetric(instrument, err) | ||||
| 	return Float64Counter{commonMetric: common}, err | ||||
| // wrappedMeterImpl implements the `Meter` interface given a | ||||
| // `MeterImpl` implementation. | ||||
| type wrappedMeterImpl struct { | ||||
| 	impl MeterImpl | ||||
| } | ||||
|  | ||||
| // WrapInt64MeasureInstrument wraps the instrument in the type-safe | ||||
| // wrapper as an integral measure. | ||||
| // | ||||
| // It is mostly intended for SDKs. | ||||
| func WrapInt64MeasureInstrument(instrument InstrumentImpl, err error) (Int64Measure, error) { | ||||
| 	common, err := newCommonMetric(instrument, err) | ||||
| 	return Int64Measure{commonMetric: common}, err | ||||
| // int64ObserverResult is an adapter for int64-valued asynchronous | ||||
| // callbacks. | ||||
| type int64ObserverResult struct { | ||||
| 	observe func(core.Number, LabelSet) | ||||
| } | ||||
|  | ||||
| // WrapFloat64MeasureInstrument wraps the instrument in the type-safe | ||||
| // wrapper as an floating point measure. | ||||
| // | ||||
| // It is mostly intended for SDKs. | ||||
| func WrapFloat64MeasureInstrument(instrument InstrumentImpl, err error) (Float64Measure, error) { | ||||
| 	common, err := newCommonMetric(instrument, err) | ||||
| 	return Float64Measure{commonMetric: common}, err | ||||
| // float64ObserverResult is an adapter for float64-valued asynchronous | ||||
| // callbacks. | ||||
| type float64ObserverResult struct { | ||||
| 	observe func(core.Number, LabelSet) | ||||
| } | ||||
|  | ||||
| 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 | ||||
| @@ -95,3 +132,145 @@ func Configure(opts []Option) Config { | ||||
| 	} | ||||
| 	return config | ||||
| } | ||||
|  | ||||
| // WrapMeterImpl constructs a `Meter` implementation from a | ||||
| // `MeterImpl` implementation. | ||||
| func WrapMeterImpl(impl MeterImpl) Meter { | ||||
| 	return &wrappedMeterImpl{ | ||||
| 		impl: impl, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // UnwrapImpl returns a `MeterImpl` given a `Meter` that was | ||||
| // constructed using `WrapMeterImpl`. | ||||
| func UnwrapImpl(meter Meter) (MeterImpl, bool) { | ||||
| 	if wrap, ok := meter.(*wrappedMeterImpl); ok { | ||||
| 		return wrap.impl, true | ||||
| 	} | ||||
| 	return nil, false | ||||
| } | ||||
|  | ||||
| func (m *wrappedMeterImpl) Labels(labels ...core.KeyValue) LabelSet { | ||||
| 	return m.impl.Labels(labels...) | ||||
| } | ||||
|  | ||||
| func (m *wrappedMeterImpl) RecordBatch(ctx context.Context, ls LabelSet, ms ...Measurement) { | ||||
| 	m.impl.RecordBatch(ctx, ls, ms...) | ||||
| } | ||||
|  | ||||
| func (m *wrappedMeterImpl) newSync(name string, metricKind Kind, numberKind core.NumberKind, opts []Option) (SyncImpl, error) { | ||||
| 	return m.impl.NewSyncInstrument(NewDescriptor(name, metricKind, numberKind, opts...)) | ||||
| } | ||||
|  | ||||
| func (m *wrappedMeterImpl) NewInt64Counter(name string, opts ...Option) (Int64Counter, error) { | ||||
| 	return WrapInt64CounterInstrument( | ||||
| 		m.newSync(name, CounterKind, core.Int64NumberKind, opts)) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	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, core.Float64NumberKind, opts)) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	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, core.Int64NumberKind, opts)) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	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, core.Float64NumberKind, opts)) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	common, err := checkNewSync(syncInst, err) | ||||
| 	return Float64Measure{syncInstrument: common}, err | ||||
| } | ||||
|  | ||||
| func (m *wrappedMeterImpl) newAsync(name string, mkind Kind, nkind core.NumberKind, opts []Option, callback func(func(core.Number, LabelSet))) (AsyncImpl, error) { | ||||
| 	return m.impl.NewAsyncInstrument( | ||||
| 		NewDescriptor(name, mkind, nkind, opts...), | ||||
| 		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, core.Int64NumberKind, opts, | ||||
| 			func(observe func(core.Number, LabelSet)) { | ||||
| 				// 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` is nil (in which case a No-op is substituted), | ||||
| // otherwise the error passes through. | ||||
| 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, core.Float64NumberKind, opts, | ||||
| 			func(observe func(core.Number, LabelSet)) { | ||||
| 				callback(float64ObserverResult{observe}) | ||||
| 			})) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	common, err := checkNewAsync(asyncInst, err) | ||||
| 	return Float64Observer{asyncInstrument: common}, err | ||||
| } | ||||
|  | ||||
| func (io int64ObserverResult) Observe(value int64, labels LabelSet) { | ||||
| 	io.observe(core.NewInt64Number(value), labels) | ||||
| } | ||||
|  | ||||
| func (fo float64ObserverResult) Observe(value float64, labels LabelSet) { | ||||
| 	fo.observe(core.NewFloat64Number(value), labels) | ||||
| } | ||||
|   | ||||
| @@ -77,11 +77,10 @@ func main() { | ||||
| 	oneMetricCB := func(result metric.Float64ObserverResult) { | ||||
| 		result.Observe(1, commonLabels) | ||||
| 	} | ||||
| 	oneMetric := metric.Must(meter).RegisterFloat64Observer("ex.com.one", oneMetricCB, | ||||
| 	_ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", oneMetricCB, | ||||
| 		metric.WithKeys(fooKey, barKey, lemonsKey), | ||||
| 		metric.WithDescription("An observer set to 1.0"), | ||||
| 	) | ||||
| 	defer oneMetric.Unregister() | ||||
|  | ||||
| 	measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two") | ||||
|  | ||||
|   | ||||
| @@ -61,11 +61,10 @@ func main() { | ||||
| 		(*observerLock).RUnlock() | ||||
| 		result.Observe(value, labelset) | ||||
| 	} | ||||
| 	oneMetric := metric.Must(meter).RegisterFloat64Observer("ex.com.one", cb, | ||||
| 	_ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", cb, | ||||
| 		metric.WithKeys(fooKey, barKey, lemonsKey), | ||||
| 		metric.WithDescription("A measure set to 1.0"), | ||||
| 	) | ||||
| 	defer oneMetric.Unregister() | ||||
|  | ||||
| 	measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two", metric.WithKeys(key.New("A"))) | ||||
| 	measureThree := metric.Must(meter).NewFloat64Counter("ex.com.three") | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/dogstatsd" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/internal/statsd" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/test" | ||||
| @@ -44,12 +45,12 @@ func TestDogstatsLabels(t *testing.T) { | ||||
| 			ctx := context.Background() | ||||
| 			checkpointSet := test.NewCheckpointSet(encoder) | ||||
|  | ||||
| 			desc := export.NewDescriptor("test.name", export.CounterKind, nil, "", "", core.Int64NumberKind) | ||||
| 			desc := metric.NewDescriptor("test.name", metric.CounterKind, core.Int64NumberKind) | ||||
| 			cagg := sum.New() | ||||
| 			_ = cagg.Update(ctx, core.NewInt64Number(123), desc) | ||||
| 			cagg.Checkpoint(ctx, desc) | ||||
| 			_ = cagg.Update(ctx, core.NewInt64Number(123), &desc) | ||||
| 			cagg.Checkpoint(ctx, &desc) | ||||
|  | ||||
| 			checkpointSet.Add(desc, cagg, key.New("A").String("B")) | ||||
| 			checkpointSet.Add(&desc, cagg, key.New("A").String("B")) | ||||
|  | ||||
| 			var buf bytes.Buffer | ||||
| 			exp, err := dogstatsd.NewRawExporter(dogstatsd.Config{ | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/api/unit" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/internal/statsd" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/test" | ||||
| @@ -123,14 +124,14 @@ timer.B.D:%s|ms | ||||
| 					} | ||||
|  | ||||
| 					checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
| 					cdesc := export.NewDescriptor( | ||||
| 						"counter", export.CounterKind, nil, "", "", nkind) | ||||
| 					gdesc := export.NewDescriptor( | ||||
| 						"observer", export.ObserverKind, nil, "", "", nkind) | ||||
| 					mdesc := export.NewDescriptor( | ||||
| 						"measure", export.MeasureKind, nil, "", "", nkind) | ||||
| 					tdesc := export.NewDescriptor( | ||||
| 						"timer", export.MeasureKind, nil, "", unit.Milliseconds, nkind) | ||||
| 					cdesc := metric.NewDescriptor( | ||||
| 						"counter", metric.CounterKind, nkind) | ||||
| 					gdesc := metric.NewDescriptor( | ||||
| 						"observer", metric.ObserverKind, nkind) | ||||
| 					mdesc := metric.NewDescriptor( | ||||
| 						"measure", metric.MeasureKind, nkind) | ||||
| 					tdesc := metric.NewDescriptor( | ||||
| 						"timer", metric.MeasureKind, nkind, metric.WithUnit(unit.Milliseconds)) | ||||
|  | ||||
| 					labels := []core.KeyValue{ | ||||
| 						key.New("A").String("B"), | ||||
| @@ -138,10 +139,10 @@ timer.B.D:%s|ms | ||||
| 					} | ||||
| 					const value = 123.456 | ||||
|  | ||||
| 					checkpointSet.AddCounter(cdesc, value, labels...) | ||||
| 					checkpointSet.AddLastValue(gdesc, value, labels...) | ||||
| 					checkpointSet.AddMeasure(mdesc, value, labels...) | ||||
| 					checkpointSet.AddMeasure(tdesc, value, labels...) | ||||
| 					checkpointSet.AddCounter(&cdesc, value, labels...) | ||||
| 					checkpointSet.AddLastValue(&gdesc, value, labels...) | ||||
| 					checkpointSet.AddMeasure(&mdesc, value, labels...) | ||||
| 					checkpointSet.AddMeasure(&tdesc, value, labels...) | ||||
|  | ||||
| 					err = exp.Export(ctx, checkpointSet) | ||||
| 					require.Nil(t, err) | ||||
| @@ -285,7 +286,7 @@ func TestPacketSplit(t *testing.T) { | ||||
| 			} | ||||
|  | ||||
| 			checkpointSet := test.NewCheckpointSet(adapter.LabelEncoder) | ||||
| 			desc := export.NewDescriptor("counter", export.CounterKind, nil, "", "", core.Int64NumberKind) | ||||
| 			desc := metric.NewDescriptor("counter", metric.CounterKind, core.Int64NumberKind) | ||||
|  | ||||
| 			var expected []string | ||||
|  | ||||
| @@ -295,7 +296,7 @@ func TestPacketSplit(t *testing.T) { | ||||
| 				offset += nkeys | ||||
| 				expect := fmt.Sprint("counter:100|c", adapter.LabelEncoder.Encode(labels), "\n") | ||||
| 				expected = append(expected, expect) | ||||
| 				checkpointSet.AddCounter(desc, 100, labels...) | ||||
| 				checkpointSet.AddCounter(&desc, 100, labels...) | ||||
| 			}) | ||||
|  | ||||
| 			err = exp.Export(ctx, checkpointSet) | ||||
|   | ||||
| @@ -12,10 +12,10 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/prometheus" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/test" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric" | ||||
| 	sdk "go.opentelemetry.io/otel/sdk/metric" | ||||
| ) | ||||
|  | ||||
| func TestPrometheusExporter(t *testing.T) { | ||||
| @@ -27,29 +27,29 @@ func TestPrometheusExporter(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	var expected []string | ||||
| 	checkpointSet := test.NewCheckpointSet(metric.NewDefaultLabelEncoder()) | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	counter := export.NewDescriptor( | ||||
| 		"counter", export.CounterKind, nil, "", "", core.Float64NumberKind) | ||||
| 	lastValue := export.NewDescriptor( | ||||
| 		"lastvalue", export.ObserverKind, nil, "", "", core.Float64NumberKind) | ||||
| 	measure := export.NewDescriptor( | ||||
| 		"measure", export.MeasureKind, nil, "", "", core.Float64NumberKind) | ||||
| 	counter := metric.NewDescriptor( | ||||
| 		"counter", metric.CounterKind, core.Float64NumberKind) | ||||
| 	lastValue := metric.NewDescriptor( | ||||
| 		"lastvalue", metric.ObserverKind, core.Float64NumberKind) | ||||
| 	measure := metric.NewDescriptor( | ||||
| 		"measure", metric.MeasureKind, core.Float64NumberKind) | ||||
|  | ||||
| 	labels := []core.KeyValue{ | ||||
| 		key.New("A").String("B"), | ||||
| 		key.New("C").String("D"), | ||||
| 	} | ||||
|  | ||||
| 	checkpointSet.AddCounter(counter, 15.3, labels...) | ||||
| 	checkpointSet.AddCounter(&counter, 15.3, labels...) | ||||
| 	expected = append(expected, `counter{A="B",C="D"} 15.3`) | ||||
|  | ||||
| 	checkpointSet.AddLastValue(lastValue, 13.2, labels...) | ||||
| 	checkpointSet.AddLastValue(&lastValue, 13.2, labels...) | ||||
| 	expected = append(expected, `lastvalue{A="B",C="D"} 13.2`) | ||||
|  | ||||
| 	checkpointSet.AddMeasure(measure, 13, labels...) | ||||
| 	checkpointSet.AddMeasure(measure, 15, labels...) | ||||
| 	checkpointSet.AddMeasure(measure, 17, labels...) | ||||
| 	checkpointSet.AddMeasure(&measure, 13, labels...) | ||||
| 	checkpointSet.AddMeasure(&measure, 15, labels...) | ||||
| 	checkpointSet.AddMeasure(&measure, 17, labels...) | ||||
| 	expected = append(expected, `measure{A="B",C="D",quantile="0.5"} 15`) | ||||
| 	expected = append(expected, `measure{A="B",C="D",quantile="0.9"} 17`) | ||||
| 	expected = append(expected, `measure{A="B",C="D",quantile="0.99"} 17`) | ||||
| @@ -61,13 +61,13 @@ func TestPrometheusExporter(t *testing.T) { | ||||
| 		key.New("C").String(""), | ||||
| 	} | ||||
|  | ||||
| 	checkpointSet.AddCounter(counter, 12, missingLabels...) | ||||
| 	checkpointSet.AddCounter(&counter, 12, missingLabels...) | ||||
| 	expected = append(expected, `counter{A="E",C=""} 12`) | ||||
|  | ||||
| 	checkpointSet.AddLastValue(lastValue, 32, missingLabels...) | ||||
| 	checkpointSet.AddLastValue(&lastValue, 32, missingLabels...) | ||||
| 	expected = append(expected, `lastvalue{A="E",C=""} 32`) | ||||
|  | ||||
| 	checkpointSet.AddMeasure(measure, 19, missingLabels...) | ||||
| 	checkpointSet.AddMeasure(&measure, 19, missingLabels...) | ||||
| 	expected = append(expected, `measure{A="E",C="",quantile="0.5"} 19`) | ||||
| 	expected = append(expected, `measure{A="E",C="",quantile="0.9"} 19`) | ||||
| 	expected = append(expected, `measure{A="E",C="",quantile="0.99"} 19`) | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/stdout" | ||||
| 	"go.opentelemetry.io/otel/exporters/metric/test" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| @@ -82,12 +83,12 @@ func TestStdoutTimestamp(t *testing.T) { | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	ctx := context.Background() | ||||
| 	desc := export.NewDescriptor("test.name", export.ObserverKind, nil, "", "", core.Int64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Int64NumberKind) | ||||
| 	lvagg := lastvalue.New() | ||||
| 	aggtest.CheckedUpdate(t, lvagg, core.NewInt64Number(321), desc) | ||||
| 	lvagg.Checkpoint(ctx, desc) | ||||
| 	aggtest.CheckedUpdate(t, lvagg, core.NewInt64Number(321), &desc) | ||||
| 	lvagg.Checkpoint(ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, lvagg) | ||||
| 	checkpointSet.Add(&desc, lvagg) | ||||
|  | ||||
| 	if err := exporter.Export(ctx, checkpointSet); err != nil { | ||||
| 		t.Fatal("Unexpected export error: ", err) | ||||
| @@ -127,12 +128,12 @@ func TestStdoutCounterFormat(t *testing.T) { | ||||
|  | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.CounterKind, nil, "", "", core.Int64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.CounterKind, core.Int64NumberKind) | ||||
| 	cagg := sum.New() | ||||
| 	aggtest.CheckedUpdate(fix.t, cagg, core.NewInt64Number(123), desc) | ||||
| 	cagg.Checkpoint(fix.ctx, desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, cagg, core.NewInt64Number(123), &desc) | ||||
| 	cagg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, cagg, key.String("A", "B"), key.String("C", "D")) | ||||
| 	checkpointSet.Add(&desc, cagg, key.String("A", "B"), key.String("C", "D")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -144,12 +145,12 @@ func TestStdoutLastValueFormat(t *testing.T) { | ||||
|  | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.ObserverKind, nil, "", "", core.Float64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Float64NumberKind) | ||||
| 	lvagg := lastvalue.New() | ||||
| 	aggtest.CheckedUpdate(fix.t, lvagg, core.NewFloat64Number(123.456), desc) | ||||
| 	lvagg.Checkpoint(fix.ctx, desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, lvagg, core.NewFloat64Number(123.456), &desc) | ||||
| 	lvagg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, lvagg, key.String("A", "B"), key.String("C", "D")) | ||||
| 	checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -161,13 +162,13 @@ func TestStdoutMinMaxSumCount(t *testing.T) { | ||||
|  | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.MeasureKind, nil, "", "", core.Float64NumberKind) | ||||
| 	magg := minmaxsumcount.New(desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(123.456), desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(876.543), desc) | ||||
| 	magg.Checkpoint(fix.ctx, desc) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) | ||||
| 	magg := minmaxsumcount.New(&desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(123.456), &desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(876.543), &desc) | ||||
| 	magg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, magg, key.String("A", "B"), key.String("C", "D")) | ||||
| 	checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -181,16 +182,16 @@ func TestStdoutMeasureFormat(t *testing.T) { | ||||
|  | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.MeasureKind, nil, "", "", core.Float64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) | ||||
| 	magg := array.New() | ||||
|  | ||||
| 	for i := 0; i < 1000; i++ { | ||||
| 		aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(float64(i)+0.5), desc) | ||||
| 		aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(float64(i)+0.5), &desc) | ||||
| 	} | ||||
|  | ||||
| 	magg.Checkpoint(fix.ctx, desc) | ||||
| 	magg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, magg, key.String("A", "B"), key.String("C", "D")) | ||||
| 	checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -222,10 +223,10 @@ func TestStdoutMeasureFormat(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestStdoutNoData(t *testing.T) { | ||||
| 	desc := export.NewDescriptor("test.name", export.MeasureKind, nil, "", "", core.Float64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) | ||||
| 	for name, tc := range map[string]export.Aggregator{ | ||||
| 		"ddsketch":       ddsketch.New(ddsketch.NewDefaultConfig(), desc), | ||||
| 		"minmaxsumcount": minmaxsumcount.New(desc), | ||||
| 		"ddsketch":       ddsketch.New(ddsketch.NewDefaultConfig(), &desc), | ||||
| 		"minmaxsumcount": minmaxsumcount.New(&desc), | ||||
| 	} { | ||||
| 		tc := tc | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| @@ -236,9 +237,9 @@ func TestStdoutNoData(t *testing.T) { | ||||
| 			checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 			magg := tc | ||||
| 			magg.Checkpoint(fix.ctx, desc) | ||||
| 			magg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 			checkpointSet.Add(desc, magg) | ||||
| 			checkpointSet.Add(&desc, magg) | ||||
|  | ||||
| 			fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -252,11 +253,11 @@ func TestStdoutLastValueNotSet(t *testing.T) { | ||||
|  | ||||
| 	checkpointSet := test.NewCheckpointSet(sdk.NewDefaultLabelEncoder()) | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.ObserverKind, nil, "", "", core.Float64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Float64NumberKind) | ||||
| 	lvagg := lastvalue.New() | ||||
| 	lvagg.Checkpoint(fix.ctx, desc) | ||||
| 	lvagg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, lvagg, key.String("A", "B"), key.String("C", "D")) | ||||
| 	checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
| @@ -270,12 +271,12 @@ func TestStdoutCounterWithUnspecifiedKeys(t *testing.T) { | ||||
|  | ||||
| 	keys := []core.Key{key.New("C"), key.New("D")} | ||||
|  | ||||
| 	desc := export.NewDescriptor("test.name", export.CounterKind, keys, "", "", core.Int64NumberKind) | ||||
| 	desc := metric.NewDescriptor("test.name", metric.CounterKind, core.Int64NumberKind, metric.WithKeys(keys...)) | ||||
| 	cagg := sum.New() | ||||
| 	aggtest.CheckedUpdate(fix.t, cagg, core.NewInt64Number(10), desc) | ||||
| 	cagg.Checkpoint(fix.ctx, desc) | ||||
| 	aggtest.CheckedUpdate(fix.t, cagg, core.NewInt64Number(10), &desc) | ||||
| 	cagg.Checkpoint(fix.ctx, &desc) | ||||
|  | ||||
| 	checkpointSet.Add(desc, cagg, key.String("A", "B")) | ||||
| 	checkpointSet.Add(&desc, cagg, key.String("A", "B")) | ||||
|  | ||||
| 	fix.Export(checkpointSet) | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"errors" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/array" | ||||
| @@ -36,7 +37,7 @@ func (p *CheckpointSet) Reset() { | ||||
| // | ||||
| // If there is an existing record with the same descriptor and LabelSet | ||||
| // the stored aggregator will be returned and should be merged. | ||||
| func (p *CheckpointSet) Add(desc *export.Descriptor, newAgg export.Aggregator, labels ...core.KeyValue) (agg export.Aggregator, added bool) { | ||||
| func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, labels ...core.KeyValue) (agg export.Aggregator, added bool) { | ||||
| 	encoded := p.encoder.Encode(labels) | ||||
| 	elabels := export.NewLabels(labels, encoded, p.encoder) | ||||
|  | ||||
| @@ -51,26 +52,26 @@ func (p *CheckpointSet) Add(desc *export.Descriptor, newAgg export.Aggregator, l | ||||
| 	return newAgg, true | ||||
| } | ||||
|  | ||||
| func createNumber(desc *export.Descriptor, v float64) core.Number { | ||||
| func createNumber(desc *metric.Descriptor, v float64) core.Number { | ||||
| 	if desc.NumberKind() == core.Float64NumberKind { | ||||
| 		return core.NewFloat64Number(v) | ||||
| 	} | ||||
| 	return core.NewInt64Number(int64(v)) | ||||
| } | ||||
|  | ||||
| func (p *CheckpointSet) AddLastValue(desc *export.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| func (p *CheckpointSet) AddLastValue(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| 	p.updateAggregator(desc, lastvalue.New(), v, labels...) | ||||
| } | ||||
|  | ||||
| func (p *CheckpointSet) AddCounter(desc *export.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| 	p.updateAggregator(desc, sum.New(), v, labels...) | ||||
| } | ||||
|  | ||||
| func (p *CheckpointSet) AddMeasure(desc *export.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { | ||||
| 	p.updateAggregator(desc, array.New(), v, labels...) | ||||
| } | ||||
|  | ||||
| func (p *CheckpointSet) updateAggregator(desc *export.Descriptor, newAgg export.Aggregator, v float64, labels ...core.KeyValue) { | ||||
| func (p *CheckpointSet) updateAggregator(desc *metric.Descriptor, newAgg export.Aggregator, v float64, labels ...core.KeyValue) { | ||||
| 	ctx := context.Background() | ||||
| 	// Updates and checkpoint the new aggregator | ||||
| 	_ = newAgg.Update(ctx, createNumber(desc, v), desc) | ||||
|   | ||||
| @@ -23,7 +23,8 @@ import ( | ||||
| 	metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	metricsdk "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
|  | ||||
| @@ -33,7 +34,7 @@ var ErrUnimplementedAgg = errors.New("unimplemented aggregator") | ||||
|  | ||||
| // Record transforms a Record into an OTLP Metric. An ErrUnimplementedAgg | ||||
| // error is returned if the Record Aggregator is not supported. | ||||
| func Record(r metricsdk.Record) (*metricpb.Metric, error) { | ||||
| func Record(r export.Record) (*metricpb.Metric, error) { | ||||
| 	d := r.Descriptor() | ||||
| 	l := r.Labels() | ||||
| 	switch a := r.Aggregator().(type) { | ||||
| @@ -46,7 +47,7 @@ func Record(r metricsdk.Record) (*metricpb.Metric, error) { | ||||
| } | ||||
|  | ||||
| // sum transforms a Sum Aggregator into an OTLP Metric. | ||||
| func sum(desc *metricsdk.Descriptor, labels metricsdk.Labels, a aggregator.Sum) (*metricpb.Metric, error) { | ||||
| func sum(desc *metric.Descriptor, labels export.Labels, a aggregator.Sum) (*metricpb.Metric, error) { | ||||
| 	sum, err := a.Sum() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -96,7 +97,7 @@ func minMaxSumCountValues(a aggregator.MinMaxSumCount) (min, max, sum core.Numbe | ||||
| } | ||||
|  | ||||
| // minMaxSumCount transforms a MinMaxSumCount Aggregator into an OTLP Metric. | ||||
| func minMaxSumCount(desc *metricsdk.Descriptor, labels metricsdk.Labels, a aggregator.MinMaxSumCount) (*metricpb.Metric, error) { | ||||
| func minMaxSumCount(desc *metric.Descriptor, labels export.Labels, a aggregator.MinMaxSumCount) (*metricpb.Metric, error) { | ||||
| 	min, max, sum, count, err := minMaxSumCountValues(a) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|   | ||||
| @@ -23,8 +23,9 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/api/unit" | ||||
| 	metricsdk "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" | ||||
| 	sumAgg "go.opentelemetry.io/otel/sdk/metric/aggregator/sum" | ||||
| @@ -73,16 +74,16 @@ func TestStringKeyValues(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestMinMaxSumCountValue(t *testing.T) { | ||||
| 	mmsc := minmaxsumcount.New(&metricsdk.Descriptor{}) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 1, &metricsdk.Descriptor{})) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 10, &metricsdk.Descriptor{})) | ||||
| 	mmsc := minmaxsumcount.New(&metric.Descriptor{}) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 1, &metric.Descriptor{})) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 10, &metric.Descriptor{})) | ||||
|  | ||||
| 	// Prior to checkpointing ErrNoData should be returned. | ||||
| 	_, _, _, _, err := minMaxSumCountValues(mmsc) | ||||
| 	assert.EqualError(t, err, aggregator.ErrNoData.Error()) | ||||
|  | ||||
| 	// Checkpoint to set non-zero values | ||||
| 	mmsc.Checkpoint(context.Background(), &metricsdk.Descriptor{}) | ||||
| 	mmsc.Checkpoint(context.Background(), &metric.Descriptor{}) | ||||
| 	min, max, sum, count, err := minMaxSumCountValues(mmsc) | ||||
| 	if assert.NoError(t, err) { | ||||
| 		assert.Equal(t, min, core.NewInt64Number(1)) | ||||
| @@ -95,7 +96,7 @@ func TestMinMaxSumCountValue(t *testing.T) { | ||||
| func TestMinMaxSumCountMetricDescriptor(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name        string | ||||
| 		metricKind  metricsdk.Kind | ||||
| 		metricKind  metric.Kind | ||||
| 		keys        []core.Key | ||||
| 		description string | ||||
| 		unit        unit.Unit | ||||
| @@ -105,7 +106,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"mmsc-test-a", | ||||
| 			metricsdk.MeasureKind, | ||||
| 			metric.MeasureKind, | ||||
| 			[]core.Key{}, | ||||
| 			"test-a-description", | ||||
| 			unit.Dimensionless, | ||||
| @@ -121,8 +122,8 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { | ||||
| 		}, | ||||
| 		{ | ||||
| 			"mmsc-test-b", | ||||
| 			metricsdk.CounterKind, // This shouldn't change anything. | ||||
| 			[]core.Key{"test"},    // This shouldn't change anything. | ||||
| 			metric.CounterKind, // This shouldn't change anything. | ||||
| 			[]core.Key{"test"}, // This shouldn't change anything. | ||||
| 			"test-b-description", | ||||
| 			unit.Bytes, | ||||
| 			core.Float64NumberKind, // This shouldn't change anything. | ||||
| @@ -138,15 +139,18 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	ctx := context.Background() | ||||
| 	mmsc := minmaxsumcount.New(&metricsdk.Descriptor{}) | ||||
| 	if !assert.NoError(t, mmsc.Update(ctx, 1, &metricsdk.Descriptor{})) { | ||||
| 	mmsc := minmaxsumcount.New(&metric.Descriptor{}) | ||||
| 	if !assert.NoError(t, mmsc.Update(ctx, 1, &metric.Descriptor{})) { | ||||
| 		return | ||||
| 	} | ||||
| 	mmsc.Checkpoint(ctx, &metricsdk.Descriptor{}) | ||||
| 	mmsc.Checkpoint(ctx, &metric.Descriptor{}) | ||||
| 	for _, test := range tests { | ||||
| 		desc := metricsdk.NewDescriptor(test.name, test.metricKind, test.keys, test.description, test.unit, test.numberKind) | ||||
| 		labels := metricsdk.NewLabels(test.labels, "", nil) | ||||
| 		got, err := minMaxSumCount(desc, labels, mmsc) | ||||
| 		desc := metric.NewDescriptor(test.name, test.metricKind, test.numberKind, | ||||
| 			metric.WithKeys(test.keys...), | ||||
| 			metric.WithDescription(test.description), | ||||
| 			metric.WithUnit(test.unit)) | ||||
| 		labels := export.NewLabels(test.labels, "", nil) | ||||
| 		got, err := minMaxSumCount(&desc, labels, mmsc) | ||||
| 		if assert.NoError(t, err) { | ||||
| 			assert.Equal(t, test.expected, got.MetricDescriptor) | ||||
| 		} | ||||
| @@ -154,12 +158,12 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestMinMaxSumCountDatapoints(t *testing.T) { | ||||
| 	desc := metricsdk.NewDescriptor("", metricsdk.MeasureKind, []core.Key{}, "", unit.Dimensionless, core.Int64NumberKind) | ||||
| 	labels := metricsdk.NewLabels([]core.KeyValue{}, "", nil) | ||||
| 	mmsc := minmaxsumcount.New(desc) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 1, desc)) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 10, desc)) | ||||
| 	mmsc.Checkpoint(context.Background(), desc) | ||||
| 	desc := metric.NewDescriptor("", metric.MeasureKind, core.Int64NumberKind) | ||||
| 	labels := export.NewLabels([]core.KeyValue{}, "", nil) | ||||
| 	mmsc := minmaxsumcount.New(&desc) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 1, &desc)) | ||||
| 	assert.NoError(t, mmsc.Update(context.Background(), 10, &desc)) | ||||
| 	mmsc.Checkpoint(context.Background(), &desc) | ||||
| 	expected := []*metricpb.SummaryDataPoint{ | ||||
| 		{ | ||||
| 			Count: 2, | ||||
| @@ -176,7 +180,7 @@ func TestMinMaxSumCountDatapoints(t *testing.T) { | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	m, err := minMaxSumCount(desc, labels, mmsc) | ||||
| 	m, err := minMaxSumCount(&desc, labels, mmsc) | ||||
| 	if assert.NoError(t, err) { | ||||
| 		assert.Equal(t, []*metricpb.Int64DataPoint(nil), m.Int64DataPoints) | ||||
| 		assert.Equal(t, []*metricpb.DoubleDataPoint(nil), m.DoubleDataPoints) | ||||
| @@ -189,7 +193,7 @@ func TestMinMaxSumCountPropagatesErrors(t *testing.T) { | ||||
| 	// ErrNoData should be returned by both the Min and Max values of | ||||
| 	// a MinMaxSumCount Aggregator. Use this fact to check the error is | ||||
| 	// correctly returned. | ||||
| 	mmsc := minmaxsumcount.New(&metricsdk.Descriptor{}) | ||||
| 	mmsc := minmaxsumcount.New(&metric.Descriptor{}) | ||||
| 	_, _, _, _, err := minMaxSumCountValues(mmsc) | ||||
| 	assert.Error(t, err) | ||||
| 	assert.Equal(t, aggregator.ErrNoData, err) | ||||
| @@ -198,7 +202,7 @@ func TestMinMaxSumCountPropagatesErrors(t *testing.T) { | ||||
| func TestSumMetricDescriptor(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name        string | ||||
| 		metricKind  metricsdk.Kind | ||||
| 		metricKind  metric.Kind | ||||
| 		keys        []core.Key | ||||
| 		description string | ||||
| 		unit        unit.Unit | ||||
| @@ -208,7 +212,7 @@ func TestSumMetricDescriptor(t *testing.T) { | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"sum-test-a", | ||||
| 			metricsdk.CounterKind, | ||||
| 			metric.CounterKind, | ||||
| 			[]core.Key{}, | ||||
| 			"test-a-description", | ||||
| 			unit.Dimensionless, | ||||
| @@ -224,8 +228,8 @@ func TestSumMetricDescriptor(t *testing.T) { | ||||
| 		}, | ||||
| 		{ | ||||
| 			"sum-test-b", | ||||
| 			metricsdk.MeasureKind, // This shouldn't change anything. | ||||
| 			[]core.Key{"test"},    // This shouldn't change anything. | ||||
| 			metric.MeasureKind, // This shouldn't change anything. | ||||
| 			[]core.Key{"test"}, // This shouldn't change anything. | ||||
| 			"test-b-description", | ||||
| 			unit.Milliseconds, | ||||
| 			core.Float64NumberKind, | ||||
| @@ -241,22 +245,26 @@ func TestSumMetricDescriptor(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range tests { | ||||
| 		desc := metricsdk.NewDescriptor(test.name, test.metricKind, test.keys, test.description, test.unit, test.numberKind) | ||||
| 		labels := metricsdk.NewLabels(test.labels, "", nil) | ||||
| 		got, err := sum(desc, labels, sumAgg.New()) | ||||
| 		desc := metric.NewDescriptor(test.name, test.metricKind, test.numberKind, | ||||
| 			metric.WithKeys(test.keys...), | ||||
| 			metric.WithDescription(test.description), | ||||
| 			metric.WithUnit(test.unit), | ||||
| 		) | ||||
| 		labels := export.NewLabels(test.labels, "", nil) | ||||
| 		got, err := sum(&desc, labels, sumAgg.New()) | ||||
| 		if assert.NoError(t, err) { | ||||
| 			assert.Equal(t, test.expected, got.MetricDescriptor) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSumInt64Datapoints(t *testing.T) { | ||||
| 	desc := metricsdk.NewDescriptor("", metricsdk.MeasureKind, []core.Key{}, "", unit.Dimensionless, core.Int64NumberKind) | ||||
| 	labels := metricsdk.NewLabels([]core.KeyValue{}, "", nil) | ||||
| func TestSumInt64DataPoints(t *testing.T) { | ||||
| 	desc := metric.NewDescriptor("", metric.MeasureKind, core.Int64NumberKind) | ||||
| 	labels := export.NewLabels([]core.KeyValue{}, "", nil) | ||||
| 	s := sumAgg.New() | ||||
| 	assert.NoError(t, s.Update(context.Background(), core.Number(1), desc)) | ||||
| 	s.Checkpoint(context.Background(), desc) | ||||
| 	if m, err := sum(desc, labels, s); assert.NoError(t, err) { | ||||
| 	assert.NoError(t, s.Update(context.Background(), core.Number(1), &desc)) | ||||
| 	s.Checkpoint(context.Background(), &desc) | ||||
| 	if m, err := sum(&desc, labels, s); assert.NoError(t, err) { | ||||
| 		assert.Equal(t, []*metricpb.Int64DataPoint{{Value: 1}}, m.Int64DataPoints) | ||||
| 		assert.Equal(t, []*metricpb.DoubleDataPoint(nil), m.DoubleDataPoints) | ||||
| 		assert.Equal(t, []*metricpb.HistogramDataPoint(nil), m.HistogramDataPoints) | ||||
| @@ -264,13 +272,13 @@ func TestSumInt64Datapoints(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSumFloat64Datapoints(t *testing.T) { | ||||
| 	desc := metricsdk.NewDescriptor("", metricsdk.MeasureKind, []core.Key{}, "", unit.Dimensionless, core.Float64NumberKind) | ||||
| 	labels := metricsdk.NewLabels([]core.KeyValue{}, "", nil) | ||||
| func TestSumFloat64DataPoints(t *testing.T) { | ||||
| 	desc := metric.NewDescriptor("", metric.MeasureKind, core.Float64NumberKind) | ||||
| 	labels := export.NewLabels([]core.KeyValue{}, "", nil) | ||||
| 	s := sumAgg.New() | ||||
| 	assert.NoError(t, s.Update(context.Background(), core.NewFloat64Number(1), desc)) | ||||
| 	s.Checkpoint(context.Background(), desc) | ||||
| 	if m, err := sum(desc, labels, s); assert.NoError(t, err) { | ||||
| 	assert.NoError(t, s.Update(context.Background(), core.NewFloat64Number(1), &desc)) | ||||
| 	s.Checkpoint(context.Background(), &desc) | ||||
| 	if m, err := sum(&desc, labels, s); assert.NoError(t, err) { | ||||
| 		assert.Equal(t, []*metricpb.Int64DataPoint(nil), m.Int64DataPoints) | ||||
| 		assert.Equal(t, []*metricpb.DoubleDataPoint{{Value: 1}}, m.DoubleDataPoints) | ||||
| 		assert.Equal(t, []*metricpb.HistogramDataPoint(nil), m.HistogramDataPoints) | ||||
|   | ||||
| @@ -27,9 +27,9 @@ import ( | ||||
| 	metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	metricapi "go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/exporters/otlp" | ||||
| 	metricsdk "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/trace" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/controller/push" | ||||
| @@ -119,21 +119,21 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) | ||||
| 	labels := meter.Labels(core.Key("test").Bool(true)) | ||||
|  | ||||
| 	type data struct { | ||||
| 		iKind metricsdk.Kind | ||||
| 		iKind metric.Kind | ||||
| 		nKind core.NumberKind | ||||
| 		val   int64 | ||||
| 	} | ||||
| 	instruments := map[string]data{ | ||||
| 		"test-int64-counter":    {metricsdk.CounterKind, core.Int64NumberKind, 1}, | ||||
| 		"test-float64-counter":  {metricsdk.CounterKind, core.Float64NumberKind, 1}, | ||||
| 		"test-int64-measure":    {metricsdk.MeasureKind, core.Int64NumberKind, 2}, | ||||
| 		"test-float64-measure":  {metricsdk.MeasureKind, core.Float64NumberKind, 2}, | ||||
| 		"test-int64-observer":   {metricsdk.ObserverKind, core.Int64NumberKind, 3}, | ||||
| 		"test-float64-observer": {metricsdk.ObserverKind, core.Float64NumberKind, 3}, | ||||
| 		"test-int64-counter":    {metric.CounterKind, core.Int64NumberKind, 1}, | ||||
| 		"test-float64-counter":  {metric.CounterKind, core.Float64NumberKind, 1}, | ||||
| 		"test-int64-measure":    {metric.MeasureKind, core.Int64NumberKind, 2}, | ||||
| 		"test-float64-measure":  {metric.MeasureKind, core.Float64NumberKind, 2}, | ||||
| 		"test-int64-observer":   {metric.ObserverKind, core.Int64NumberKind, 3}, | ||||
| 		"test-float64-observer": {metric.ObserverKind, core.Float64NumberKind, 3}, | ||||
| 	} | ||||
| 	for name, data := range instruments { | ||||
| 		switch data.iKind { | ||||
| 		case metricsdk.CounterKind: | ||||
| 		case metric.CounterKind: | ||||
| 			switch data.nKind { | ||||
| 			case core.Int64NumberKind: | ||||
| 				metricapi.Must(meter).NewInt64Counter(name).Add(ctx, data.val, labels) | ||||
| @@ -142,7 +142,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) | ||||
| 			default: | ||||
| 				assert.Failf(t, "unsupported number testing kind", data.nKind.String()) | ||||
| 			} | ||||
| 		case metricsdk.MeasureKind: | ||||
| 		case metric.MeasureKind: | ||||
| 			switch data.nKind { | ||||
| 			case core.Int64NumberKind: | ||||
| 				metricapi.Must(meter).NewInt64Measure(name).Record(ctx, data.val, labels) | ||||
| @@ -151,7 +151,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) | ||||
| 			default: | ||||
| 				assert.Failf(t, "unsupported number testing kind", data.nKind.String()) | ||||
| 			} | ||||
| 		case metricsdk.ObserverKind: | ||||
| 		case metric.ObserverKind: | ||||
| 			switch data.nKind { | ||||
| 			case core.Int64NumberKind: | ||||
| 				callback := func(v int64) metricapi.Int64ObserverCallback { | ||||
| @@ -228,7 +228,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) | ||||
| 		seen[desc.Name] = struct{}{} | ||||
|  | ||||
| 		switch data.iKind { | ||||
| 		case metricsdk.CounterKind: | ||||
| 		case metric.CounterKind: | ||||
| 			switch data.nKind { | ||||
| 			case core.Int64NumberKind: | ||||
| 				assert.Equal(t, metricpb.MetricDescriptor_COUNTER_INT64.String(), desc.GetType().String()) | ||||
| @@ -243,7 +243,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) | ||||
| 			default: | ||||
| 				assert.Failf(t, "invalid number kind", data.nKind.String()) | ||||
| 			} | ||||
| 		case metricsdk.MeasureKind, metricsdk.ObserverKind: | ||||
| 		case metric.MeasureKind, metric.ObserverKind: | ||||
| 			assert.Equal(t, metricpb.MetricDescriptor_SUMMARY.String(), desc.GetType().String()) | ||||
| 			m.GetSummaryDataPoints() | ||||
| 			if dp := m.GetSummaryDataPoints(); assert.Len(t, dp, 1) { | ||||
|   | ||||
| @@ -19,22 +19,16 @@ import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	apimetric "go.opentelemetry.io/otel/api/metric" | ||||
| ) | ||||
|  | ||||
| type ( | ||||
| 	Handle struct { | ||||
| 		Instrument *Instrument | ||||
| 		Instrument *Sync | ||||
| 		LabelSet   *LabelSet | ||||
| 	} | ||||
|  | ||||
| 	Instrument struct { | ||||
| 		Name       string | ||||
| 		Kind       Kind | ||||
| 		NumberKind core.NumberKind | ||||
| 		Config     apimetric.Config | ||||
| 	} | ||||
|  | ||||
| 	LabelSet struct { | ||||
| 		TheMeter *Meter | ||||
| 		Labels   map[core.Key]core.Value | ||||
| @@ -54,101 +48,77 @@ type ( | ||||
|  | ||||
| 	Meter struct { | ||||
| 		MeasurementBatches []Batch | ||||
| 		// Observers contains also unregistered | ||||
| 		// observers. Check the Dead field of the Observer to | ||||
| 		// figure out its status. | ||||
| 		Observers []*Observer | ||||
| 		AsyncInstruments   []*Async | ||||
| 	} | ||||
|  | ||||
| 	Kind int8 | ||||
|  | ||||
| 	Measurement struct { | ||||
| 		// Number needs to be aligned for 64-bit atomic operations. | ||||
| 		Number     core.Number | ||||
| 		Instrument *Instrument | ||||
| 		Instrument apimetric.InstrumentImpl | ||||
| 	} | ||||
|  | ||||
| 	observerResult struct { | ||||
| 		instrument *Instrument | ||||
| 	Instrument struct { | ||||
| 		meter      *Meter | ||||
| 		descriptor apimetric.Descriptor | ||||
| 	} | ||||
|  | ||||
| 	int64ObserverResult struct { | ||||
| 		result observerResult | ||||
| 	Async struct { | ||||
| 		Instrument | ||||
|  | ||||
| 		callback func(func(core.Number, apimetric.LabelSet)) | ||||
| 	} | ||||
|  | ||||
| 	float64ObserverResult struct { | ||||
| 		result observerResult | ||||
| 	} | ||||
|  | ||||
| 	observerCallback func(observerResult) | ||||
|  | ||||
| 	Observer struct { | ||||
| 		Instrument *Instrument | ||||
| 		Meter      *Meter | ||||
| 		Dead       bool | ||||
| 		callback   observerCallback | ||||
| 	Sync struct { | ||||
| 		Instrument | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	_ apimetric.InstrumentImpl        = &Instrument{} | ||||
| 	_ apimetric.BoundInstrumentImpl   = &Handle{} | ||||
| 	_ apimetric.LabelSet              = &LabelSet{} | ||||
| 	_ apimetric.Meter                 = &Meter{} | ||||
| 	_ apimetric.Int64Observer         = &Observer{} | ||||
| 	_ apimetric.Float64Observer       = &Observer{} | ||||
| 	_ apimetric.Int64ObserverResult   = int64ObserverResult{} | ||||
| 	_ apimetric.Float64ObserverResult = float64ObserverResult{} | ||||
| 	_ apimetric.SyncImpl      = &Sync{} | ||||
| 	_ apimetric.BoundSyncImpl = &Handle{} | ||||
| 	_ apimetric.LabelSet      = &LabelSet{} | ||||
| 	_ apimetric.MeterImpl     = &Meter{} | ||||
| 	_ apimetric.AsyncImpl     = &Async{} | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	KindCounter Kind = iota | ||||
| 	KindMeasure | ||||
| 	KindObserver | ||||
| ) | ||||
|  | ||||
| func (o *Observer) Unregister() { | ||||
| 	o.Dead = true | ||||
| func (i Instrument) Descriptor() apimetric.Descriptor { | ||||
| 	return i.descriptor | ||||
| } | ||||
|  | ||||
| func (r int64ObserverResult) Observe(value int64, labels apimetric.LabelSet) { | ||||
| 	r.result.observe(core.NewInt64Number(value), labels) | ||||
| func (a *Async) Implementation() interface{} { | ||||
| 	return a | ||||
| } | ||||
|  | ||||
| func (r float64ObserverResult) Observe(value float64, labels apimetric.LabelSet) { | ||||
| 	r.result.observe(core.NewFloat64Number(value), labels) | ||||
| func (s *Sync) Implementation() interface{} { | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| func (r observerResult) observe(number core.Number, labels apimetric.LabelSet) { | ||||
| 	r.instrument.RecordOne(context.Background(), number, labels) | ||||
| } | ||||
|  | ||||
| func (i *Instrument) Bind(labels apimetric.LabelSet) apimetric.BoundInstrumentImpl { | ||||
| func (s *Sync) Bind(labels apimetric.LabelSet) apimetric.BoundSyncImpl { | ||||
| 	if ld, ok := labels.(apimetric.LabelSetDelegate); ok { | ||||
| 		labels = ld.Delegate() | ||||
| 	} | ||||
| 	return &Handle{ | ||||
| 		Instrument: i, | ||||
| 		Instrument: s, | ||||
| 		LabelSet:   labels.(*LabelSet), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (i *Instrument) RecordOne(ctx context.Context, number core.Number, labels apimetric.LabelSet) { | ||||
| func (s *Sync) RecordOne(ctx context.Context, number core.Number, labels apimetric.LabelSet) { | ||||
| 	if ld, ok := labels.(apimetric.LabelSetDelegate); ok { | ||||
| 		labels = ld.Delegate() | ||||
| 	} | ||||
| 	doRecordBatch(ctx, labels.(*LabelSet), i, number) | ||||
| 	s.meter.doRecordSingle(ctx, labels.(*LabelSet), s, number) | ||||
| } | ||||
|  | ||||
| func (h *Handle) RecordOne(ctx context.Context, number core.Number) { | ||||
| 	doRecordBatch(ctx, h.LabelSet, h.Instrument, number) | ||||
| 	h.Instrument.meter.doRecordSingle(ctx, h.LabelSet, h.Instrument, number) | ||||
| } | ||||
|  | ||||
| func (h *Handle) Unbind() { | ||||
| } | ||||
|  | ||||
| func doRecordBatch(ctx context.Context, labelSet *LabelSet, instrument *Instrument, number core.Number) { | ||||
| 	labelSet.TheMeter.recordMockBatch(ctx, labelSet, Measurement{ | ||||
| func (m *Meter) doRecordSingle(ctx context.Context, labelSet *LabelSet, instrument apimetric.InstrumentImpl, number core.Number) { | ||||
| 	m.recordMockBatch(ctx, labelSet, Measurement{ | ||||
| 		Instrument: instrument, | ||||
| 		Number:     number, | ||||
| 	}) | ||||
| @@ -167,13 +137,14 @@ func (p *MeterProvider) Meter(name string) apimetric.Meter { | ||||
| 	if lookup, ok := p.registered[name]; ok { | ||||
| 		return lookup | ||||
| 	} | ||||
| 	m := NewMeter() | ||||
| 	_, m := NewMeter() | ||||
| 	p.registered[name] = m | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| func NewMeter() *Meter { | ||||
| 	return &Meter{} | ||||
| func NewMeter() (*Meter, apimetric.Meter) { | ||||
| 	mock := &Meter{} | ||||
| 	return mock, apimetric.WrapMeterImpl(mock) | ||||
| } | ||||
|  | ||||
| func (m *Meter) Labels(labels ...core.KeyValue) apimetric.LabelSet { | ||||
| @@ -187,92 +158,25 @@ func (m *Meter) Labels(labels ...core.KeyValue) apimetric.LabelSet { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Meter) NewInt64Counter(name string, opts ...apimetric.Option) (apimetric.Int64Counter, error) { | ||||
| 	instrument := m.newCounterInstrument(name, core.Int64NumberKind, opts) | ||||
| 	return apimetric.WrapInt64CounterInstrument(instrument, nil) | ||||
| } | ||||
|  | ||||
| func (m *Meter) NewFloat64Counter(name string, opts ...apimetric.Option) (apimetric.Float64Counter, error) { | ||||
| 	instrument := m.newCounterInstrument(name, core.Float64NumberKind, opts) | ||||
| 	return apimetric.WrapFloat64CounterInstrument(instrument, nil) | ||||
| } | ||||
|  | ||||
| func (m *Meter) newCounterInstrument(name string, numberKind core.NumberKind, opts []apimetric.Option) *Instrument { | ||||
| 	return &Instrument{ | ||||
| 		Name:       name, | ||||
| 		Kind:       KindCounter, | ||||
| 		NumberKind: numberKind, | ||||
| 		Config:     apimetric.Configure(opts), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Meter) NewInt64Measure(name string, opts ...apimetric.Option) (apimetric.Int64Measure, error) { | ||||
| 	instrument := m.newMeasureInstrument(name, core.Int64NumberKind, opts) | ||||
| 	return apimetric.WrapInt64MeasureInstrument(instrument, nil) | ||||
| } | ||||
|  | ||||
| func (m *Meter) NewFloat64Measure(name string, opts ...apimetric.Option) (apimetric.Float64Measure, error) { | ||||
| 	instrument := m.newMeasureInstrument(name, core.Float64NumberKind, opts) | ||||
| 	return apimetric.WrapFloat64MeasureInstrument(instrument, nil) | ||||
| } | ||||
|  | ||||
| func (m *Meter) newMeasureInstrument(name string, numberKind core.NumberKind, opts []apimetric.Option) *Instrument { | ||||
| 	return &Instrument{ | ||||
| 		Name:       name, | ||||
| 		Kind:       KindMeasure, | ||||
| 		NumberKind: numberKind, | ||||
| 		Config:     apimetric.Configure(opts), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Meter) RegisterInt64Observer(name string, callback apimetric.Int64ObserverCallback, opts ...apimetric.Option) (apimetric.Int64Observer, error) { | ||||
| 	wrappedCallback := wrapInt64ObserverCallback(callback) | ||||
| 	return m.newObserver(name, wrappedCallback, core.Int64NumberKind, opts), nil | ||||
| } | ||||
|  | ||||
| func wrapInt64ObserverCallback(callback apimetric.Int64ObserverCallback) observerCallback { | ||||
| 	if callback == nil { | ||||
| 		return func(result observerResult) {} | ||||
| 	} | ||||
| 	return func(result observerResult) { | ||||
| 		typeSafeResult := int64ObserverResult{ | ||||
| 			result: result, | ||||
| 		} | ||||
| 		callback(typeSafeResult) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Meter) RegisterFloat64Observer(name string, callback apimetric.Float64ObserverCallback, opts ...apimetric.Option) (apimetric.Float64Observer, error) { | ||||
| 	wrappedCallback := wrapFloat64ObserverCallback(callback) | ||||
| 	return m.newObserver(name, wrappedCallback, core.Float64NumberKind, opts), nil | ||||
| } | ||||
|  | ||||
| func wrapFloat64ObserverCallback(callback apimetric.Float64ObserverCallback) observerCallback { | ||||
| 	if callback == nil { | ||||
| 		return func(result observerResult) {} | ||||
| 	} | ||||
| 	return func(result observerResult) { | ||||
| 		typeSafeResult := float64ObserverResult{ | ||||
| 			result: result, | ||||
| 		} | ||||
| 		callback(typeSafeResult) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Meter) newObserver(name string, callback observerCallback, numberKind core.NumberKind, opts []apimetric.Option) *Observer { | ||||
| 	obs := &Observer{ | ||||
| 		Instrument: &Instrument{ | ||||
| 			Name:       name, | ||||
| 			Kind:       KindObserver, | ||||
| 			NumberKind: numberKind, | ||||
| 			Config:     apimetric.Configure(opts), | ||||
| func (m *Meter) NewSyncInstrument(descriptor metric.Descriptor) (apimetric.SyncImpl, error) { | ||||
| 	return &Sync{ | ||||
| 		Instrument{ | ||||
| 			descriptor: descriptor, | ||||
| 			meter:      m, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (m *Meter) NewAsyncInstrument(descriptor metric.Descriptor, callback func(func(core.Number, apimetric.LabelSet))) (apimetric.AsyncImpl, error) { | ||||
| 	a := &Async{ | ||||
| 		Instrument: Instrument{ | ||||
| 			descriptor: descriptor, | ||||
| 			meter:      m, | ||||
| 		}, | ||||
| 		Meter:    m, | ||||
| 		Dead:     false, | ||||
| 		callback: callback, | ||||
| 	} | ||||
| 	m.Observers = append(m.Observers, obs) | ||||
| 	return obs | ||||
| 	m.AsyncInstruments = append(m.AsyncInstruments, a) | ||||
| 	return a, nil | ||||
| } | ||||
|  | ||||
| func (m *Meter) RecordBatch(ctx context.Context, labels apimetric.LabelSet, measurements ...apimetric.Measurement) { | ||||
| @@ -281,7 +185,7 @@ func (m *Meter) RecordBatch(ctx context.Context, labels apimetric.LabelSet, meas | ||||
| 	for i := 0; i < len(measurements); i++ { | ||||
| 		m := measurements[i] | ||||
| 		mm[i] = Measurement{ | ||||
| 			Instrument: m.InstrumentImpl().(*Instrument), | ||||
| 			Instrument: m.SyncImpl().(*Sync), | ||||
| 			Number:     m.Number(), | ||||
| 		} | ||||
| 	} | ||||
| @@ -296,13 +200,15 @@ func (m *Meter) recordMockBatch(ctx context.Context, labelSet *LabelSet, measure | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (m *Meter) RunObservers() { | ||||
| 	for _, observer := range m.Observers { | ||||
| 		if observer.Dead { | ||||
| 			continue | ||||
| 		} | ||||
| 		observer.callback(observerResult{ | ||||
| 			instrument: observer.Instrument, | ||||
| func (m *Meter) RunAsyncInstruments() { | ||||
| 	for _, observer := range m.AsyncInstruments { | ||||
| 		observer.callback(func(n core.Number, labels apimetric.LabelSet) { | ||||
|  | ||||
| 			if ld, ok := labels.(apimetric.LabelSetDelegate); ok { | ||||
| 				labels = ld.Delegate() | ||||
| 			} | ||||
|  | ||||
| 			m.doRecordSingle(context.Background(), labels.(*LabelSet), observer, n) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| ) | ||||
|  | ||||
| @@ -116,7 +117,7 @@ func NewInconsistentMergeError(a1, a2 export.Aggregator) error { | ||||
| // This rejects NaN values.  This rejects negative values when the | ||||
| // metric instrument does not support negative values, including | ||||
| // monotonic counter metrics and absolute measure metrics. | ||||
| func RangeTest(number core.Number, descriptor *export.Descriptor) error { | ||||
| func RangeTest(number core.Number, descriptor *metric.Descriptor) error { | ||||
| 	numberKind := descriptor.NumberKind() | ||||
|  | ||||
| 	if numberKind == core.Float64NumberKind && math.IsNaN(number.AsFloat64()) { | ||||
| @@ -124,7 +125,7 @@ func RangeTest(number core.Number, descriptor *export.Descriptor) error { | ||||
| 	} | ||||
|  | ||||
| 	switch descriptor.MetricKind() { | ||||
| 	case export.CounterKind: | ||||
| 	case metric.CounterKind: | ||||
| 		if number.IsNegative(numberKind) { | ||||
| 			return ErrNegativeInput | ||||
| 		} | ||||
|   | ||||
| @@ -22,7 +22,7 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/sum" | ||||
| @@ -38,7 +38,7 @@ func TestInconsistentMergeErr(t *testing.T) { | ||||
| 	require.True(t, errors.Is(err, aggregator.ErrInconsistentType)) | ||||
| } | ||||
|  | ||||
| func testRangeNaN(t *testing.T, desc *export.Descriptor) { | ||||
| func testRangeNaN(t *testing.T, desc *metric.Descriptor) { | ||||
| 	// If the descriptor uses int64 numbers, this won't register as NaN | ||||
| 	nan := core.NewFloat64Number(math.NaN()) | ||||
| 	err := aggregator.RangeTest(nan, desc) | ||||
| @@ -50,7 +50,7 @@ func testRangeNaN(t *testing.T, desc *export.Descriptor) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testRangeNegative(t *testing.T, desc *export.Descriptor) { | ||||
| func testRangeNegative(t *testing.T, desc *metric.Descriptor) { | ||||
| 	var neg, pos core.Number | ||||
|  | ||||
| 	if desc.NumberKind() == core.Float64NumberKind { | ||||
| @@ -72,15 +72,12 @@ func TestRangeTest(t *testing.T) { | ||||
| 	// Only Counters implement a range test. | ||||
| 	for _, nkind := range []core.NumberKind{core.Float64NumberKind, core.Int64NumberKind} { | ||||
| 		t.Run(nkind.String(), func(t *testing.T) { | ||||
| 			desc := export.NewDescriptor( | ||||
| 			desc := metric.NewDescriptor( | ||||
| 				"name", | ||||
| 				export.CounterKind, | ||||
| 				nil, | ||||
| 				"", | ||||
| 				"", | ||||
| 				metric.CounterKind, | ||||
| 				nkind, | ||||
| 			) | ||||
| 			testRangeNegative(t, desc) | ||||
| 			testRangeNegative(t, &desc) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| @@ -88,20 +85,17 @@ func TestRangeTest(t *testing.T) { | ||||
| func TestNaNTest(t *testing.T) { | ||||
| 	for _, nkind := range []core.NumberKind{core.Float64NumberKind, core.Int64NumberKind} { | ||||
| 		t.Run(nkind.String(), func(t *testing.T) { | ||||
| 			for _, mkind := range []export.Kind{ | ||||
| 				export.CounterKind, | ||||
| 				export.MeasureKind, | ||||
| 				export.ObserverKind, | ||||
| 			for _, mkind := range []metric.Kind{ | ||||
| 				metric.CounterKind, | ||||
| 				metric.MeasureKind, | ||||
| 				metric.ObserverKind, | ||||
| 			} { | ||||
| 				desc := export.NewDescriptor( | ||||
| 				desc := metric.NewDescriptor( | ||||
| 					"name", | ||||
| 					mkind, | ||||
| 					nil, | ||||
| 					"", | ||||
| 					"", | ||||
| 					nkind, | ||||
| 				) | ||||
| 				testRangeNaN(t, desc) | ||||
| 				testRangeNaN(t, &desc) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
|   | ||||
| @@ -14,13 +14,11 @@ | ||||
|  | ||||
| package metric | ||||
|  | ||||
| //go:generate stringer -type=Kind | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/unit" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| ) | ||||
|  | ||||
| // Batcher is responsible for deciding which kind of aggregation to | ||||
| @@ -102,7 +100,7 @@ type AggregationSelector interface { | ||||
| 	// Note: This is context-free because the aggregator should | ||||
| 	// not relate to the incoming context.  This call should not | ||||
| 	// block. | ||||
| 	AggregatorFor(*Descriptor) Aggregator | ||||
| 	AggregatorFor(*metric.Descriptor) Aggregator | ||||
| } | ||||
|  | ||||
| // Aggregator implements a specific aggregation behavior, e.g., a | ||||
| @@ -132,7 +130,7 @@ type Aggregator interface { | ||||
| 	// | ||||
| 	// The Context argument comes from user-level code and could be | ||||
| 	// inspected for distributed or span context. | ||||
| 	Update(context.Context, core.Number, *Descriptor) error | ||||
| 	Update(context.Context, core.Number, *metric.Descriptor) error | ||||
|  | ||||
| 	// Checkpoint is called during collection to finish one period | ||||
| 	// of aggregation by atomically saving the current value. | ||||
| @@ -147,13 +145,13 @@ type Aggregator interface { | ||||
| 	// | ||||
| 	// The Context argument originates from the controller that | ||||
| 	// orchestrates collection. | ||||
| 	Checkpoint(context.Context, *Descriptor) | ||||
| 	Checkpoint(context.Context, *metric.Descriptor) | ||||
|  | ||||
| 	// Merge combines the checkpointed state from the argument | ||||
| 	// aggregator into this aggregator's checkpointed state. | ||||
| 	// Merge() is called in a single-threaded context, no locking | ||||
| 	// is required. | ||||
| 	Merge(Aggregator, *Descriptor) error | ||||
| 	Merge(Aggregator, *metric.Descriptor) error | ||||
| } | ||||
|  | ||||
| // Exporter handles presentation of the checkpoint of aggregate | ||||
| @@ -213,7 +211,7 @@ type CheckpointSet interface { | ||||
| // Record contains the exported data for a single metric instrument | ||||
| // and label set. | ||||
| type Record struct { | ||||
| 	descriptor *Descriptor | ||||
| 	descriptor *metric.Descriptor | ||||
| 	labels     Labels | ||||
| 	aggregator Aggregator | ||||
| } | ||||
| @@ -263,7 +261,7 @@ func (l Labels) Len() int { | ||||
| // NewRecord allows Batcher implementations to construct export | ||||
| // records.  The Descriptor, Labels, and Aggregator represent | ||||
| // aggregate metric events received over a single collection period. | ||||
| func NewRecord(descriptor *Descriptor, labels Labels, aggregator Aggregator) Record { | ||||
| func NewRecord(descriptor *metric.Descriptor, labels Labels, aggregator Aggregator) Record { | ||||
| 	return Record{ | ||||
| 		descriptor: descriptor, | ||||
| 		labels:     labels, | ||||
| @@ -278,7 +276,7 @@ func (r Record) Aggregator() Aggregator { | ||||
| } | ||||
|  | ||||
| // Descriptor describes the metric instrument being exported. | ||||
| func (r Record) Descriptor() *Descriptor { | ||||
| func (r Record) Descriptor() *metric.Descriptor { | ||||
| 	return r.descriptor | ||||
| } | ||||
|  | ||||
| @@ -287,91 +285,3 @@ func (r Record) Descriptor() *Descriptor { | ||||
| func (r Record) Labels() Labels { | ||||
| 	return r.labels | ||||
| } | ||||
|  | ||||
| // Kind describes the kind of instrument. | ||||
| type Kind int8 | ||||
|  | ||||
| const ( | ||||
| 	// Counter kind indicates a counter instrument. | ||||
| 	CounterKind Kind = iota | ||||
|  | ||||
| 	// Measure kind indicates a measure instrument. | ||||
| 	MeasureKind | ||||
|  | ||||
| 	// Observer kind indicates an observer instrument | ||||
| 	ObserverKind | ||||
| ) | ||||
|  | ||||
| // Descriptor describes a metric instrument to the exporter. | ||||
| // | ||||
| // Descriptors are created once per instrument and a pointer to the | ||||
| // descriptor may be used to uniquely identify the instrument in an | ||||
| // exporter. | ||||
| type Descriptor struct { | ||||
| 	name        string | ||||
| 	metricKind  Kind | ||||
| 	keys        []core.Key | ||||
| 	description string | ||||
| 	unit        unit.Unit | ||||
| 	numberKind  core.NumberKind | ||||
| } | ||||
|  | ||||
| // NewDescriptor builds a new descriptor, for use by `Meter` | ||||
| // implementations in constructing new metric instruments. | ||||
| // | ||||
| // Descriptors are created once per instrument and a pointer to the | ||||
| // descriptor may be used to uniquely identify the instrument in an | ||||
| // exporter. | ||||
| func NewDescriptor( | ||||
| 	name string, | ||||
| 	metricKind Kind, | ||||
| 	keys []core.Key, | ||||
| 	description string, | ||||
| 	unit unit.Unit, | ||||
| 	numberKind core.NumberKind, | ||||
| ) *Descriptor { | ||||
| 	return &Descriptor{ | ||||
| 		name:        name, | ||||
| 		metricKind:  metricKind, | ||||
| 		keys:        keys, | ||||
| 		description: description, | ||||
| 		unit:        unit, | ||||
| 		numberKind:  numberKind, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Name returns the metric instrument's name. | ||||
| func (d *Descriptor) Name() string { | ||||
| 	return d.name | ||||
| } | ||||
|  | ||||
| // MetricKind returns the kind of instrument: counter, measure, or | ||||
| // observer. | ||||
| func (d *Descriptor) MetricKind() Kind { | ||||
| 	return d.metricKind | ||||
| } | ||||
|  | ||||
| // Keys returns the recommended keys included in the metric | ||||
| // definition.  These keys may be used by a Batcher as a default set | ||||
| // of grouping keys for the metric instrument. | ||||
| func (d *Descriptor) Keys() []core.Key { | ||||
| 	return d.keys | ||||
| } | ||||
|  | ||||
| // Description provides a human-readable description of the metric | ||||
| // instrument. | ||||
| func (d *Descriptor) Description() string { | ||||
| 	return d.description | ||||
| } | ||||
|  | ||||
| // Unit describes the units of the metric instrument.  Unitless | ||||
| // metrics return the empty string. | ||||
| func (d *Descriptor) Unit() unit.Unit { | ||||
| 	return d.unit | ||||
| } | ||||
|  | ||||
| // NumberKind returns whether this instrument is declared over int64 | ||||
| // or a float64 values. | ||||
| func (d *Descriptor) NumberKind() core.NumberKind { | ||||
| 	return d.numberKind | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,7 @@ import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
| @@ -83,7 +84,7 @@ func (c *Aggregator) Points() ([]core.Number, error) { | ||||
|  | ||||
| // Checkpoint saves the current state and resets the current state to | ||||
| // the empty set, taking a lock to prevent concurrent Update() calls. | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *export.Descriptor) { | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { | ||||
| 	c.lock.Lock() | ||||
| 	c.checkpoint, c.current = c.current, nil | ||||
| 	c.lock.Unlock() | ||||
| @@ -106,7 +107,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, desc *export.Descriptor) { | ||||
| // Update adds the recorded measurement to the current data set. | ||||
| // Update takes a lock to prevent concurrent Update() and Checkpoint() | ||||
| // calls. | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	c.lock.Lock() | ||||
| 	c.current = append(c.current, number) | ||||
| 	c.lock.Unlock() | ||||
| @@ -114,7 +115,7 @@ func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export. | ||||
| } | ||||
|  | ||||
| // Merge combines two data sets into one. | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(c, oa) | ||||
|   | ||||
| @@ -25,8 +25,8 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/test" | ||||
| ) | ||||
| @@ -51,7 +51,7 @@ type updateTest struct { | ||||
| } | ||||
|  | ||||
| func (ut *updateTest) run(t *testing.T, profile test.Profile) { | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 	agg := New() | ||||
|  | ||||
| @@ -119,7 +119,7 @@ type mergeTest struct { | ||||
| func (mt *mergeTest) run(t *testing.T, profile test.Profile) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 	agg1 := New() | ||||
| 	agg2 := New() | ||||
| @@ -216,7 +216,7 @@ func TestArrayErrors(t *testing.T) { | ||||
|  | ||||
| 		ctx := context.Background() | ||||
|  | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		test.CheckedUpdate(t, agg, core.Number(0), descriptor) | ||||
|  | ||||
| @@ -244,7 +244,7 @@ func TestArrayErrors(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestArrayFloat64(t *testing.T) { | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, core.Float64NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, core.Float64NumberKind) | ||||
|  | ||||
| 	fpsf := func(sign int) []float64 { | ||||
| 		// Check behavior of a bunch of odd floating | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import ( | ||||
| 	sdk "github.com/DataDog/sketches-go/ddsketch" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
|  | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| @@ -43,7 +44,7 @@ var _ aggregator.MinMaxSumCount = &Aggregator{} | ||||
| var _ aggregator.Distribution = &Aggregator{} | ||||
|  | ||||
| // New returns a new DDSketch aggregator. | ||||
| func New(cfg *Config, desc *export.Descriptor) *Aggregator { | ||||
| func New(cfg *Config, desc *metric.Descriptor) *Aggregator { | ||||
| 	return &Aggregator{ | ||||
| 		cfg:        cfg, | ||||
| 		kind:       desc.NumberKind(), | ||||
| @@ -103,7 +104,7 @@ func (c *Aggregator) toNumber(f float64) core.Number { | ||||
|  | ||||
| // Checkpoint saves the current state and resets the current state to | ||||
| // the empty set, taking a lock to prevent concurrent Update() calls. | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, _ *export.Descriptor) { | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { | ||||
| 	replace := sdk.NewDDSketch(c.cfg) | ||||
|  | ||||
| 	c.lock.Lock() | ||||
| @@ -115,7 +116,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, _ *export.Descriptor) { | ||||
| // Update adds the recorded measurement to the current data set. | ||||
| // Update takes a lock to prevent concurrent Update() and Checkpoint() | ||||
| // calls. | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	c.lock.Lock() | ||||
| 	defer c.lock.Unlock() | ||||
| 	c.current.Add(number.CoerceToFloat64(desc.NumberKind())) | ||||
| @@ -123,7 +124,7 @@ func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export. | ||||
| } | ||||
|  | ||||
| // Merge combines two sketches into one. | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, d *export.Descriptor) error { | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, d *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(c, oa) | ||||
|   | ||||
| @@ -21,7 +21,7 @@ import ( | ||||
|  | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/test" | ||||
| ) | ||||
|  | ||||
| @@ -33,7 +33,7 @@ type updateTest struct { | ||||
| func (ut *updateTest) run(t *testing.T, profile test.Profile) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
| 	agg := New(NewDefaultConfig(), descriptor) | ||||
|  | ||||
| 	all := test.NewNumbers(profile.NumberKind) | ||||
| @@ -92,7 +92,7 @@ type mergeTest struct { | ||||
|  | ||||
| func (mt *mergeTest) run(t *testing.T, profile test.Profile) { | ||||
| 	ctx := context.Background() | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 	agg1 := New(NewDefaultConfig(), descriptor) | ||||
| 	agg2 := New(NewDefaultConfig(), descriptor) | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import ( | ||||
| 	"sort" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/internal" | ||||
| @@ -68,7 +69,7 @@ var _ aggregator.Histogram = &Aggregator{} | ||||
| // Note that this aggregator maintains each value using independent | ||||
| // atomic operations, which introduces the possibility that | ||||
| // checkpoints are inconsistent. | ||||
| func New(desc *export.Descriptor, boundaries []core.Number) *Aggregator { | ||||
| func New(desc *metric.Descriptor, boundaries []core.Number) *Aggregator { | ||||
| 	// Boundaries MUST be ordered otherwise the histogram could not | ||||
| 	// be properly computed. | ||||
| 	sortedBoundaries := numbers{ | ||||
| @@ -126,7 +127,7 @@ func (c *Aggregator) Histogram() (aggregator.Buckets, error) { | ||||
| // the empty set.  Since no locks are taken, there is a chance that | ||||
| // the independent Sum, Count and Bucket Count are not consistent with each | ||||
| // other. | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *export.Descriptor) { | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { | ||||
| 	c.lock.SwapActiveState(c.resetCheckpoint) | ||||
| } | ||||
|  | ||||
| @@ -144,7 +145,7 @@ func (c *Aggregator) resetCheckpoint() { | ||||
| } | ||||
|  | ||||
| // Update adds the recorded measurement to the current data set. | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	kind := desc.NumberKind() | ||||
|  | ||||
| 	cIdx := c.lock.Start() | ||||
| @@ -168,7 +169,7 @@ func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export. | ||||
| } | ||||
|  | ||||
| // Merge combines two histograms that have the same buckets into a single one. | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(c, oa) | ||||
|   | ||||
| @@ -26,8 +26,8 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/test" | ||||
| ) | ||||
|  | ||||
| @@ -116,7 +116,7 @@ func TestHistogramPositiveAndNegative(t *testing.T) { | ||||
| // Validates count, sum and buckets for a given profile and policy | ||||
| func histogram(t *testing.T, profile test.Profile, policy policy) { | ||||
| 	ctx := context.Background() | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 	agg := New(descriptor, boundaries[profile.NumberKind]) | ||||
|  | ||||
| @@ -158,7 +158,7 @@ func TestHistogramMerge(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		agg1 := New(descriptor, boundaries[profile.NumberKind]) | ||||
| 		agg2 := New(descriptor, boundaries[profile.NumberKind]) | ||||
| @@ -210,7 +210,7 @@ func TestHistogramNotSet(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		agg := New(descriptor, boundaries[profile.NumberKind]) | ||||
| 		agg.Checkpoint(ctx, descriptor) | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
| @@ -80,12 +81,12 @@ func (g *Aggregator) LastValue() (core.Number, time.Time, error) { | ||||
| } | ||||
|  | ||||
| // Checkpoint atomically saves the current value. | ||||
| func (g *Aggregator) Checkpoint(ctx context.Context, _ *export.Descriptor) { | ||||
| func (g *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { | ||||
| 	g.checkpoint = atomic.LoadPointer(&g.current) | ||||
| } | ||||
|  | ||||
| // Update atomically sets the current "last" value. | ||||
| func (g *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (g *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	ngd := &lastValueData{ | ||||
| 		value:     number, | ||||
| 		timestamp: time.Now(), | ||||
| @@ -96,7 +97,7 @@ func (g *Aggregator) Update(_ context.Context, number core.Number, desc *export. | ||||
|  | ||||
| // Merge combines state from two aggregators.  The most-recently set | ||||
| // value is chosen. | ||||
| func (g *Aggregator) Merge(oa export.Aggregator, desc *export.Descriptor) error { | ||||
| func (g *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(g, oa) | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| @@ -55,7 +56,7 @@ func TestLastValueUpdate(t *testing.T) { | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		agg := New() | ||||
|  | ||||
| 		record := test.NewAggregatorTest(export.ObserverKind, profile.NumberKind) | ||||
| 		record := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind) | ||||
|  | ||||
| 		var last core.Number | ||||
| 		for i := 0; i < count; i++ { | ||||
| @@ -79,7 +80,7 @@ func TestLastValueMerge(t *testing.T) { | ||||
| 		agg1 := New() | ||||
| 		agg2 := New() | ||||
|  | ||||
| 		descriptor := test.NewAggregatorTest(export.ObserverKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind) | ||||
|  | ||||
| 		first1 := profile.Random(+1) | ||||
| 		first2 := profile.Random(+1) | ||||
| @@ -107,7 +108,7 @@ func TestLastValueMerge(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestLastValueNotSet(t *testing.T) { | ||||
| 	descriptor := test.NewAggregatorTest(export.ObserverKind, core.Int64NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.ObserverKind, core.Int64NumberKind) | ||||
|  | ||||
| 	g := New() | ||||
| 	g.Checkpoint(context.Background(), descriptor) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/internal" | ||||
| @@ -50,7 +51,7 @@ var _ aggregator.MinMaxSumCount = &Aggregator{} | ||||
| // | ||||
| // This aggregator uses the StateLocker pattern to guarantee | ||||
| // the count, sum, min and max are consistent within a checkpoint | ||||
| func New(desc *export.Descriptor) *Aggregator { | ||||
| func New(desc *metric.Descriptor) *Aggregator { | ||||
| 	kind := desc.NumberKind() | ||||
| 	return &Aggregator{ | ||||
| 		kind: kind, | ||||
| @@ -111,7 +112,7 @@ func (c *Aggregator) Max() (core.Number, error) { | ||||
|  | ||||
| // Checkpoint saves the current state and resets the current state to | ||||
| // the empty set. | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *export.Descriptor) { | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { | ||||
| 	c.lock.SwapActiveState(c.resetCheckpoint) | ||||
| } | ||||
|  | ||||
| @@ -131,7 +132,7 @@ func (c *Aggregator) resetCheckpoint() { | ||||
| } | ||||
|  | ||||
| // Update adds the recorded measurement to the current data set. | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	kind := desc.NumberKind() | ||||
|  | ||||
| 	cIdx := c.lock.Start() | ||||
| @@ -165,7 +166,7 @@ func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export. | ||||
| } | ||||
|  | ||||
| // Merge combines two data sets into one. | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(c, oa) | ||||
|   | ||||
| @@ -25,8 +25,8 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/test" | ||||
| ) | ||||
| @@ -114,7 +114,7 @@ func TestMinMaxSumCountPositiveAndNegative(t *testing.T) { | ||||
| // Validates min, max, sum and count for a given profile and policy | ||||
| func minMaxSumCount(t *testing.T, profile test.Profile, policy policy) { | ||||
| 	ctx := context.Background() | ||||
| 	descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 	descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 	agg := New(descriptor) | ||||
|  | ||||
| @@ -162,7 +162,7 @@ func TestMinMaxSumCountMerge(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		agg1 := New(descriptor) | ||||
| 		agg2 := New(descriptor) | ||||
| @@ -220,7 +220,7 @@ func TestMaxSumCountNotSet(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		agg := New(descriptor) | ||||
| 		agg.Checkpoint(ctx, descriptor) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
| @@ -51,18 +52,18 @@ func (c *Aggregator) Sum() (core.Number, error) { | ||||
|  | ||||
| // Checkpoint atomically saves the current value and resets the | ||||
| // current sum to zero. | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, _ *export.Descriptor) { | ||||
| func (c *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { | ||||
| 	c.checkpoint = c.current.SwapNumberAtomic(core.Number(0)) | ||||
| } | ||||
|  | ||||
| // Update atomically adds to the current value. | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { | ||||
| 	c.current.AddNumberAtomic(desc.NumberKind(), number) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Merge combines two counters by adding their sums. | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *export.Descriptor) error { | ||||
| func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error { | ||||
| 	o, _ := oa.(*Aggregator) | ||||
| 	if o == nil { | ||||
| 		return aggregator.NewInconsistentMergeError(c, oa) | ||||
|   | ||||
| @@ -23,8 +23,8 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/test" | ||||
| ) | ||||
|  | ||||
| @@ -55,7 +55,7 @@ func TestCounterSum(t *testing.T) { | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		agg := New() | ||||
|  | ||||
| 		descriptor := test.NewAggregatorTest(export.CounterKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.CounterKind, profile.NumberKind) | ||||
|  | ||||
| 		sum := core.Number(0) | ||||
| 		for i := 0; i < count; i++ { | ||||
| @@ -78,7 +78,7 @@ func TestMeasureSum(t *testing.T) { | ||||
| 	test.RunProfiles(t, func(t *testing.T, profile test.Profile) { | ||||
| 		agg := New() | ||||
|  | ||||
| 		descriptor := test.NewAggregatorTest(export.MeasureKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) | ||||
|  | ||||
| 		sum := core.Number(0) | ||||
|  | ||||
| @@ -106,7 +106,7 @@ func TestCounterMerge(t *testing.T) { | ||||
| 		agg1 := New() | ||||
| 		agg2 := New() | ||||
|  | ||||
| 		descriptor := test.NewAggregatorTest(export.CounterKind, profile.NumberKind) | ||||
| 		descriptor := test.NewAggregatorTest(metric.CounterKind, profile.NumberKind) | ||||
|  | ||||
| 		sum := core.Number(0) | ||||
| 		for i := 0; i < count; i++ { | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	ottest "go.opentelemetry.io/otel/internal/testing" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| @@ -53,8 +54,9 @@ func newProfiles() []Profile { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewAggregatorTest(mkind export.Kind, nkind core.NumberKind) *export.Descriptor { | ||||
| 	return export.NewDescriptor("test.name", mkind, nil, "", "", nkind) | ||||
| func NewAggregatorTest(mkind metric.Kind, nkind core.NumberKind) *metric.Descriptor { | ||||
| 	desc := metric.NewDescriptor("test.name", mkind, nkind) | ||||
| 	return &desc | ||||
| } | ||||
|  | ||||
| func RunProfiles(t *testing.T, f func(*testing.T, Profile)) { | ||||
| @@ -147,7 +149,7 @@ func (n *Numbers) Points() []core.Number { | ||||
| } | ||||
|  | ||||
| // Performs the same range test the SDK does on behalf of the aggregator. | ||||
| func CheckedUpdate(t *testing.T, agg export.Aggregator, number core.Number, descriptor *export.Descriptor) { | ||||
| func CheckedUpdate(t *testing.T, agg export.Aggregator, number core.Number, descriptor *metric.Descriptor) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	// Note: Aggregator tests are written assuming that the SDK | ||||
| @@ -163,7 +165,7 @@ func CheckedUpdate(t *testing.T, agg export.Aggregator, number core.Number, desc | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func CheckedMerge(t *testing.T, aggInto, aggFrom export.Aggregator, descriptor *export.Descriptor) { | ||||
| func CheckedMerge(t *testing.T, aggInto, aggFrom export.Aggregator, descriptor *metric.Descriptor) { | ||||
| 	if err := aggInto.Merge(aggFrom, descriptor); err != nil { | ||||
| 		t.Error("Unexpected Merge failure", err) | ||||
| 	} | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import ( | ||||
| 	"errors" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
| @@ -34,11 +35,11 @@ type ( | ||||
|  | ||||
| 	// descKeyIndexMap is a mapping, for each Descriptor, from the | ||||
| 	// Key to the position in the descriptor's recommended keys. | ||||
| 	descKeyIndexMap map[*export.Descriptor]map[core.Key]int | ||||
| 	descKeyIndexMap map[*metric.Descriptor]map[core.Key]int | ||||
|  | ||||
| 	// batchKey describes a unique metric descriptor and encoded label set. | ||||
| 	batchKey struct { | ||||
| 		descriptor *export.Descriptor | ||||
| 		descriptor *metric.Descriptor | ||||
| 		encoded    string | ||||
| 	} | ||||
|  | ||||
| @@ -66,7 +67,7 @@ func New(selector export.AggregationSelector, labelEncoder export.LabelEncoder, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Batcher) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (b *Batcher) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	return b.selector.AggregatorFor(descriptor) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,21 +30,21 @@ func TestGroupingStateless(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
| 	b := defaultkeys.New(test.NewAggregationSelector(), test.GroupEncoder, false) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels3, 30)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels3, 30)) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels3, 30)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels3, 30)) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels3, 40)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels3, 40)) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels3, 40)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels3, 40)) | ||||
|  | ||||
| 	checkpointSet := b.CheckpointSet() | ||||
| 	b.FinishedCollection() | ||||
| @@ -56,7 +56,7 @@ func TestGroupingStateless(t *testing.T) { | ||||
| 	// Repeat for {counter,lastvalue}.{1,2}. | ||||
| 	// Output lastvalue should have only the "G=H" and "G=" keys. | ||||
| 	// Output counter should have only the "C=D" and "C=" keys. | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/C=D":       30, // labels1 + labels2 | ||||
| 		"sum.a/C=":        40, // labels3 | ||||
| 		"sum.b/C=D":       30, // labels1 + labels2 | ||||
| @@ -80,11 +80,11 @@ func TestGroupingStateful(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
| 	b := defaultkeys.New(test.NewAggregationSelector(), test.GroupEncoder, true) | ||||
|  | ||||
| 	counterA := test.NewCounterRecord(test.CounterADesc, test.Labels1, 10) | ||||
| 	counterA := test.NewCounterRecord(&test.CounterADesc, test.Labels1, 10) | ||||
| 	caggA := counterA.Aggregator() | ||||
| 	_ = b.Process(ctx, counterA) | ||||
|  | ||||
| 	counterB := test.NewCounterRecord(test.CounterBDesc, test.Labels1, 10) | ||||
| 	counterB := test.NewCounterRecord(&test.CounterBDesc, test.Labels1, 10) | ||||
| 	caggB := counterB.Aggregator() | ||||
| 	_ = b.Process(ctx, counterB) | ||||
|  | ||||
| @@ -95,7 +95,7 @@ func TestGroupingStateful(t *testing.T) { | ||||
| 	err := checkpointSet.ForEach(records1.AddTo) | ||||
| 	require.NoError(t, err) | ||||
|  | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/C=D": 10, // labels1 | ||||
| 		"sum.b/C=D": 10, // labels1 | ||||
| 	}, records1) | ||||
| @@ -111,10 +111,10 @@ func TestGroupingStateful(t *testing.T) { | ||||
| 	require.EqualValues(t, records1, records2) | ||||
|  | ||||
| 	// Update and re-checkpoint the original record. | ||||
| 	_ = caggA.Update(ctx, core.NewInt64Number(20), test.CounterADesc) | ||||
| 	_ = caggB.Update(ctx, core.NewInt64Number(20), test.CounterBDesc) | ||||
| 	caggA.Checkpoint(ctx, test.CounterADesc) | ||||
| 	caggB.Checkpoint(ctx, test.CounterBDesc) | ||||
| 	_ = caggA.Update(ctx, core.NewInt64Number(20), &test.CounterADesc) | ||||
| 	_ = caggB.Update(ctx, core.NewInt64Number(20), &test.CounterBDesc) | ||||
| 	caggA.Checkpoint(ctx, &test.CounterADesc) | ||||
| 	caggB.Checkpoint(ctx, &test.CounterBDesc) | ||||
|  | ||||
| 	// As yet cagg has not been passed to Batcher.Process.  Should | ||||
| 	// not see an update. | ||||
| @@ -128,8 +128,8 @@ func TestGroupingStateful(t *testing.T) { | ||||
| 	require.EqualValues(t, records1, records3) | ||||
|  | ||||
| 	// Now process the second update | ||||
| 	_ = b.Process(ctx, export.NewRecord(test.CounterADesc, test.Labels1, caggA)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(test.CounterBDesc, test.Labels1, caggB)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(&test.CounterADesc, test.Labels1, caggA)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(&test.CounterBDesc, test.Labels1, caggB)) | ||||
|  | ||||
| 	checkpointSet = b.CheckpointSet() | ||||
| 	b.FinishedCollection() | ||||
| @@ -138,7 +138,7 @@ func TestGroupingStateful(t *testing.T) { | ||||
| 	err = checkpointSet.ForEach(records4.AddTo) | ||||
| 	require.NoError(t, err) | ||||
|  | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/C=D": 30, | ||||
| 		"sum.b/C=D": 30, | ||||
| 	}, records4) | ||||
|   | ||||
| @@ -21,7 +21,9 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/api/key" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| 	sdk "go.opentelemetry.io/otel/sdk/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/sum" | ||||
| @@ -32,7 +34,7 @@ type ( | ||||
| 	Encoder struct{} | ||||
|  | ||||
| 	// Output collects distinct metric/label set outputs. | ||||
| 	Output map[string]int64 | ||||
| 	Output map[string]float64 | ||||
|  | ||||
| 	// testAggregationSelector returns aggregators consistent with | ||||
| 	// the test variables below, needed for testing stateful | ||||
| @@ -42,15 +44,15 @@ type ( | ||||
|  | ||||
| var ( | ||||
| 	// LastValueADesc and LastValueBDesc group by "G" | ||||
| 	LastValueADesc = export.NewDescriptor( | ||||
| 		"lastvalue.a", export.ObserverKind, []core.Key{key.New("G")}, "", "", core.Int64NumberKind) | ||||
| 	LastValueBDesc = export.NewDescriptor( | ||||
| 		"lastvalue.b", export.ObserverKind, []core.Key{key.New("G")}, "", "", core.Int64NumberKind) | ||||
| 	LastValueADesc = metric.NewDescriptor( | ||||
| 		"lastvalue.a", metric.ObserverKind, core.Int64NumberKind, metric.WithKeys(key.New("G"))) | ||||
| 	LastValueBDesc = metric.NewDescriptor( | ||||
| 		"lastvalue.b", metric.ObserverKind, core.Int64NumberKind, metric.WithKeys(key.New("G"))) | ||||
| 	// CounterADesc and CounterBDesc group by "C" | ||||
| 	CounterADesc = export.NewDescriptor( | ||||
| 		"sum.a", export.CounterKind, []core.Key{key.New("C")}, "", "", core.Int64NumberKind) | ||||
| 	CounterBDesc = export.NewDescriptor( | ||||
| 		"sum.b", export.CounterKind, []core.Key{key.New("C")}, "", "", core.Int64NumberKind) | ||||
| 	CounterADesc = metric.NewDescriptor( | ||||
| 		"sum.a", metric.CounterKind, core.Int64NumberKind, metric.WithKeys(key.New("C"))) | ||||
| 	CounterBDesc = metric.NewDescriptor( | ||||
| 		"sum.b", metric.CounterKind, core.Int64NumberKind, metric.WithKeys(key.New("C"))) | ||||
|  | ||||
| 	// SdkEncoder uses a non-standard encoder like K1~V1&K2~V2 | ||||
| 	SdkEncoder = &Encoder{} | ||||
| @@ -75,11 +77,11 @@ func NewAggregationSelector() export.AggregationSelector { | ||||
| 	return &testAggregationSelector{} | ||||
| } | ||||
|  | ||||
| func (*testAggregationSelector) AggregatorFor(desc *export.Descriptor) export.Aggregator { | ||||
| func (*testAggregationSelector) AggregatorFor(desc *metric.Descriptor) export.Aggregator { | ||||
| 	switch desc.MetricKind() { | ||||
| 	case export.CounterKind: | ||||
| 	case metric.CounterKind: | ||||
| 		return sum.New() | ||||
| 	case export.ObserverKind: | ||||
| 	case metric.ObserverKind: | ||||
| 		return lastvalue.New() | ||||
| 	default: | ||||
| 		panic("Invalid descriptor MetricKind for this test") | ||||
| @@ -105,7 +107,7 @@ func (Encoder) Encode(labels []core.KeyValue) string { | ||||
| } | ||||
|  | ||||
| // LastValueAgg returns a checkpointed lastValue aggregator w/ the specified descriptor and value. | ||||
| func LastValueAgg(desc *export.Descriptor, v int64) export.Aggregator { | ||||
| func LastValueAgg(desc *metric.Descriptor, v int64) export.Aggregator { | ||||
| 	ctx := context.Background() | ||||
| 	gagg := lastvalue.New() | ||||
| 	_ = gagg.Update(ctx, core.NewInt64Number(v), desc) | ||||
| @@ -114,17 +116,17 @@ func LastValueAgg(desc *export.Descriptor, v int64) export.Aggregator { | ||||
| } | ||||
|  | ||||
| // Convenience method for building a test exported lastValue record. | ||||
| func NewLastValueRecord(desc *export.Descriptor, labels export.Labels, value int64) export.Record { | ||||
| func NewLastValueRecord(desc *metric.Descriptor, labels export.Labels, value int64) export.Record { | ||||
| 	return export.NewRecord(desc, labels, LastValueAgg(desc, value)) | ||||
| } | ||||
|  | ||||
| // Convenience method for building a test exported counter record. | ||||
| func NewCounterRecord(desc *export.Descriptor, labels export.Labels, value int64) export.Record { | ||||
| func NewCounterRecord(desc *metric.Descriptor, labels export.Labels, value int64) export.Record { | ||||
| 	return export.NewRecord(desc, labels, CounterAgg(desc, value)) | ||||
| } | ||||
|  | ||||
| // CounterAgg returns a checkpointed counter aggregator w/ the specified descriptor and value. | ||||
| func CounterAgg(desc *export.Descriptor, v int64) export.Aggregator { | ||||
| func CounterAgg(desc *metric.Descriptor, v int64) export.Aggregator { | ||||
| 	ctx := context.Background() | ||||
| 	cagg := sum.New() | ||||
| 	_ = cagg.Update(ctx, core.NewInt64Number(v), desc) | ||||
| @@ -137,14 +139,16 @@ func CounterAgg(desc *export.Descriptor, v int64) export.Aggregator { | ||||
| func (o Output) AddTo(rec export.Record) error { | ||||
| 	labels := rec.Labels() | ||||
| 	key := fmt.Sprint(rec.Descriptor().Name(), "/", labels.Encoded()) | ||||
| 	var value int64 | ||||
| 	switch t := rec.Aggregator().(type) { | ||||
| 	case *sum.Aggregator: | ||||
| 		sum, _ := t.Sum() | ||||
| 		value = sum.AsInt64() | ||||
| 	case *lastvalue.Aggregator: | ||||
| 		lv, _, _ := t.LastValue() | ||||
| 		value = lv.AsInt64() | ||||
| 	var value float64 | ||||
|  | ||||
| 	if s, ok := rec.Aggregator().(aggregator.Sum); ok { | ||||
| 		sum, _ := s.Sum() | ||||
| 		value = sum.CoerceToFloat64(rec.Descriptor().NumberKind()) | ||||
| 	} else if l, ok := rec.Aggregator().(aggregator.LastValue); ok { | ||||
| 		last, _, _ := l.LastValue() | ||||
| 		value = last.CoerceToFloat64(rec.Descriptor().NumberKind()) | ||||
| 	} else { | ||||
| 		panic(fmt.Sprintf("Unhandled aggregator type: %T", rec.Aggregator())) | ||||
| 	} | ||||
| 	o[key] = value | ||||
| 	return nil | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric/aggregator" | ||||
| ) | ||||
| @@ -30,7 +31,7 @@ type ( | ||||
| 	} | ||||
|  | ||||
| 	batchKey struct { | ||||
| 		descriptor *export.Descriptor | ||||
| 		descriptor *metric.Descriptor | ||||
| 		encoded    string | ||||
| 	} | ||||
|  | ||||
| @@ -53,7 +54,7 @@ func New(selector export.AggregationSelector, stateful bool) *Batcher { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Batcher) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (b *Batcher) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	return b.selector.AggregatorFor(descriptor) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -33,30 +33,30 @@ func TestUngroupedStateless(t *testing.T) { | ||||
| 	b := ungrouped.New(test.NewAggregationSelector(), false) | ||||
|  | ||||
| 	// Set initial lastValue values | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels3, 30)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels3, 30)) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels3, 30)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels3, 30)) | ||||
|  | ||||
| 	// Another lastValue Set for Labels1 | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueADesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(test.LastValueBDesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueBDesc, test.Labels1, 50)) | ||||
|  | ||||
| 	// Set initial counter values | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels3, 40)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels3, 40)) | ||||
|  | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels3, 40)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels1, 10)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels2, 20)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels3, 40)) | ||||
|  | ||||
| 	// Another counter Add for Labels1 | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterADesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(test.CounterBDesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterADesc, test.Labels1, 50)) | ||||
| 	_ = b.Process(ctx, test.NewCounterRecord(&test.CounterBDesc, test.Labels1, 50)) | ||||
|  | ||||
| 	checkpointSet := b.CheckpointSet() | ||||
| 	b.FinishedCollection() | ||||
| @@ -66,7 +66,7 @@ func TestUngroupedStateless(t *testing.T) { | ||||
|  | ||||
| 	// Output lastvalue should have only the "G=H" and "G=" keys. | ||||
| 	// Output counter should have only the "C=D" and "C=" keys. | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/G~H&C~D":       60, // labels1 | ||||
| 		"sum.a/C~D&E~F":       20, // labels2 | ||||
| 		"sum.a/":              40, // labels3 | ||||
| @@ -94,11 +94,11 @@ func TestUngroupedStateful(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
| 	b := ungrouped.New(test.NewAggregationSelector(), true) | ||||
|  | ||||
| 	counterA := test.NewCounterRecord(test.CounterADesc, test.Labels1, 10) | ||||
| 	counterA := test.NewCounterRecord(&test.CounterADesc, test.Labels1, 10) | ||||
| 	caggA := counterA.Aggregator() | ||||
| 	_ = b.Process(ctx, counterA) | ||||
|  | ||||
| 	counterB := test.NewCounterRecord(test.CounterBDesc, test.Labels1, 10) | ||||
| 	counterB := test.NewCounterRecord(&test.CounterBDesc, test.Labels1, 10) | ||||
| 	caggB := counterB.Aggregator() | ||||
| 	_ = b.Process(ctx, counterB) | ||||
|  | ||||
| @@ -108,7 +108,7 @@ func TestUngroupedStateful(t *testing.T) { | ||||
| 	records1 := test.Output{} | ||||
| 	_ = checkpointSet.ForEach(records1.AddTo) | ||||
|  | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/G~H&C~D": 10, // labels1 | ||||
| 		"sum.b/G~H&C~D": 10, // labels1 | ||||
| 	}, records1) | ||||
| @@ -123,10 +123,10 @@ func TestUngroupedStateful(t *testing.T) { | ||||
| 	require.EqualValues(t, records1, records2) | ||||
|  | ||||
| 	// Update and re-checkpoint the original record. | ||||
| 	_ = caggA.Update(ctx, core.NewInt64Number(20), test.CounterADesc) | ||||
| 	_ = caggB.Update(ctx, core.NewInt64Number(20), test.CounterBDesc) | ||||
| 	caggA.Checkpoint(ctx, test.CounterADesc) | ||||
| 	caggB.Checkpoint(ctx, test.CounterBDesc) | ||||
| 	_ = caggA.Update(ctx, core.NewInt64Number(20), &test.CounterADesc) | ||||
| 	_ = caggB.Update(ctx, core.NewInt64Number(20), &test.CounterBDesc) | ||||
| 	caggA.Checkpoint(ctx, &test.CounterADesc) | ||||
| 	caggB.Checkpoint(ctx, &test.CounterBDesc) | ||||
|  | ||||
| 	// As yet cagg has not been passed to Batcher.Process.  Should | ||||
| 	// not see an update. | ||||
| @@ -139,8 +139,8 @@ func TestUngroupedStateful(t *testing.T) { | ||||
| 	require.EqualValues(t, records1, records3) | ||||
|  | ||||
| 	// Now process the second update | ||||
| 	_ = b.Process(ctx, export.NewRecord(test.CounterADesc, test.Labels1, caggA)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(test.CounterBDesc, test.Labels1, caggB)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(&test.CounterADesc, test.Labels1, caggA)) | ||||
| 	_ = b.Process(ctx, export.NewRecord(&test.CounterBDesc, test.Labels1, caggB)) | ||||
|  | ||||
| 	checkpointSet = b.CheckpointSet() | ||||
| 	b.FinishedCollection() | ||||
| @@ -148,7 +148,7 @@ func TestUngroupedStateful(t *testing.T) { | ||||
| 	records4 := test.Output{} | ||||
| 	_ = checkpointSet.ForEach(records4.AddTo) | ||||
|  | ||||
| 	require.EqualValues(t, map[string]int64{ | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"sum.a/G~H&C~D": 30, | ||||
| 		"sum.b/G~H&C~D": 30, | ||||
| 	}, records4) | ||||
|   | ||||
| @@ -44,11 +44,11 @@ func newFixture(b *testing.B) *benchFixture { | ||||
| 		B: b, | ||||
| 	} | ||||
| 	bf.sdk = sdk.New(bf, sdk.NewDefaultLabelEncoder()) | ||||
| 	bf.meter = metric.Must(bf.sdk) | ||||
| 	bf.meter = metric.Must(metric.WrapMeterImpl(bf.sdk)) | ||||
| 	return bf | ||||
| } | ||||
|  | ||||
| func (*benchFixture) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (*benchFixture) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	name := descriptor.Name() | ||||
| 	switch { | ||||
| 	case strings.HasSuffix(name, "counter"): | ||||
| @@ -377,40 +377,6 @@ func BenchmarkObserverRegistration(b *testing.B) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkObserverRegistrationUnregistration(b *testing.B) { | ||||
| 	fix := newFixture(b) | ||||
| 	names := make([]string, 0, b.N) | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		names = append(names, fmt.Sprintf("test.observer.%d", i)) | ||||
| 	} | ||||
| 	cb := func(result metric.Int64ObserverResult) {} | ||||
|  | ||||
| 	b.ResetTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		fix.meter.RegisterInt64Observer(names[i], cb).Unregister() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkObserverRegistrationUnregistrationBatched(b *testing.B) { | ||||
| 	fix := newFixture(b) | ||||
| 	names := make([]string, 0, b.N) | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		names = append(names, fmt.Sprintf("test.observer.%d", i)) | ||||
| 	} | ||||
| 	observers := make([]metric.Int64Observer, 0, b.N) | ||||
| 	cb := func(result metric.Int64ObserverResult) {} | ||||
|  | ||||
| 	b.ResetTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		observers = append(observers, fix.meter.RegisterInt64Observer(names[i], cb)) | ||||
| 	} | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		observers[i].Unregister() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkObserverObservationInt64(b *testing.B) { | ||||
| 	ctx := context.Background() | ||||
| 	fix := newFixture(b) | ||||
|   | ||||
| @@ -29,6 +29,7 @@ type Controller struct { | ||||
| 	lock         sync.Mutex | ||||
| 	collectLock  sync.Mutex | ||||
| 	sdk          *sdk.SDK | ||||
| 	meter        metric.Meter | ||||
| 	errorHandler sdk.ErrorHandler | ||||
| 	batcher      export.Batcher | ||||
| 	exporter     export.Exporter | ||||
| @@ -80,8 +81,10 @@ func New(batcher export.Batcher, exporter export.Exporter, period time.Duration) | ||||
| 		lencoder = sdk.NewDefaultLabelEncoder() | ||||
| 	} | ||||
|  | ||||
| 	impl := sdk.New(batcher, lencoder) | ||||
| 	return &Controller{ | ||||
| 		sdk:          sdk.New(batcher, lencoder), | ||||
| 		sdk:          impl, | ||||
| 		meter:        metric.WrapMeterImpl(impl), | ||||
| 		errorHandler: sdk.DefaultErrorHandler, | ||||
| 		batcher:      batcher, | ||||
| 		exporter:     exporter, | ||||
| @@ -109,7 +112,7 @@ func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) { | ||||
| // Meter returns a named Meter, satisifying the metric.Provider | ||||
| // interface. | ||||
| func (c *Controller) Meter(_ string) metric.Meter { | ||||
| 	return c.sdk | ||||
| 	return c.meter | ||||
| } | ||||
|  | ||||
| // Start begins a ticker that periodically collects and exports | ||||
|   | ||||
| @@ -84,7 +84,7 @@ func newFixture(t *testing.T) testFixture { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *testBatcher) AggregatorFor(*export.Descriptor) export.Aggregator { | ||||
| func (b *testBatcher) AggregatorFor(*metric.Descriptor) export.Aggregator { | ||||
| 	return sum.New() | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -31,6 +31,7 @@ import ( | ||||
| 	sdk "go.opentelemetry.io/otel/sdk/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/array" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/sum" | ||||
| 	batchTest "go.opentelemetry.io/otel/sdk/metric/batcher/test" | ||||
| ) | ||||
|  | ||||
| var Must = metric.Must | ||||
| @@ -43,7 +44,7 @@ type correctnessBatcher struct { | ||||
|  | ||||
| type testLabelEncoder struct{} | ||||
|  | ||||
| func (cb *correctnessBatcher) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (cb *correctnessBatcher) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	name := descriptor.Name() | ||||
| 	switch { | ||||
| 	case strings.HasSuffix(name, ".counter"): | ||||
| @@ -78,13 +79,14 @@ func TestInputRangeTestCounter(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	var sdkErr error | ||||
| 	sdk.SetErrorHandler(func(handleErr error) { | ||||
| 		sdkErr = handleErr | ||||
| 	}) | ||||
|  | ||||
| 	counter := Must(sdk).NewInt64Counter("name.counter") | ||||
| 	counter := Must(meter).NewInt64Counter("name.counter") | ||||
|  | ||||
| 	counter.Add(ctx, -1, sdk.Labels()) | ||||
| 	require.Equal(t, aggregator.ErrNegativeInput, sdkErr) | ||||
| @@ -112,13 +114,14 @@ func TestInputRangeTestMeasure(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	var sdkErr error | ||||
| 	sdk.SetErrorHandler(func(handleErr error) { | ||||
| 		sdkErr = handleErr | ||||
| 	}) | ||||
|  | ||||
| 	measure := Must(sdk).NewFloat64Measure("name.measure") | ||||
| 	measure := Must(meter).NewFloat64Measure("name.measure") | ||||
|  | ||||
| 	measure.Record(ctx, math.NaN(), sdk.Labels()) | ||||
| 	require.Equal(t, aggregator.ErrNaNInput, sdkErr) | ||||
| @@ -149,7 +152,8 @@ func TestDisabledInstrument(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	measure := Must(sdk).NewFloat64Measure("name.disabled") | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
| 	measure := Must(meter).NewFloat64Measure("name.disabled") | ||||
|  | ||||
| 	measure.Record(ctx, -1, sdk.Labels()) | ||||
| 	checkpointed := sdk.Collect(ctx) | ||||
| @@ -164,12 +168,13 @@ func TestRecordNaN(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	var sdkErr error | ||||
| 	sdk.SetErrorHandler(func(handleErr error) { | ||||
| 		sdkErr = handleErr | ||||
| 	}) | ||||
| 	c := Must(sdk).NewFloat64Counter("sum.name") | ||||
| 	c := Must(meter).NewFloat64Counter("sum.name") | ||||
|  | ||||
| 	require.Nil(t, sdkErr) | ||||
| 	c.Add(ctx, math.NaN(), sdk.Labels()) | ||||
| @@ -182,8 +187,9 @@ func TestSDKAltLabelEncoder(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, testLabelEncoder{}) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	measure := Must(sdk).NewFloat64Measure("measure") | ||||
| 	measure := Must(meter).NewFloat64Measure("measure") | ||||
| 	measure.Record(ctx, 1, sdk.Labels(key.String("A", "B"), key.String("C", "D"))) | ||||
|  | ||||
| 	sdk.Collect(ctx) | ||||
| @@ -200,8 +206,9 @@ func TestSDKLabelsDeduplication(t *testing.T) { | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	counter := Must(sdk).NewInt64Counter("counter") | ||||
| 	counter := Must(meter).NewInt64Counter("counter") | ||||
|  | ||||
| 	const ( | ||||
| 		maxKeys = 21 | ||||
| @@ -289,3 +296,45 @@ func TestDefaultLabelEncoder(t *testing.T) { | ||||
| 	}) | ||||
| 	require.Equal(t, "I=1,U=1,I32=1,U32=1,I64=1,U64=1,F64=1,F64=1,S=1,B=true", encoded) | ||||
| } | ||||
|  | ||||
| func TestObserverCollection(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
| 	batcher := &correctnessBatcher{ | ||||
| 		t: t, | ||||
| 	} | ||||
| 	sdk := sdk.New(batcher, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
|  | ||||
| 	_ = Must(meter).RegisterFloat64Observer("float.observer", func(result metric.Float64ObserverResult) { | ||||
| 		// TODO: The spec says the last-value wins in observer | ||||
| 		// instruments, but it is not implemented yet, i.e., with the | ||||
| 		// following line we get 1-1==0 instead of -1: | ||||
| 		// result.Observe(1, meter.Labels(key.String("A", "B"))) | ||||
|  | ||||
| 		result.Observe(-1, meter.Labels(key.String("A", "B"))) | ||||
| 		result.Observe(-1, meter.Labels(key.String("C", "D"))) | ||||
| 	}) | ||||
| 	_ = Must(meter).RegisterInt64Observer("int.observer", func(result metric.Int64ObserverResult) { | ||||
| 		result.Observe(1, meter.Labels(key.String("A", "B"))) | ||||
| 		result.Observe(1, meter.Labels()) | ||||
| 	}) | ||||
| 	_ = Must(meter).RegisterInt64Observer("empty.observer", func(result metric.Int64ObserverResult) { | ||||
| 	}) | ||||
|  | ||||
| 	collected := sdk.Collect(ctx) | ||||
|  | ||||
| 	require.Equal(t, 4, collected) | ||||
| 	require.Equal(t, 4, len(batcher.records)) | ||||
|  | ||||
| 	out := batchTest.Output{} | ||||
| 	for _, rec := range batcher.records { | ||||
| 		_ = out.AddTo(rec) | ||||
| 	} | ||||
| 	require.EqualValues(t, map[string]float64{ | ||||
| 		"float.observer/A=B": -1, | ||||
| 		"float.observer/C=D": -1, | ||||
| 		"int.observer/":      1, | ||||
| 		"int.observer/A=B":   1, | ||||
| 	}, out) | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -25,13 +25,13 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram" | ||||
| ) | ||||
|  | ||||
| func TestStressInt64Histogram(t *testing.T) { | ||||
| 	desc := metric.NewDescriptor("some_metric", metric.MeasureKind, nil, "", "", core.Int64NumberKind) | ||||
| 	h := histogram.New(desc, []core.Number{core.NewInt64Number(25), core.NewInt64Number(50), core.NewInt64Number(75)}) | ||||
| 	desc := metric.NewDescriptor("some_metric", metric.MeasureKind, core.Int64NumberKind) | ||||
| 	h := histogram.New(&desc, []core.Number{core.NewInt64Number(25), core.NewInt64Number(50), core.NewInt64Number(75)}) | ||||
|  | ||||
| 	ctx, cancelFunc := context.WithCancel(context.Background()) | ||||
| 	defer cancelFunc() | ||||
| @@ -42,14 +42,14 @@ func TestStressInt64Histogram(t *testing.T) { | ||||
| 			case <-ctx.Done(): | ||||
| 				return | ||||
| 			default: | ||||
| 				_ = h.Update(ctx, core.NewInt64Number(rnd.Int63()%100), desc) | ||||
| 				_ = h.Update(ctx, core.NewInt64Number(rnd.Int63()%100), &desc) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	startTime := time.Now() | ||||
| 	for time.Since(startTime) < time.Second { | ||||
| 		h.Checkpoint(context.Background(), desc) | ||||
| 		h.Checkpoint(context.Background(), &desc) | ||||
|  | ||||
| 		b, _ := h.Histogram() | ||||
| 		c, _ := h.Count() | ||||
|   | ||||
| @@ -25,13 +25,13 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	"go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" | ||||
| ) | ||||
|  | ||||
| func TestStressInt64MinMaxSumCount(t *testing.T) { | ||||
| 	desc := metric.NewDescriptor("some_metric", metric.MeasureKind, nil, "", "", core.Int64NumberKind) | ||||
| 	mmsc := minmaxsumcount.New(desc) | ||||
| 	desc := metric.NewDescriptor("some_metric", metric.MeasureKind, core.Int64NumberKind) | ||||
| 	mmsc := minmaxsumcount.New(&desc) | ||||
|  | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	defer cancel() | ||||
| @@ -43,7 +43,7 @@ func TestStressInt64MinMaxSumCount(t *testing.T) { | ||||
| 			case <-ctx.Done(): | ||||
| 				return | ||||
| 			default: | ||||
| 				_ = mmsc.Update(ctx, core.NewInt64Number(v), desc) | ||||
| 				_ = mmsc.Update(ctx, core.NewInt64Number(v), &desc) | ||||
| 			} | ||||
| 			v++ | ||||
| 		} | ||||
| @@ -51,7 +51,7 @@ func TestStressInt64MinMaxSumCount(t *testing.T) { | ||||
|  | ||||
| 	startTime := time.Now() | ||||
| 	for time.Since(startTime) < time.Second { | ||||
| 		mmsc.Checkpoint(context.Background(), desc) | ||||
| 		mmsc.Checkpoint(context.Background(), &desc) | ||||
|  | ||||
| 		s, _ := mmsc.Sum() | ||||
| 		c, _ := mmsc.Count() | ||||
|   | ||||
| @@ -44,8 +44,9 @@ type ( | ||||
| 		// current maps `mapkey` to *record. | ||||
| 		current sync.Map | ||||
|  | ||||
| 		// observers is a set of `*observer` instances | ||||
| 		observers sync.Map | ||||
| 		// asyncInstruments is a set of | ||||
| 		// `*asyncInstrument` instances | ||||
| 		asyncInstruments sync.Map | ||||
|  | ||||
| 		// empty is the (singleton) result of Labels() | ||||
| 		// w/ zero arguments. | ||||
| @@ -68,9 +69,8 @@ type ( | ||||
| 		errorHandler ErrorHandler | ||||
| 	} | ||||
|  | ||||
| 	instrument struct { | ||||
| 		descriptor *export.Descriptor | ||||
| 		meter      *SDK | ||||
| 	syncInstrument struct { | ||||
| 		instrument | ||||
| 	} | ||||
|  | ||||
| 	// orderedLabels is a variable-size array of core.KeyValue | ||||
| @@ -95,7 +95,7 @@ type ( | ||||
| 	// mapkey uniquely describes a metric instrument in terms of | ||||
| 	// its InstrumentID and the encoded form of its LabelSet. | ||||
| 	mapkey struct { | ||||
| 		descriptor *export.Descriptor | ||||
| 		descriptor *metric.Descriptor | ||||
| 		ordered    orderedLabels | ||||
| 	} | ||||
|  | ||||
| @@ -117,8 +117,8 @@ type ( | ||||
| 		// labels is the LabelSet passed by the user. | ||||
| 		labels *labels | ||||
|  | ||||
| 		// descriptor describes the metric instrument. | ||||
| 		descriptor *export.Descriptor | ||||
| 		// inst is a pointer to the corresponding instrument. | ||||
| 		inst *syncInstrument | ||||
|  | ||||
| 		// recorder implements the actual RecordOne() API, | ||||
| 		// depending on the type of aggregation.  If nil, the | ||||
| @@ -126,27 +126,18 @@ type ( | ||||
| 		recorder export.Aggregator | ||||
| 	} | ||||
|  | ||||
| 	observerResult struct { | ||||
| 		observer *observer | ||||
| 	} | ||||
|  | ||||
| 	int64ObserverResult struct { | ||||
| 		result observerResult | ||||
| 	} | ||||
|  | ||||
| 	float64ObserverResult struct { | ||||
| 		result observerResult | ||||
| 	} | ||||
|  | ||||
| 	observerCallback func(result observerResult) | ||||
|  | ||||
| 	observer struct { | ||||
| 	instrument struct { | ||||
| 		meter      *SDK | ||||
| 		descriptor *export.Descriptor | ||||
| 		descriptor metric.Descriptor | ||||
| 	} | ||||
|  | ||||
| 	asyncInstrument struct { | ||||
| 		instrument | ||||
| 		// recorders maps ordered labels to the pair of | ||||
| 		// labelset and recorder | ||||
| 		recorders map[orderedLabels]labeledRecorder | ||||
| 		callback  observerCallback | ||||
|  | ||||
| 		callback func(func(core.Number, api.LabelSet)) | ||||
| 	} | ||||
|  | ||||
| 	labeledRecorder struct { | ||||
| @@ -155,110 +146,83 @@ type ( | ||||
| 		modifiedEpoch int64 | ||||
| 	} | ||||
|  | ||||
| 	int64Observer struct { | ||||
| 		observer *observer | ||||
| 	} | ||||
|  | ||||
| 	float64Observer struct { | ||||
| 		observer *observer | ||||
| 	} | ||||
|  | ||||
| 	ErrorHandler func(error) | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	_ api.Meter                 = &SDK{} | ||||
| 	_ api.LabelSet              = &labels{} | ||||
| 	_ api.InstrumentImpl        = &instrument{} | ||||
| 	_ api.BoundInstrumentImpl   = &record{} | ||||
| 	_ api.Int64Observer         = int64Observer{} | ||||
| 	_ api.Float64Observer       = float64Observer{} | ||||
| 	_ api.Int64ObserverResult   = int64ObserverResult{} | ||||
| 	_ api.Float64ObserverResult = float64ObserverResult{} | ||||
| 	_ api.MeterImpl     = &SDK{} | ||||
| 	_ api.LabelSet      = &labels{} | ||||
| 	_ api.AsyncImpl     = &asyncInstrument{} | ||||
| 	_ api.SyncImpl      = &syncInstrument{} | ||||
| 	_ api.BoundSyncImpl = &record{} | ||||
|  | ||||
| 	kvType = reflect.TypeOf(core.KeyValue{}) | ||||
| ) | ||||
|  | ||||
| func (r observerResult) observe(number core.Number, ls api.LabelSet) { | ||||
| 	r.observer.recordOne(number, ls) | ||||
| func (inst *instrument) Descriptor() api.Descriptor { | ||||
| 	return inst.descriptor | ||||
| } | ||||
|  | ||||
| func (o *observer) recordOne(number core.Number, ls api.LabelSet) { | ||||
| 	if err := aggregator.RangeTest(number, o.descriptor); err != nil { | ||||
| 		o.meter.errorHandler(err) | ||||
| func (a *asyncInstrument) Implementation() interface{} { | ||||
| 	return a | ||||
| } | ||||
|  | ||||
| func (s *syncInstrument) Implementation() interface{} { | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| func (a *asyncInstrument) observe(number core.Number, ls api.LabelSet) { | ||||
| 	if err := aggregator.RangeTest(number, &a.descriptor); err != nil { | ||||
| 		a.meter.errorHandler(err) | ||||
| 		return | ||||
| 	} | ||||
| 	recorder := o.getRecorder(ls) | ||||
| 	recorder := a.getRecorder(ls) | ||||
| 	if recorder == nil { | ||||
| 		// The instrument is disabled according to the | ||||
| 		// AggregationSelector. | ||||
| 		return | ||||
| 	} | ||||
| 	if err := recorder.Update(context.Background(), number, o.descriptor); err != nil { | ||||
| 		o.meter.errorHandler(err) | ||||
| 	if err := recorder.Update(context.Background(), number, &a.descriptor); err != nil { | ||||
| 		a.meter.errorHandler(err) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *observer) getRecorder(ls api.LabelSet) export.Aggregator { | ||||
| 	labels := o.meter.labsFor(ls) | ||||
| 	lrec, ok := o.recorders[labels.ordered] | ||||
| func (a *asyncInstrument) getRecorder(ls api.LabelSet) export.Aggregator { | ||||
| 	labels := a.meter.labsFor(ls) | ||||
| 	lrec, ok := a.recorders[labels.ordered] | ||||
| 	if ok { | ||||
| 		lrec.modifiedEpoch = o.meter.currentEpoch | ||||
| 		o.recorders[labels.ordered] = lrec | ||||
| 		lrec.modifiedEpoch = a.meter.currentEpoch | ||||
| 		a.recorders[labels.ordered] = lrec | ||||
| 		return lrec.recorder | ||||
| 	} | ||||
| 	rec := o.meter.batcher.AggregatorFor(o.descriptor) | ||||
| 	if o.recorders == nil { | ||||
| 		o.recorders = make(map[orderedLabels]labeledRecorder) | ||||
| 	rec := a.meter.batcher.AggregatorFor(&a.descriptor) | ||||
| 	if a.recorders == nil { | ||||
| 		a.recorders = make(map[orderedLabels]labeledRecorder) | ||||
| 	} | ||||
| 	// This may store nil recorder in the map, thus disabling the | ||||
| 	// observer for the labelset for good. This is intentional, | ||||
| 	// asyncInstrument for the labelset for good. This is intentional, | ||||
| 	// but will be revisited later. | ||||
| 	o.recorders[labels.ordered] = labeledRecorder{ | ||||
| 	a.recorders[labels.ordered] = labeledRecorder{ | ||||
| 		recorder:      rec, | ||||
| 		labels:        labels, | ||||
| 		modifiedEpoch: o.meter.currentEpoch, | ||||
| 		modifiedEpoch: a.meter.currentEpoch, | ||||
| 	} | ||||
| 	return rec | ||||
| } | ||||
|  | ||||
| func (o *observer) unregister() { | ||||
| 	o.meter.observers.Delete(o) | ||||
| } | ||||
|  | ||||
| func (r int64ObserverResult) Observe(value int64, labels api.LabelSet) { | ||||
| 	r.result.observe(core.NewInt64Number(value), labels) | ||||
| } | ||||
|  | ||||
| func (r float64ObserverResult) Observe(value float64, labels api.LabelSet) { | ||||
| 	r.result.observe(core.NewFloat64Number(value), labels) | ||||
| } | ||||
|  | ||||
| func (o int64Observer) Unregister() { | ||||
| 	o.observer.unregister() | ||||
| } | ||||
|  | ||||
| func (o float64Observer) Unregister() { | ||||
| 	o.observer.unregister() | ||||
| } | ||||
|  | ||||
| func (i *instrument) Meter() api.Meter { | ||||
| 	return i.meter | ||||
| } | ||||
|  | ||||
| func (m *SDK) SetErrorHandler(f ErrorHandler) { | ||||
| 	m.errorHandler = f | ||||
| } | ||||
|  | ||||
| func (i *instrument) acquireHandle(ls *labels) *record { | ||||
| func (s *syncInstrument) acquireHandle(ls *labels) *record { | ||||
| 	// Create lookup key for sync.Map (one allocation) | ||||
| 	mk := mapkey{ | ||||
| 		descriptor: i.descriptor, | ||||
| 		descriptor: &s.descriptor, | ||||
| 		ordered:    ls.ordered, | ||||
| 	} | ||||
|  | ||||
| 	if actual, ok := i.meter.current.Load(mk); ok { | ||||
| 	if actual, ok := s.meter.current.Load(mk); ok { | ||||
| 		// Existing record case, only one allocation so far. | ||||
| 		rec := actual.(*record) | ||||
| 		if rec.refMapped.ref() { | ||||
| @@ -271,17 +235,17 @@ func (i *instrument) acquireHandle(ls *labels) *record { | ||||
|  | ||||
| 	// There's a memory allocation here. | ||||
| 	rec := &record{ | ||||
| 		labels:     ls, | ||||
| 		descriptor: i.descriptor, | ||||
| 		refMapped:  refcountMapped{value: 2}, | ||||
| 		modified:   0, | ||||
| 		recorder:   i.meter.batcher.AggregatorFor(i.descriptor), | ||||
| 		labels:    ls, | ||||
| 		inst:      s, | ||||
| 		refMapped: refcountMapped{value: 2}, | ||||
| 		modified:  0, | ||||
| 		recorder:  s.meter.batcher.AggregatorFor(&s.descriptor), | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		// Load/Store: there's a memory allocation to place `mk` into | ||||
| 		// an interface here. | ||||
| 		if actual, loaded := i.meter.current.LoadOrStore(mk, rec); loaded { | ||||
| 		if actual, loaded := s.meter.current.LoadOrStore(mk, rec); loaded { | ||||
| 			// Existing record case. Cannot change rec here because if fail | ||||
| 			// will try to add rec again to avoid new allocations. | ||||
| 			oldRec := actual.(*record) | ||||
| @@ -308,14 +272,14 @@ func (i *instrument) acquireHandle(ls *labels) *record { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (i *instrument) Bind(ls api.LabelSet) api.BoundInstrumentImpl { | ||||
| 	labs := i.meter.labsFor(ls) | ||||
| 	return i.acquireHandle(labs) | ||||
| func (s *syncInstrument) Bind(ls api.LabelSet) api.BoundSyncImpl { | ||||
| 	labs := s.meter.labsFor(ls) | ||||
| 	return s.acquireHandle(labs) | ||||
| } | ||||
|  | ||||
| func (i *instrument) RecordOne(ctx context.Context, number core.Number, ls api.LabelSet) { | ||||
| 	ourLs := i.meter.labsFor(ls) | ||||
| 	h := i.acquireHandle(ourLs) | ||||
| func (s *syncInstrument) RecordOne(ctx context.Context, number core.Number, ls api.LabelSet) { | ||||
| 	ourLs := s.meter.labsFor(ls) | ||||
| 	h := s.acquireHandle(ourLs) | ||||
| 	defer h.Unbind() | ||||
| 	h.RecordOne(ctx, number) | ||||
| } | ||||
| @@ -461,100 +425,25 @@ func (m *SDK) labsFor(ls api.LabelSet) *labels { | ||||
| 	return &m.empty | ||||
| } | ||||
|  | ||||
| func newDescriptor(name string, metricKind export.Kind, numberKind core.NumberKind, opts []api.Option) *export.Descriptor { | ||||
| 	config := api.Configure(opts) | ||||
| 	return export.NewDescriptor( | ||||
| 		name, | ||||
| 		metricKind, | ||||
| 		config.Keys, | ||||
| 		config.Description, | ||||
| 		config.Unit, | ||||
| 		numberKind) | ||||
| } | ||||
|  | ||||
| func (m *SDK) newInstrument(name string, metricKind export.Kind, numberKind core.NumberKind, opts []api.Option) *instrument { | ||||
| 	descriptor := newDescriptor(name, metricKind, numberKind, opts) | ||||
| 	return &instrument{ | ||||
| 		descriptor: descriptor, | ||||
| 		meter:      m, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *SDK) newCounterInstrument(name string, numberKind core.NumberKind, opts []api.Option) *instrument { | ||||
| 	return m.newInstrument(name, export.CounterKind, numberKind, opts) | ||||
| } | ||||
|  | ||||
| func (m *SDK) newMeasureInstrument(name string, numberKind core.NumberKind, opts []api.Option) *instrument { | ||||
| 	return m.newInstrument(name, export.MeasureKind, numberKind, opts) | ||||
| } | ||||
|  | ||||
| func (m *SDK) NewInt64Counter(name string, opts ...api.Option) (api.Int64Counter, error) { | ||||
| 	return api.WrapInt64CounterInstrument(m.newCounterInstrument(name, core.Int64NumberKind, opts), nil) | ||||
| } | ||||
|  | ||||
| func (m *SDK) NewFloat64Counter(name string, opts ...api.Option) (api.Float64Counter, error) { | ||||
| 	return api.WrapFloat64CounterInstrument(m.newCounterInstrument(name, core.Float64NumberKind, opts), nil) | ||||
| } | ||||
|  | ||||
| func (m *SDK) NewInt64Measure(name string, opts ...api.Option) (api.Int64Measure, error) { | ||||
| 	return api.WrapInt64MeasureInstrument(m.newMeasureInstrument(name, core.Int64NumberKind, opts), nil) | ||||
| } | ||||
|  | ||||
| func (m *SDK) NewFloat64Measure(name string, opts ...api.Option) (api.Float64Measure, error) { | ||||
| 	return api.WrapFloat64MeasureInstrument(m.newMeasureInstrument(name, core.Float64NumberKind, opts), nil) | ||||
| } | ||||
|  | ||||
| func (m *SDK) RegisterInt64Observer(name string, callback api.Int64ObserverCallback, opts ...api.Option) (api.Int64Observer, error) { | ||||
| 	if callback == nil { | ||||
| 		return api.NoopMeter{}.RegisterInt64Observer("", nil) | ||||
| 	} | ||||
| 	descriptor := newDescriptor(name, export.ObserverKind, core.Int64NumberKind, opts) | ||||
| 	cb := wrapInt64ObserverCallback(callback) | ||||
| 	obs := m.newObserver(descriptor, cb) | ||||
| 	return int64Observer{ | ||||
| 		observer: obs, | ||||
| func (m *SDK) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl, error) { | ||||
| 	return &syncInstrument{ | ||||
| 		instrument: instrument{ | ||||
| 			descriptor: descriptor, | ||||
| 			meter:      m, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func wrapInt64ObserverCallback(callback api.Int64ObserverCallback) observerCallback { | ||||
| 	return func(result observerResult) { | ||||
| 		typeSafeResult := int64ObserverResult{ | ||||
| 			result: result, | ||||
| 		} | ||||
| 		callback(typeSafeResult) | ||||
| func (m *SDK) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(core.Number, api.LabelSet))) (api.AsyncImpl, error) { | ||||
| 	a := &asyncInstrument{ | ||||
| 		instrument: instrument{ | ||||
| 			descriptor: descriptor, | ||||
| 			meter:      m, | ||||
| 		}, | ||||
| 		callback: callback, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *SDK) RegisterFloat64Observer(name string, callback api.Float64ObserverCallback, opts ...api.Option) (api.Float64Observer, error) { | ||||
| 	if callback == nil { | ||||
| 		return api.NoopMeter{}.RegisterFloat64Observer("", nil) | ||||
| 	} | ||||
| 	descriptor := newDescriptor(name, export.ObserverKind, core.Float64NumberKind, opts) | ||||
| 	cb := wrapFloat64ObserverCallback(callback) | ||||
| 	obs := m.newObserver(descriptor, cb) | ||||
| 	return float64Observer{ | ||||
| 		observer: obs, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func wrapFloat64ObserverCallback(callback api.Float64ObserverCallback) observerCallback { | ||||
| 	return func(result observerResult) { | ||||
| 		typeSafeResult := float64ObserverResult{ | ||||
| 			result: result, | ||||
| 		} | ||||
| 		callback(typeSafeResult) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *SDK) newObserver(descriptor *export.Descriptor, callback observerCallback) *observer { | ||||
| 	obs := &observer{ | ||||
| 		meter:      m, | ||||
| 		descriptor: descriptor, | ||||
| 		recorders:  nil, | ||||
| 		callback:   callback, | ||||
| 	} | ||||
| 	m.observers.Store(obs, nil) | ||||
| 	return obs | ||||
| 	m.asyncInstruments.Store(a, nil) | ||||
| 	return a, nil | ||||
| } | ||||
|  | ||||
| // Collect traverses the list of active records and observers and | ||||
| @@ -570,7 +459,7 @@ func (m *SDK) Collect(ctx context.Context) int { | ||||
| 	defer m.collectLock.Unlock() | ||||
|  | ||||
| 	checkpointed := m.collectRecords(ctx) | ||||
| 	checkpointed += m.collectObservers(ctx) | ||||
| 	checkpointed += m.collectAsync(ctx) | ||||
| 	m.currentEpoch++ | ||||
| 	return checkpointed | ||||
| } | ||||
| @@ -601,16 +490,13 @@ func (m *SDK) collectRecords(ctx context.Context) int { | ||||
| 	return checkpointed | ||||
| } | ||||
|  | ||||
| func (m *SDK) collectObservers(ctx context.Context) int { | ||||
| func (m *SDK) collectAsync(ctx context.Context) int { | ||||
| 	checkpointed := 0 | ||||
|  | ||||
| 	m.observers.Range(func(key, value interface{}) bool { | ||||
| 		obs := key.(*observer) | ||||
| 		result := observerResult{ | ||||
| 			observer: obs, | ||||
| 		} | ||||
| 		obs.callback(result) | ||||
| 		checkpointed += m.checkpointObserver(ctx, obs) | ||||
| 	m.asyncInstruments.Range(func(key, value interface{}) bool { | ||||
| 		a := key.(*asyncInstrument) | ||||
| 		a.callback(a.observe) | ||||
| 		checkpointed += m.checkpointAsync(ctx, a) | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| @@ -618,32 +504,32 @@ func (m *SDK) collectObservers(ctx context.Context) int { | ||||
| } | ||||
|  | ||||
| func (m *SDK) checkpointRecord(ctx context.Context, r *record) int { | ||||
| 	return m.checkpoint(ctx, r.descriptor, r.recorder, r.labels) | ||||
| 	return m.checkpoint(ctx, &r.inst.descriptor, r.recorder, r.labels) | ||||
| } | ||||
|  | ||||
| func (m *SDK) checkpointObserver(ctx context.Context, obs *observer) int { | ||||
| 	if len(obs.recorders) == 0 { | ||||
| func (m *SDK) checkpointAsync(ctx context.Context, a *asyncInstrument) int { | ||||
| 	if len(a.recorders) == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	checkpointed := 0 | ||||
| 	for encodedLabels, lrec := range obs.recorders { | ||||
| 	for encodedLabels, lrec := range a.recorders { | ||||
| 		epochDiff := m.currentEpoch - lrec.modifiedEpoch | ||||
| 		if epochDiff == 0 { | ||||
| 			checkpointed += m.checkpoint(ctx, obs.descriptor, lrec.recorder, lrec.labels) | ||||
| 			checkpointed += m.checkpoint(ctx, &a.descriptor, lrec.recorder, lrec.labels) | ||||
| 		} else if epochDiff > 1 { | ||||
| 			// This is second collection cycle with no | ||||
| 			// observations for this labelset. Remove the | ||||
| 			// recorder. | ||||
| 			delete(obs.recorders, encodedLabels) | ||||
| 			delete(a.recorders, encodedLabels) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(obs.recorders) == 0 { | ||||
| 		obs.recorders = nil | ||||
| 	if len(a.recorders) == 0 { | ||||
| 		a.recorders = nil | ||||
| 	} | ||||
| 	return checkpointed | ||||
| } | ||||
|  | ||||
| func (m *SDK) checkpoint(ctx context.Context, descriptor *export.Descriptor, recorder export.Aggregator, labels *labels) int { | ||||
| func (m *SDK) checkpoint(ctx context.Context, descriptor *metric.Descriptor, recorder export.Aggregator, labels *labels) int { | ||||
| 	if recorder == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| @@ -665,15 +551,16 @@ func (m *SDK) checkpoint(ctx context.Context, descriptor *export.Descriptor, rec | ||||
| // RecordBatch enters a batch of metric events. | ||||
| func (m *SDK) RecordBatch(ctx context.Context, ls api.LabelSet, measurements ...api.Measurement) { | ||||
| 	for _, meas := range measurements { | ||||
| 		meas.InstrumentImpl().RecordOne(ctx, meas.Number(), ls) | ||||
| 		meas.SyncImpl().RecordOne(ctx, meas.Number(), ls) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetDescriptor returns the descriptor of an instrument, which is not | ||||
| // part of the public metric API. | ||||
| func (m *SDK) GetDescriptor(inst metric.InstrumentImpl) *export.Descriptor { | ||||
| 	if ii, ok := inst.(*instrument); ok { | ||||
| 		return ii.descriptor | ||||
| // GetDescriptor returns a pointer to the descriptor of an instrument, | ||||
| // which is not part of the public metric API.  This is for testing.  Use | ||||
| // SyncImpl().Descriptor() to get a copy of the descriptor. | ||||
| func (m *SDK) GetDescriptor(inst api.SyncImpl) *metric.Descriptor { | ||||
| 	if ii, ok := inst.(*syncInstrument); ok { | ||||
| 		return &ii.descriptor | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -683,11 +570,11 @@ func (r *record) RecordOne(ctx context.Context, number core.Number) { | ||||
| 		// The instrument is disabled according to the AggregationSelector. | ||||
| 		return | ||||
| 	} | ||||
| 	if err := aggregator.RangeTest(number, r.descriptor); err != nil { | ||||
| 	if err := aggregator.RangeTest(number, &r.inst.descriptor); err != nil { | ||||
| 		r.labels.meter.errorHandler(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err := r.recorder.Update(ctx, number, r.descriptor); err != nil { | ||||
| 	if err := r.recorder.Update(ctx, number, &r.inst.descriptor); err != nil { | ||||
| 		r.labels.meter.errorHandler(err) | ||||
| 		return | ||||
| 	} | ||||
| @@ -703,7 +590,7 @@ func (r *record) Unbind() { | ||||
|  | ||||
| func (r *record) mapkey() mapkey { | ||||
| 	return mapkey{ | ||||
| 		descriptor: r.descriptor, | ||||
| 		descriptor: &r.inst.descriptor, | ||||
| 		ordered:    r.labels.ordered, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| package simple // import "go.opentelemetry.io/otel/sdk/metric/selector/simple" | ||||
|  | ||||
| import ( | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/array" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/ddsketch" | ||||
| @@ -65,33 +66,33 @@ func NewWithExactMeasure() export.AggregationSelector { | ||||
| 	return selectorExact{} | ||||
| } | ||||
|  | ||||
| func (selectorInexpensive) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	switch descriptor.MetricKind() { | ||||
| 	case export.ObserverKind: | ||||
| 	case metric.ObserverKind: | ||||
| 		fallthrough | ||||
| 	case export.MeasureKind: | ||||
| 	case metric.MeasureKind: | ||||
| 		return minmaxsumcount.New(descriptor) | ||||
| 	default: | ||||
| 		return sum.New() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s selectorSketch) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	switch descriptor.MetricKind() { | ||||
| 	case export.ObserverKind: | ||||
| 	case metric.ObserverKind: | ||||
| 		fallthrough | ||||
| 	case export.MeasureKind: | ||||
| 	case metric.MeasureKind: | ||||
| 		return ddsketch.New(s.config, descriptor) | ||||
| 	default: | ||||
| 		return sum.New() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (selectorExact) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	switch descriptor.MetricKind() { | ||||
| 	case export.ObserverKind: | ||||
| 	case metric.ObserverKind: | ||||
| 		fallthrough | ||||
| 	case export.MeasureKind: | ||||
| 	case metric.MeasureKind: | ||||
| 		return array.New() | ||||
| 	default: | ||||
| 		return sum.New() | ||||
|   | ||||
| @@ -20,7 +20,7 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/api/core" | ||||
| 	export "go.opentelemetry.io/otel/sdk/export/metric" | ||||
| 	"go.opentelemetry.io/otel/api/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/array" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/ddsketch" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" | ||||
| @@ -29,28 +29,28 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	testCounterDesc  = export.NewDescriptor("counter", export.CounterKind, nil, "", "", core.Int64NumberKind) | ||||
| 	testMeasureDesc  = export.NewDescriptor("measure", export.MeasureKind, nil, "", "", core.Int64NumberKind) | ||||
| 	testObserverDesc = export.NewDescriptor("observer", export.ObserverKind, nil, "", "", core.Int64NumberKind) | ||||
| 	testCounterDesc  = metric.NewDescriptor("counter", metric.CounterKind, core.Int64NumberKind) | ||||
| 	testMeasureDesc  = metric.NewDescriptor("measure", metric.MeasureKind, core.Int64NumberKind) | ||||
| 	testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, core.Int64NumberKind) | ||||
| ) | ||||
|  | ||||
| func TestInexpensiveMeasure(t *testing.T) { | ||||
| 	inex := simple.NewWithInexpensiveMeasure() | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(testMeasureDesc).(*minmaxsumcount.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(testObserverDesc).(*minmaxsumcount.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(&testMeasureDesc).(*minmaxsumcount.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = inex.AggregatorFor(&testObserverDesc).(*minmaxsumcount.Aggregator) }) | ||||
| } | ||||
|  | ||||
| func TestSketchMeasure(t *testing.T) { | ||||
| 	sk := simple.NewWithSketchMeasure(ddsketch.NewDefaultConfig()) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(testMeasureDesc).(*ddsketch.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(testObserverDesc).(*ddsketch.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(&testMeasureDesc).(*ddsketch.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = sk.AggregatorFor(&testObserverDesc).(*ddsketch.Aggregator) }) | ||||
| } | ||||
|  | ||||
| func TestExactMeasure(t *testing.T) { | ||||
| 	ex := simple.NewWithExactMeasure() | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(testMeasureDesc).(*array.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(testObserverDesc).(*array.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(&testMeasureDesc).(*array.Aggregator) }) | ||||
| 	require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*array.Aggregator) }) | ||||
| } | ||||
|   | ||||
| @@ -68,11 +68,11 @@ type ( | ||||
|  | ||||
| 	testKey struct { | ||||
| 		labels     string | ||||
| 		descriptor *export.Descriptor | ||||
| 		descriptor *metric.Descriptor | ||||
| 	} | ||||
|  | ||||
| 	testImpl struct { | ||||
| 		newInstrument  func(meter api.Meter, name string) withImpl | ||||
| 		newInstrument  func(meter api.Meter, name string) SyncImpler | ||||
| 		getUpdateValue func() core.Number | ||||
| 		operate        func(interface{}, context.Context, core.Number, api.LabelSet) | ||||
| 		newStore       func() interface{} | ||||
| @@ -86,8 +86,8 @@ type ( | ||||
| 		equalValues  func(a, b core.Number) bool | ||||
| 	} | ||||
|  | ||||
| 	withImpl interface { | ||||
| 		Impl() metric.InstrumentImpl | ||||
| 	SyncImpler interface { | ||||
| 		SyncImpl() metric.SyncImpl | ||||
| 	} | ||||
|  | ||||
| 	// lastValueState supports merging lastValue values, for the case | ||||
| @@ -156,14 +156,14 @@ func (f *testFixture) someLabels() []core.KeyValue { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (f *testFixture) startWorker(sdk *sdk.SDK, wg *sync.WaitGroup, i int) { | ||||
| func (f *testFixture) startWorker(impl *sdk.SDK, meter api.Meter, wg *sync.WaitGroup, i int) { | ||||
| 	ctx := context.Background() | ||||
| 	name := fmt.Sprint("test_", i) | ||||
| 	instrument := f.impl.newInstrument(sdk, name) | ||||
| 	descriptor := sdk.GetDescriptor(instrument.Impl()) | ||||
| 	instrument := f.impl.newInstrument(meter, name) | ||||
| 	descriptor := impl.GetDescriptor(instrument.SyncImpl()) | ||||
| 	kvs := f.someLabels() | ||||
| 	clabs := canonicalizeLabels(kvs) | ||||
| 	labs := sdk.Labels(kvs...) | ||||
| 	labs := meter.Labels(kvs...) | ||||
| 	dur := getPeriod() | ||||
| 	key := testKey{ | ||||
| 		labels:     clabs, | ||||
| @@ -230,7 +230,7 @@ func (f *testFixture) preCollect() { | ||||
| 	f.dupCheck = map[testKey]int{} | ||||
| } | ||||
|  | ||||
| func (*testFixture) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { | ||||
| func (*testFixture) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { | ||||
| 	name := descriptor.Name() | ||||
| 	switch { | ||||
| 	case strings.HasSuffix(name, "counter"): | ||||
| @@ -264,13 +264,13 @@ func (f *testFixture) Process(_ context.Context, record export.Record) error { | ||||
|  | ||||
| 	agg := record.Aggregator() | ||||
| 	switch record.Descriptor().MetricKind() { | ||||
| 	case export.CounterKind: | ||||
| 	case metric.CounterKind: | ||||
| 		sum, err := agg.(aggregator.Sum).Sum() | ||||
| 		if err != nil { | ||||
| 			f.T.Fatal("Sum error: ", err) | ||||
| 		} | ||||
| 		f.impl.storeCollect(actual, sum, time.Time{}) | ||||
| 	case export.MeasureKind: | ||||
| 	case metric.MeasureKind: | ||||
| 		lv, ts, err := agg.(aggregator.LastValue).LastValue() | ||||
| 		if err != nil && err != aggregator.ErrNoData { | ||||
| 			f.T.Fatal("Last value error: ", err) | ||||
| @@ -292,10 +292,11 @@ func stressTest(t *testing.T, impl testImpl) { | ||||
| 	} | ||||
| 	cc := concurrency() | ||||
| 	sdk := sdk.New(fixture, sdk.NewDefaultLabelEncoder()) | ||||
| 	meter := metric.WrapMeterImpl(sdk) | ||||
| 	fixture.wg.Add(cc + 1) | ||||
|  | ||||
| 	for i := 0; i < cc; i++ { | ||||
| 		go fixture.startWorker(sdk, &fixture.wg, i) | ||||
| 		go fixture.startWorker(sdk, meter, &fixture.wg, i) | ||||
| 	} | ||||
|  | ||||
| 	numCollect := 0 | ||||
| @@ -336,7 +337,7 @@ func float64sEqual(a, b core.Number) bool { | ||||
|  | ||||
| func intCounterTestImpl() testImpl { | ||||
| 	return testImpl{ | ||||
| 		newInstrument: func(meter api.Meter, name string) withImpl { | ||||
| 		newInstrument: func(meter api.Meter, name string) SyncImpler { | ||||
| 			return Must(meter).NewInt64Counter(name + ".counter") | ||||
| 		}, | ||||
| 		getUpdateValue: func() core.Number { | ||||
| @@ -374,7 +375,7 @@ func TestStressInt64Counter(t *testing.T) { | ||||
|  | ||||
| func floatCounterTestImpl() testImpl { | ||||
| 	return testImpl{ | ||||
| 		newInstrument: func(meter api.Meter, name string) withImpl { | ||||
| 		newInstrument: func(meter api.Meter, name string) SyncImpler { | ||||
| 			return Must(meter).NewFloat64Counter(name + ".counter") | ||||
| 		}, | ||||
| 		getUpdateValue: func() core.Number { | ||||
| @@ -414,7 +415,7 @@ func TestStressFloat64Counter(t *testing.T) { | ||||
|  | ||||
| func intLastValueTestImpl() testImpl { | ||||
| 	return testImpl{ | ||||
| 		newInstrument: func(meter api.Meter, name string) withImpl { | ||||
| 		newInstrument: func(meter api.Meter, name string) SyncImpler { | ||||
| 			return Must(meter).NewInt64Measure(name + ".lastvalue") | ||||
| 		}, | ||||
| 		getUpdateValue: func() core.Number { | ||||
| @@ -456,7 +457,7 @@ func TestStressInt64LastValue(t *testing.T) { | ||||
|  | ||||
| func floatLastValueTestImpl() testImpl { | ||||
| 	return testImpl{ | ||||
| 		newInstrument: func(meter api.Meter, name string) withImpl { | ||||
| 		newInstrument: func(meter api.Meter, name string) SyncImpler { | ||||
| 			return Must(meter).NewFloat64Measure(name + ".lastvalue") | ||||
| 		}, | ||||
| 		getUpdateValue: func() core.Number { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user