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