From 0abb30103ff8f5736e27488a6ed0a0bbe8be73a4 Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 18 Dec 2019 15:59:13 -0800 Subject: [PATCH 01/13] Initial skeleton --- api/global/global.go | 32 ++------- api/global/internal/meter.go | 136 +++++++++++++++++++++++++++++++++++ api/global/internal/state.go | 60 ++++++++++++++++ api/metric/noop.go | 6 -- 4 files changed, 201 insertions(+), 33 deletions(-) create mode 100644 api/global/internal/meter.go create mode 100644 api/global/internal/state.go diff --git a/api/global/global.go b/api/global/global.go index af7f8ac8c12..0700e8bfed1 100644 --- a/api/global/global.go +++ b/api/global/global.go @@ -15,41 +15,22 @@ package global import ( - "sync/atomic" - + "go.opentelemetry.io/otel/api/global/internal" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/trace" ) -type ( - traceProvider struct { - tp trace.Provider - } - - meterProvider struct { - mp metric.Provider - } -) - -var ( - globalTracer atomic.Value - globalMeter atomic.Value -) - // TraceProvider returns the registered global trace provider. // If none is registered then an instance of trace.NoopProvider is returned. // Use the trace provider to create a named tracer. E.g. // tracer := global.TraceProvider().Tracer("example.com/foo") func TraceProvider() trace.Provider { - if gp := globalTracer.Load(); gp != nil { - return gp.(traceProvider).tp - } - return trace.NoopProvider{} + return internal.TraceProvider() } // SetTraceProvider registers `tp` as the global trace provider. func SetTraceProvider(tp trace.Provider) { - globalTracer.Store(traceProvider{tp: tp}) + internal.SetTraceProvider(tp) } // MeterProvider returns the registered global meter provider. @@ -57,13 +38,10 @@ func SetTraceProvider(tp trace.Provider) { // Use the trace provider to create a named meter. E.g. // meter := global.MeterProvider().Meter("example.com/foo") func MeterProvider() metric.Provider { - if gp := globalMeter.Load(); gp != nil { - return gp.(meterProvider).mp - } - return metric.NoopProvider{} + return internal.MeterProvider() } // SetMeterProvider registers `mp` as the global meter provider. func SetMeterProvider(mp metric.Provider) { - globalMeter.Store(meterProvider{mp: mp}) + internal.SetMeterProvider(mp) } diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go new file mode 100644 index 00000000000..aefb7efe8ce --- /dev/null +++ b/api/global/internal/meter.go @@ -0,0 +1,136 @@ +package internal + +import ( + "context" + + "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/metric" +) + +type meterProvider struct { + delegate metric.Provider +} + +type meter struct { + provider *meterProvider + name string + + delegate metric.Meter +} + +type labelSet struct { + meter *meter + labels []core.KeyValue + + delegate metric.LabelSet +} + +type instImpl struct { + meter *meter + name string + opts interface{} + + delegate metric.InstrumentImpl +} + +type instHandle struct { + inst *instImpl + labels metric.LabelSet + + delegate metric.HandleImpl +} + +var _ metric.Provider = &meterProvider{} +var _ metric.Meter = &meter{} +var _ metric.LabelSet = &labelSet{} +var _ metric.InstrumentImpl = &instImpl{} +var _ metric.HandleImpl = &instHandle{} + +func (p *meterProvider) delegateTo(provider metric.Provider) { + // HERE YOU ARE @@@ +} + +func (p *meterProvider) Meter(name string) metric.Meter { + return &meter{ + provider: p, + name: name, + } +} + +func (m *meter) Labels(labels ...core.KeyValue) metric.LabelSet { + return &labelSet{ + meter: m, + labels: labels, + } +} + +func (m *meter) NewInt64Counter(name string, opts ...metric.CounterOptionApplier) metric.Int64Counter { + return metric.WrapInt64CounterInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (m *meter) NewFloat64Counter(name string, opts ...metric.CounterOptionApplier) metric.Float64Counter { + return metric.WrapFloat64CounterInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (m *meter) NewInt64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Int64Gauge { + return metric.WrapInt64GaugeInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (m *meter) NewFloat64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Float64Gauge { + return metric.WrapFloat64GaugeInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (m *meter) NewInt64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Int64Measure { + return metric.WrapInt64MeasureInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (m *meter) NewFloat64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Float64Measure { + return metric.WrapFloat64MeasureInstrument(&instImpl{ + meter: m, + name: name, + opts: opts, + }) +} + +func (inst *instImpl) AcquireHandle(labels metric.LabelSet) metric.HandleImpl { + return &instHandle{ + inst: inst, + labels: labels, + } +} + +func (b *instHandle) Release() { + +} + +func (*meter) RecordBatch(context.Context, metric.LabelSet, ...metric.Measurement) { + // This is a no-op +} + +func (*instImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { + // This is a no-op +} + +func (*instHandle) RecordOne(ctx context.Context, number core.Number) { + // This is a no-op +} diff --git a/api/global/internal/state.go b/api/global/internal/state.go new file mode 100644 index 00000000000..f841639cfb4 --- /dev/null +++ b/api/global/internal/state.go @@ -0,0 +1,60 @@ +package internal + +import ( + "sync" + "sync/atomic" + + "go.opentelemetry.io/otel/api/metric" + "go.opentelemetry.io/otel/api/trace" +) + +type ( + traceProviderHolder struct { + tp trace.Provider + } + + meterProviderHolder struct { + mp metric.Provider + } +) + +var ( + globalTracer = defaultTracerValue() + globalMeter = defaultMeterValue() + + delegateMeterOnce sync.Once +) + +func TraceProvider() trace.Provider { + return globalTracer.Load().(traceProviderHolder).tp +} + +func SetTraceProvider(tp trace.Provider) { + globalTracer.Store(traceProviderHolder{tp: tp}) +} + +func MeterProvider() metric.Provider { + return globalMeter.Load().(meterProviderHolder).mp +} + +func SetMeterProvider(mp metric.Provider) { + delegateMeterOnce.Do(func() { + current := MeterProvider() + if def, ok := current.(*meterProvider); ok { + def.delegateTo(mp) + } + }) + globalMeter.Store(meterProviderHolder{mp: mp}) +} + +func defaultTracerValue() *atomic.Value { + v := &atomic.Value{} + v.Store(traceProviderHolder{tp: trace.NoopProvider{}}) + return v +} + +func defaultMeterValue() *atomic.Value { + v := &atomic.Value{} + v.Store(meterProviderHolder{mp: &meterProvider{}}) + return v +} diff --git a/api/metric/noop.go b/api/metric/noop.go index 770837bb390..4087f904f23 100644 --- a/api/metric/noop.go +++ b/api/metric/noop.go @@ -6,22 +6,16 @@ import ( "go.opentelemetry.io/otel/api/core" ) -type NoopProvider struct{} type NoopMeter struct{} type noopHandle struct{} type noopLabelSet struct{} type noopInstrument struct{} -var _ Provider = NoopProvider{} var _ Meter = NoopMeter{} var _ InstrumentImpl = noopInstrument{} var _ HandleImpl = noopHandle{} var _ LabelSet = noopLabelSet{} -func (NoopProvider) Meter(name string) Meter { - return NoopMeter{} -} - func (noopHandle) RecordOne(context.Context, core.Number) { } From ad319fdca04288dc17889d5ef9d7aa74a86eb92d Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 18 Dec 2019 20:19:36 -0800 Subject: [PATCH 02/13] Revert noop provider removal --- api/metric/noop.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/metric/noop.go b/api/metric/noop.go index 4087f904f23..770837bb390 100644 --- a/api/metric/noop.go +++ b/api/metric/noop.go @@ -6,16 +6,22 @@ import ( "go.opentelemetry.io/otel/api/core" ) +type NoopProvider struct{} type NoopMeter struct{} type noopHandle struct{} type noopLabelSet struct{} type noopInstrument struct{} +var _ Provider = NoopProvider{} var _ Meter = NoopMeter{} var _ InstrumentImpl = noopInstrument{} var _ HandleImpl = noopHandle{} var _ LabelSet = noopLabelSet{} +func (NoopProvider) Meter(name string) Meter { + return NoopMeter{} +} + func (noopHandle) RecordOne(context.Context, core.Number) { } From f5c423165bec98835608389e78af94dfd1c08108 Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 00:55:43 -0800 Subject: [PATCH 03/13] Checkpoint --- api/global/internal/meter.go | 196 +++++++++++++++++++++++++---------- api/global/internal/state.go | 9 +- 2 files changed, 150 insertions(+), 55 deletions(-) diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index aefb7efe8ce..415f82561ea 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -2,12 +2,25 @@ package internal import ( "context" + "sync" + "sync/atomic" + "unsafe" "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" ) +type metricKind int8 + +const ( + counterKind metricKind = iota + gaugeKind + measureKind +) + type meterProvider struct { + lock sync.Mutex + meters []*meter delegate metric.Provider } @@ -15,7 +28,9 @@ type meter struct { provider *meterProvider name string - delegate metric.Meter + lock sync.Mutex + instruments []*instImpl + delegate unsafe.Pointer // (*metric.Meter) } type labelSet struct { @@ -28,16 +43,18 @@ type labelSet struct { type instImpl struct { meter *meter name string + mkind metricKind + nkind core.NumberKind opts interface{} - delegate metric.InstrumentImpl + delegate unsafe.Pointer // (*metric.InstrumentImpl) } type instHandle struct { inst *instImpl labels metric.LabelSet - delegate metric.HandleImpl + delegate unsafe.Pointer // (*metric.HandleImpl) } var _ metric.Provider = &meterProvider{} @@ -46,91 +63,164 @@ var _ metric.LabelSet = &labelSet{} var _ metric.InstrumentImpl = &instImpl{} var _ metric.HandleImpl = &instHandle{} -func (p *meterProvider) delegateTo(provider metric.Provider) { - // HERE YOU ARE @@@ +// Provider interface and delegation + +func (p *meterProvider) setDelegate(provider metric.Provider) { + p.lock.Lock() + defer p.lock.Unlock() + + p.delegate = provider + for _, m := range p.meters { + m.setDelegate(provider) + } + p.meters = nil } func (p *meterProvider) Meter(name string) metric.Meter { - return &meter{ + p.lock.Lock() + defer p.lock.Unlock() + + if p.delegate != nil { + return p.delegate.Meter(name) + } + + m := &meter{ provider: p, name: name, } + p.meters = append(p.meters, m) + return m } -func (m *meter) Labels(labels ...core.KeyValue) metric.LabelSet { - return &labelSet{ - meter: m, - labels: labels, +// Meter interface and delegation + +func (m *meter) setDelegate(provider metric.Provider) { + m.lock.Lock() + defer m.lock.Unlock() + + d := new(metric.Meter) + *d = provider.Meter(m.name) + m.delegate = unsafe.Pointer(d) + + for _, inst := range m.instruments { + inst.setDelegate(*d) } + m.instruments = nil } -func (m *meter) NewInt64Counter(name string, opts ...metric.CounterOptionApplier) metric.Int64Counter { - return metric.WrapInt64CounterInstrument(&instImpl{ - meter: m, - name: name, - opts: opts, - }) -} +func (m *meter) newInst(name string, mkind metricKind, nkind core.NumberKind, opts interface{}) metric.InstrumentImpl { + m.lock.Lock() + defer m.lock.Unlock() -func (m *meter) NewFloat64Counter(name string, opts ...metric.CounterOptionApplier) metric.Float64Counter { - return metric.WrapFloat64CounterInstrument(&instImpl{ - meter: m, - name: name, - opts: opts, - }) -} + if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return newInstDelegate(*meterPtr, name, mkind, nkind, opts) + } -func (m *meter) NewInt64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Int64Gauge { - return metric.WrapInt64GaugeInstrument(&instImpl{ + inst := &instImpl{ meter: m, name: name, + mkind: mkind, + nkind: nkind, opts: opts, - }) + } + m.instruments = append(m.instruments, inst) + return inst +} + +func newInstDelegate(m metric.Meter, name string, mkind metricKind, nkind core.NumberKind, opts interface{}) metric.InstrumentImpl { + switch mkind { + case counterKind: + if nkind == core.Int64NumberKind { + return m.NewInt64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() + } else { + return m.NewFloat64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() + } + case gaugeKind: + if nkind == core.Int64NumberKind { + return m.NewInt64Gauge(name, opts.([]metric.GaugeOptionApplier)...).Impl() + } else { + return m.NewFloat64Gauge(name, opts.([]metric.GaugeOptionApplier)...).Impl() + } + case measureKind: + if nkind == core.Int64NumberKind { + return m.NewInt64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() + } else { + return m.NewFloat64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() + } + } + return nil } -func (m *meter) NewFloat64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Float64Gauge { - return metric.WrapFloat64GaugeInstrument(&instImpl{ - meter: m, - name: name, - opts: opts, - }) -} +// Instrument delegation -func (m *meter) NewInt64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Int64Measure { - return metric.WrapInt64MeasureInstrument(&instImpl{ - meter: m, - name: name, - opts: opts, - }) -} +func (inst *instImpl) setDelegate(d metric.Meter) { + impl := new(metric.InstrumentImpl) -func (m *meter) NewFloat64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Float64Measure { - return metric.WrapFloat64MeasureInstrument(&instImpl{ - meter: m, - name: name, - opts: opts, - }) + *impl = newInstDelegate(d, inst.name, inst.mkind, inst.nkind, inst.opts) + + atomic.StorePointer(&inst.delegate, unsafe.Pointer(impl)) } func (inst *instImpl) AcquireHandle(labels metric.LabelSet) metric.HandleImpl { + if implPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { + return (*implPtr).AcquireHandle(labels) + } + return &instHandle{ inst: inst, labels: labels, } } -func (b *instHandle) Release() { - +func (bound *instHandle) Release() { + // TODO } -func (*meter) RecordBatch(context.Context, metric.LabelSet, ...metric.Measurement) { - // This is a no-op +// Metric updates + +func (*meter) RecordBatch(ctx context.Context, labels metric.LabelSet, measurements ...metric.Measurement) { + // TODO make m.delegate an unsafe.Pointer } func (*instImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { - // This is a no-op + // TODO } func (*instHandle) RecordOne(ctx context.Context, number core.Number) { - // This is a no-op + // TODO +} + +// Constructors + +func (m *meter) NewInt64Counter(name string, opts ...metric.CounterOptionApplier) metric.Int64Counter { + return metric.WrapInt64CounterInstrument(m.newInst(name, counterKind, core.Int64NumberKind, opts)) +} + +func (m *meter) NewFloat64Counter(name string, opts ...metric.CounterOptionApplier) metric.Float64Counter { + return metric.WrapFloat64CounterInstrument(m.newInst(name, counterKind, core.Float64NumberKind, opts)) +} + +func (m *meter) NewInt64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Int64Gauge { + return metric.WrapInt64GaugeInstrument(m.newInst(name, gaugeKind, core.Int64NumberKind, opts)) +} + +func (m *meter) NewFloat64Gauge(name string, opts ...metric.GaugeOptionApplier) metric.Float64Gauge { + return metric.WrapFloat64GaugeInstrument(m.newInst(name, gaugeKind, core.Float64NumberKind, opts)) +} + +func (m *meter) NewInt64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Int64Measure { + return metric.WrapInt64MeasureInstrument(m.newInst(name, measureKind, core.Int64NumberKind, opts)) +} + +func (m *meter) NewFloat64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Float64Measure { + return metric.WrapFloat64MeasureInstrument(m.newInst(name, measureKind, core.Float64NumberKind, opts)) +} + +// TODO + +func (m *meter) Labels(labels ...core.KeyValue) metric.LabelSet { + return &labelSet{ + meter: m, + labels: labels, + } } diff --git a/api/global/internal/state.go b/api/global/internal/state.go index f841639cfb4..ca8c4a321da 100644 --- a/api/global/internal/state.go +++ b/api/global/internal/state.go @@ -40,8 +40,13 @@ func MeterProvider() metric.Provider { func SetMeterProvider(mp metric.Provider) { delegateMeterOnce.Do(func() { current := MeterProvider() - if def, ok := current.(*meterProvider); ok { - def.delegateTo(mp) + + if current == mp { + // Setting the provider to the prior default + // is nonsense, set it to a noop. + mp = metric.NoopProvider{} + } else if def, ok := current.(*meterProvider); ok { + def.setDelegate(mp) } }) globalMeter.Store(meterProviderHolder{mp: mp}) From d9228873aeb21e64f3c3d90566086732bf0c9e63 Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 01:09:52 -0800 Subject: [PATCH 04/13] Checkpoint --- api/global/internal/meter.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index 415f82561ea..d8a352891b6 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -178,12 +178,16 @@ func (bound *instHandle) Release() { // Metric updates -func (*meter) RecordBatch(ctx context.Context, labels metric.LabelSet, measurements ...metric.Measurement) { - // TODO make m.delegate an unsafe.Pointer +func (m *meter) RecordBatch(ctx context.Context, labels metric.LabelSet, measurements ...metric.Measurement) { + if delegatePtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { + (*delegatePtr).RecordBatch(ctx, labels, measurements...) + } } -func (*instImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { - // TODO +func (inst *instImpl) RecordOne(ctx context.Context, number core.Number, labels metric.LabelSet) { + if instPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { + (*instPtr).RecordOne(ctx, number, labels) + } } func (*instHandle) RecordOne(ctx context.Context, number core.Number) { From e6e77d34ddf320edb1662d6b524e21f9e6c1c11a Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 14:19:18 -0800 Subject: [PATCH 05/13] Implement Bound instrument and LabelSet --- api/global/internal/meter.go | 96 ++++++++++++++++++++++++++---------- api/metric/api.go | 4 ++ 2 files changed, 75 insertions(+), 25 deletions(-) diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index d8a352891b6..097a681bb9a 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -30,18 +30,11 @@ type meter struct { lock sync.Mutex instruments []*instImpl - delegate unsafe.Pointer // (*metric.Meter) -} - -type labelSet struct { - meter *meter - labels []core.KeyValue - delegate metric.LabelSet + delegate unsafe.Pointer // (*metric.Meter) } type instImpl struct { - meter *meter name string mkind metricKind nkind core.NumberKind @@ -50,16 +43,26 @@ type instImpl struct { delegate unsafe.Pointer // (*metric.InstrumentImpl) } +type labelSet struct { + meter *meter + value []core.KeyValue + + initialize sync.Once + delegate unsafe.Pointer // (* metric.LabelSet) +} + type instHandle struct { inst *instImpl labels metric.LabelSet - delegate unsafe.Pointer // (*metric.HandleImpl) + initialize sync.Once + delegate unsafe.Pointer // (*metric.HandleImpl) } var _ metric.Provider = &meterProvider{} var _ metric.Meter = &meter{} var _ metric.LabelSet = &labelSet{} +var _ metric.LabelSetDelegate = &labelSet{} var _ metric.InstrumentImpl = &instImpl{} var _ metric.HandleImpl = &instHandle{} @@ -117,7 +120,6 @@ func (m *meter) newInst(name string, mkind metricKind, nkind core.NumberKind, op } inst := &instImpl{ - meter: m, name: name, mkind: mkind, nkind: nkind, @@ -154,11 +156,11 @@ func newInstDelegate(m metric.Meter, name string, mkind metricKind, nkind core.N // Instrument delegation func (inst *instImpl) setDelegate(d metric.Meter) { - impl := new(metric.InstrumentImpl) + implPtr := new(metric.InstrumentImpl) - *impl = newInstDelegate(d, inst.name, inst.mkind, inst.nkind, inst.opts) + *implPtr = newInstDelegate(d, inst.name, inst.mkind, inst.nkind, inst.opts) - atomic.StorePointer(&inst.delegate, unsafe.Pointer(impl)) + atomic.StorePointer(&inst.delegate, unsafe.Pointer(implPtr)) } func (inst *instImpl) AcquireHandle(labels metric.LabelSet) metric.HandleImpl { @@ -173,7 +175,15 @@ func (inst *instImpl) AcquireHandle(labels metric.LabelSet) metric.HandleImpl { } func (bound *instHandle) Release() { - // TODO + bound.initialize.Do(func() {}) + + implPtr := (*metric.HandleImpl)(atomic.LoadPointer(&bound.delegate)) + + if implPtr == nil { + return + } + + (*implPtr).Release() } // Metric updates @@ -190,8 +200,53 @@ func (inst *instImpl) RecordOne(ctx context.Context, number core.Number, labels } } -func (*instHandle) RecordOne(ctx context.Context, number core.Number) { - // TODO +// Bound instrument initialization + +func (bound *instHandle) RecordOne(ctx context.Context, number core.Number) { + instPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&bound.inst.delegate)) + if instPtr == nil { + return + } + var implPtr *metric.HandleImpl + bound.initialize.Do(func() { + implPtr = new(metric.HandleImpl) + *implPtr = (*instPtr).AcquireHandle(bound.labels) + atomic.StorePointer(&bound.delegate, unsafe.Pointer(implPtr)) + }) + if implPtr == nil { + implPtr = (*metric.HandleImpl)(atomic.LoadPointer(&bound.delegate)) + } + (*implPtr).RecordOne(ctx, number) +} + +// LabelSet initialization + +func (m *meter) Labels(labels ...core.KeyValue) metric.LabelSet { + return &labelSet{ + meter: m, + value: labels, + } +} + +func (labels *labelSet) Delegate() metric.LabelSet { + meterPtr := (*metric.Meter)(atomic.LoadPointer(&labels.meter.delegate)) + if meterPtr == nil { + // This is technically impossible, provided the global + // Meter is updated after the meters and instruments + // have been delegated. TODO Remove this panic before + // merge. + panic("Temporary panic") + } + var implPtr *metric.LabelSet + labels.initialize.Do(func() { + implPtr = new(metric.LabelSet) + *implPtr = (*meterPtr).Labels(labels.value...) + atomic.StorePointer(&labels.delegate, unsafe.Pointer(implPtr)) + }) + if implPtr == nil { + implPtr = (*metric.LabelSet)(atomic.LoadPointer(&labels.delegate)) + } + return (*implPtr) } // Constructors @@ -219,12 +274,3 @@ func (m *meter) NewInt64Measure(name string, opts ...metric.MeasureOptionApplier func (m *meter) NewFloat64Measure(name string, opts ...metric.MeasureOptionApplier) metric.Float64Measure { return metric.WrapFloat64MeasureInstrument(m.newInst(name, measureKind, core.Float64NumberKind, opts)) } - -// TODO - -func (m *meter) Labels(labels ...core.KeyValue) metric.LabelSet { - return &labelSet{ - meter: m, - labels: labels, - } -} diff --git a/api/metric/api.go b/api/metric/api.go index f96bd75d5bc..7db5e467472 100644 --- a/api/metric/api.go +++ b/api/metric/api.go @@ -33,6 +33,10 @@ type Provider interface { type LabelSet interface { } +type LabelSetDelegate interface { + Delegate() LabelSet +} + // Options contains some options for metrics of any kind. type Options struct { // Description is an optional field describing the metric From a219f91670ec090d77050ae01d770f410d05061c Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 14:58:23 -0800 Subject: [PATCH 06/13] Add test --- api/global/internal/meter.go | 7 +- api/global/internal/meter_test.go | 136 ++++++++++++++++++++++++++++++ api/global/internal/state.go | 6 ++ internal/metric/mock.go | 30 +++++++ 4 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 api/global/internal/meter_test.go diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index 097a681bb9a..b1b07b8b6ff 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -167,7 +167,6 @@ func (inst *instImpl) AcquireHandle(labels metric.LabelSet) metric.HandleImpl { if implPtr := (*metric.InstrumentImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { return (*implPtr).AcquireHandle(labels) } - return &instHandle{ inst: inst, labels: labels, @@ -209,6 +208,7 @@ func (bound *instHandle) RecordOne(ctx context.Context, number core.Number) { } var implPtr *metric.HandleImpl bound.initialize.Do(func() { + implPtr = new(metric.HandleImpl) *implPtr = (*instPtr).AcquireHandle(bound.labels) atomic.StorePointer(&bound.delegate, unsafe.Pointer(implPtr)) @@ -233,9 +233,8 @@ func (labels *labelSet) Delegate() metric.LabelSet { if meterPtr == nil { // This is technically impossible, provided the global // Meter is updated after the meters and instruments - // have been delegated. TODO Remove this panic before - // merge. - panic("Temporary panic") + // have been delegated. + return labels } var implPtr *metric.LabelSet labels.initialize.Do(func() { diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go new file mode 100644 index 00000000000..dedc1b8bc16 --- /dev/null +++ b/api/global/internal/meter_test.go @@ -0,0 +1,136 @@ +package internal_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/global" + "go.opentelemetry.io/otel/api/global/internal" + "go.opentelemetry.io/otel/api/key" + metrictest "go.opentelemetry.io/otel/internal/metric" +) + +func TestDirect(t *testing.T) { + internal.ResetForTest() + + ctx := context.Background() + glob := global.MeterProvider().Meter("test") + lvals1 := key.New("A").String("B") + labels1 := glob.Labels(lvals1) + lvals2 := key.New("C").String("D") + labels2 := glob.Labels(lvals2) + + counter := glob.NewInt64Counter("test.counter") + counter.Add(ctx, 1, labels1) + counter.Add(ctx, 1, labels1) + + gauge := glob.NewInt64Gauge("test.gauge") + gauge.Set(ctx, 1, labels2) + gauge.Set(ctx, 2, labels2) + + measure := glob.NewFloat64Measure("test.measure") + measure.Record(ctx, 1, labels1) + measure.Record(ctx, 2, labels1) + + sdk := metrictest.NewProvider() + global.SetMeterProvider(sdk) + + counter.Add(ctx, 1, labels1) + gauge.Set(ctx, 3, labels2) + measure.Record(ctx, 3, labels1) + + mock := sdk.Meter("test").(*metrictest.Meter) + require.Equal(t, 3, len(mock.MeasurementBatches)) + + require.Equal(t, map[core.Key]core.Value{ + lvals1.Key: lvals1.Value, + }, mock.MeasurementBatches[0].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[0].Measurements)) + require.Equal(t, core.NewInt64Number(1), + mock.MeasurementBatches[0].Measurements[0].Number) + require.Equal(t, "test.counter", + mock.MeasurementBatches[0].Measurements[0].Instrument.Name) + + require.Equal(t, map[core.Key]core.Value{ + lvals2.Key: lvals2.Value, + }, mock.MeasurementBatches[1].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[1].Measurements)) + require.Equal(t, core.NewInt64Number(3), + mock.MeasurementBatches[1].Measurements[0].Number) + require.Equal(t, "test.gauge", + mock.MeasurementBatches[1].Measurements[0].Instrument.Name) + + require.Equal(t, map[core.Key]core.Value{ + lvals1.Key: lvals1.Value, + }, mock.MeasurementBatches[2].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[2].Measurements)) + require.Equal(t, core.NewFloat64Number(3), + mock.MeasurementBatches[2].Measurements[0].Number) + require.Equal(t, "test.measure", + mock.MeasurementBatches[2].Measurements[0].Instrument.Name) +} + +func TestBound(t *testing.T) { + internal.ResetForTest() + + ctx := context.Background() + glob := global.MeterProvider().Meter("test") + lvals1 := key.New("A").String("B") + labels1 := glob.Labels(lvals1) + lvals2 := key.New("C").String("D") + labels2 := glob.Labels(lvals2) + + counter := glob.NewFloat64Counter("test.counter") + boundC := counter.AcquireHandle(labels1) + boundC.Add(ctx, 1) + boundC.Add(ctx, 1) + + gauge := glob.NewFloat64Gauge("test.gauge") + boundG := gauge.AcquireHandle(labels2) + boundG.Set(ctx, 1) + boundG.Set(ctx, 2) + + measure := glob.NewInt64Measure("test.measure") + boundM := measure.AcquireHandle(labels1) + boundM.Record(ctx, 1) + boundM.Record(ctx, 2) + + sdk := metrictest.NewProvider() + global.SetMeterProvider(sdk) + + boundC.Add(ctx, 1) + boundG.Set(ctx, 3) + boundM.Record(ctx, 3) + + mock := sdk.Meter("test").(*metrictest.Meter) + require.Equal(t, 3, len(mock.MeasurementBatches)) + + require.Equal(t, map[core.Key]core.Value{ + lvals1.Key: lvals1.Value, + }, mock.MeasurementBatches[0].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[0].Measurements)) + require.Equal(t, core.NewFloat64Number(1), + mock.MeasurementBatches[0].Measurements[0].Number) + require.Equal(t, "test.counter", + mock.MeasurementBatches[0].Measurements[0].Instrument.Name) + + require.Equal(t, map[core.Key]core.Value{ + lvals2.Key: lvals2.Value, + }, mock.MeasurementBatches[1].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[1].Measurements)) + require.Equal(t, core.NewFloat64Number(3), + mock.MeasurementBatches[1].Measurements[0].Number) + require.Equal(t, "test.gauge", + mock.MeasurementBatches[1].Measurements[0].Instrument.Name) + + require.Equal(t, map[core.Key]core.Value{ + lvals1.Key: lvals1.Value, + }, mock.MeasurementBatches[2].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[2].Measurements)) + require.Equal(t, core.NewInt64Number(3), + mock.MeasurementBatches[2].Measurements[0].Number) + require.Equal(t, "test.measure", + mock.MeasurementBatches[2].Measurements[0].Instrument.Name) +} diff --git a/api/global/internal/state.go b/api/global/internal/state.go index ca8c4a321da..db48af7da06 100644 --- a/api/global/internal/state.go +++ b/api/global/internal/state.go @@ -63,3 +63,9 @@ func defaultMeterValue() *atomic.Value { v.Store(meterProviderHolder{mp: &meterProvider{}}) return v } + +func ResetForTest() { + globalTracer = defaultTracerValue() + globalMeter = defaultMeterValue() + delegateMeterOnce = sync.Once{} +} diff --git a/internal/metric/mock.go b/internal/metric/mock.go index 32462e776bb..107ebc092b6 100644 --- a/internal/metric/mock.go +++ b/internal/metric/mock.go @@ -16,6 +16,7 @@ package metric import ( "context" + "sync" "go.opentelemetry.io/otel/api/core" apimetric "go.opentelemetry.io/otel/api/metric" @@ -45,6 +46,11 @@ type ( Measurements []Measurement } + MeterProvider struct { + lock sync.Mutex + registered map[string]*Meter + } + Meter struct { MeasurementBatches []Batch } @@ -71,6 +77,9 @@ const ( ) func (i *Instrument) AcquireHandle(labels apimetric.LabelSet) apimetric.HandleImpl { + if ld, ok := labels.(apimetric.LabelSetDelegate); ok { + labels = ld.Delegate() + } return &Handle{ Instrument: i, LabelSet: labels.(*LabelSet), @@ -78,6 +87,9 @@ func (i *Instrument) AcquireHandle(labels apimetric.LabelSet) apimetric.HandleIm } func (i *Instrument) RecordOne(ctx context.Context, number core.Number, labels apimetric.LabelSet) { + if ld, ok := labels.(apimetric.LabelSetDelegate); ok { + labels = ld.Delegate() + } doRecordBatch(ctx, labels.(*LabelSet), i, number) } @@ -99,6 +111,24 @@ func (s *LabelSet) Meter() apimetric.Meter { return s.TheMeter } +func NewProvider() *MeterProvider { + return &MeterProvider{ + registered: map[string]*Meter{}, + } +} + +func (p *MeterProvider) Meter(name string) apimetric.Meter { + p.lock.Lock() + defer p.lock.Unlock() + + if lookup, ok := p.registered[name]; ok { + return lookup + } + m := NewMeter() + p.registered[name] = m + return m +} + func NewMeter() *Meter { return &Meter{} } From 7656cae122da715fc6a1693075d82ed9d53d87a6 Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 15:22:19 -0800 Subject: [PATCH 07/13] Add a benchmark --- api/global/internal/benchmark_test.go | 102 ++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 api/global/internal/benchmark_test.go diff --git a/api/global/internal/benchmark_test.go b/api/global/internal/benchmark_test.go new file mode 100644 index 00000000000..ee2edc155b7 --- /dev/null +++ b/api/global/internal/benchmark_test.go @@ -0,0 +1,102 @@ +package internal_test + +import ( + "context" + "strings" + "testing" + + "go.opentelemetry.io/otel/api/global" + "go.opentelemetry.io/otel/api/global/internal" + "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/metric" + export "go.opentelemetry.io/otel/sdk/export/metric" + sdk "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/aggregator/counter" + "go.opentelemetry.io/otel/sdk/metric/aggregator/ddsketch" + "go.opentelemetry.io/otel/sdk/metric/aggregator/gauge" + "go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" +) + +// benchFixture is copied from sdk/metric/benchmark_test.go. +// TODO refactor to share this code. +type benchFixture struct { + sdk *sdk.SDK + B *testing.B +} + +var _ metric.Provider = &benchFixture{} + +func newFixture(b *testing.B) *benchFixture { + b.ReportAllocs() + bf := &benchFixture{ + B: b, + } + bf.sdk = sdk.New(bf, sdk.NewDefaultLabelEncoder()) + return bf +} + +func (*benchFixture) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { + switch descriptor.MetricKind() { + case export.CounterKind: + return counter.New() + case export.GaugeKind: + return gauge.New() + case export.MeasureKind: + if strings.HasSuffix(descriptor.Name(), "minmaxsumcount") { + return minmaxsumcount.New(descriptor) + } else if strings.HasSuffix(descriptor.Name(), "ddsketch") { + return ddsketch.New(ddsketch.NewDefaultConfig(), descriptor) + } else if strings.HasSuffix(descriptor.Name(), "array") { + return ddsketch.New(ddsketch.NewDefaultConfig(), descriptor) + } + } + return nil +} + +func (*benchFixture) Process(context.Context, export.Record) error { + return nil +} + +func (*benchFixture) CheckpointSet() export.CheckpointSet { + return nil +} + +func (*benchFixture) FinishedCollection() { +} + +func (fix *benchFixture) Meter(name string) metric.Meter { + return fix.sdk +} + +func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { + internal.ResetForTest() + ctx := context.Background() + sdk := global.MeterProvider().Meter("test") + labs := sdk.Labels(key.String("A", "B")) + cnt := sdk.NewInt64Counter("int64.counter") + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + cnt.Add(ctx, 1, labs) + } +} + +func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) { + // Comapare with BenchmarkInt64CounterAdd() in ../../sdk/meter/benchmark_test.go + ctx := context.Background() + fix := newFixture(b) + + sdk := global.MeterProvider().Meter("test") + + global.SetMeterProvider(fix) + + labs := sdk.Labels(key.String("A", "B")) + cnt := sdk.NewInt64Counter("int64.counter") + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + cnt.Add(ctx, 1, labs) + } +} From a040c3c4041284349fa79b3feb0e0638bd7522d0 Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 15:22:45 -0800 Subject: [PATCH 08/13] Add a release test --- api/global/internal/meter_test.go | 38 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index dedc1b8bc16..15d83e3ec54 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -17,9 +17,9 @@ func TestDirect(t *testing.T) { ctx := context.Background() glob := global.MeterProvider().Meter("test") - lvals1 := key.New("A").String("B") + lvals1 := key.String("A", "B") labels1 := glob.Labels(lvals1) - lvals2 := key.New("C").String("D") + lvals2 := key.String("C", "D") labels2 := glob.Labels(lvals2) counter := glob.NewInt64Counter("test.counter") @@ -75,11 +75,13 @@ func TestDirect(t *testing.T) { func TestBound(t *testing.T) { internal.ResetForTest() + // Note: this test uses oppsite Float64/Int64 number kinds + // vs. the above, to cover all the instruments. ctx := context.Background() glob := global.MeterProvider().Meter("test") - lvals1 := key.New("A").String("B") + lvals1 := key.String("A", "B") labels1 := glob.Labels(lvals1) - lvals2 := key.New("C").String("D") + lvals2 := key.String("C", "D") labels2 := glob.Labels(lvals2) counter := glob.NewFloat64Counter("test.counter") @@ -133,4 +135,32 @@ func TestBound(t *testing.T) { mock.MeasurementBatches[2].Measurements[0].Number) require.Equal(t, "test.measure", mock.MeasurementBatches[2].Measurements[0].Instrument.Name) + + boundC.Release() + boundG.Release() + boundM.Release() +} + +func TestRelease(t *testing.T) { + // Tests Release with SDK never installed. + internal.ResetForTest() + + glob := global.MeterProvider().Meter("test") + lvals1 := key.New("A").String("B") + labels1 := glob.Labels(lvals1) + lvals2 := key.New("C").String("D") + labels2 := glob.Labels(lvals2) + + counter := glob.NewFloat64Counter("test.counter") + boundC := counter.AcquireHandle(labels1) + + gauge := glob.NewFloat64Gauge("test.gauge") + boundG := gauge.AcquireHandle(labels2) + + measure := glob.NewInt64Measure("test.measure") + boundM := measure.AcquireHandle(labels1) + + boundC.Release() + boundG.Release() + boundM.Release() } From 81e9532c4ae5f197346b33da1de1812e131d3ece Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 15:22:57 -0800 Subject: [PATCH 09/13] Document LabelSetDelegator --- api/metric/api.go | 4 ---- api/metric/sdkhelpers.go | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/api/metric/api.go b/api/metric/api.go index 7db5e467472..f96bd75d5bc 100644 --- a/api/metric/api.go +++ b/api/metric/api.go @@ -33,10 +33,6 @@ type Provider interface { type LabelSet interface { } -type LabelSetDelegate interface { - Delegate() LabelSet -} - // Options contains some options for metrics of any kind. type Options struct { // Description is an optional field describing the metric diff --git a/api/metric/sdkhelpers.go b/api/metric/sdkhelpers.go index dc3c6afcff7..49f615c6288 100644 --- a/api/metric/sdkhelpers.go +++ b/api/metric/sdkhelpers.go @@ -20,6 +20,15 @@ import ( "go.opentelemetry.io/otel/api/core" ) +// LabelSetDelegate is a general-purpose delegating implementation of +// the LabelSet interface. This is implemented by the default +// Provider returned by api/global.SetMeterProvider(), and should be +// tested for by implementations before converting a LabelSet to their +// private concrete type. +type LabelSetDelegate interface { + Delegate() LabelSet +} + // InstrumentImpl is the implementation-level interface Set/Add/Record // individual metrics without precomputed labels. type InstrumentImpl interface { From 31ef9d3f8497ba9fd4ca8970f76ce024b460c6ad Mon Sep 17 00:00:00 2001 From: jmacd Date: Thu, 19 Dec 2019 15:33:47 -0800 Subject: [PATCH 10/13] Lint and comments --- api/global/global.go | 9 ++++++--- api/global/internal/meter.go | 30 ++++++++++++++++++++++++------ api/global/internal/meter_test.go | 1 + api/global/internal/state.go | 5 +++++ example/grpc/go.sum | 3 +++ example/http-stackdriver/go.sum | 3 +++ example/http/go.sum | 3 +++ example/jaeger/go.sum | 3 +++ example/namedtracer/go.sum | 3 +++ exporter/trace/jaeger/go.sum | 3 +++ exporter/trace/stackdriver/go.sum | 3 +++ 11 files changed, 57 insertions(+), 9 deletions(-) diff --git a/api/global/global.go b/api/global/global.go index 0700e8bfed1..a39013b6c73 100644 --- a/api/global/global.go +++ b/api/global/global.go @@ -22,6 +22,7 @@ import ( // TraceProvider returns the registered global trace provider. // If none is registered then an instance of trace.NoopProvider is returned. +// // Use the trace provider to create a named tracer. E.g. // tracer := global.TraceProvider().Tracer("example.com/foo") func TraceProvider() trace.Provider { @@ -33,9 +34,11 @@ func SetTraceProvider(tp trace.Provider) { internal.SetTraceProvider(tp) } -// MeterProvider returns the registered global meter provider. -// If none is registered then an instance of metric.NoopProvider is returned. -// Use the trace provider to create a named meter. E.g. +// MeterProvider returns the registered global meter provider. If +// none is registered then a dewfault meter provider is returned that +// forwards the Meter interface to the first registered Meter. +// +// Use the meter provider to create a named meter. E.g. // meter := global.MeterProvider().Meter("example.com/foo") func MeterProvider() metric.Provider { return internal.MeterProvider() diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index b1b07b8b6ff..caaba4fbd07 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -10,6 +10,27 @@ import ( "go.opentelemetry.io/otel/api/metric" ) +// This file contains the forwarding implementation of metric.Provider +// used as the default global instance. Metric events using instruments +// provided by this implementation are no-ops until the first Meter +// implementation is set as the global provider. +// +// The implementation here uses Mutexes to maintain a list of active +// Meters in the Provider and Instruments in each Meter, under the +// assumption that these interfaces are not performance-critical. +// +// We have the invariant that setDelegate() will be called before a +// new metric.Provider implementation is registered as the global +// provider. Mutexes in the Provider and Meters ensure that each +// instrument has a delegate before the global provider is set. +// +// LabelSets are implemented using the by delegating to the Meter +// instance using the metric.LabelSetDelegator interface. +// +// Bound instrument operations are implementing by delegating to the +// instrument after it is registered, with a sync.Once initializer to +// protect against races with Release(). + type metricKind int8 const ( @@ -134,21 +155,18 @@ func newInstDelegate(m metric.Meter, name string, mkind metricKind, nkind core.N case counterKind: if nkind == core.Int64NumberKind { return m.NewInt64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() - } else { - return m.NewFloat64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() } + return m.NewFloat64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() case gaugeKind: if nkind == core.Int64NumberKind { return m.NewInt64Gauge(name, opts.([]metric.GaugeOptionApplier)...).Impl() - } else { - return m.NewFloat64Gauge(name, opts.([]metric.GaugeOptionApplier)...).Impl() } + return m.NewFloat64Gauge(name, opts.([]metric.GaugeOptionApplier)...).Impl() case measureKind: if nkind == core.Int64NumberKind { return m.NewInt64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() - } else { - return m.NewFloat64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() } + return m.NewFloat64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() } return nil } diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 15d83e3ec54..a121987215f 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" "go.opentelemetry.io/otel/api/global/internal" diff --git a/api/global/internal/state.go b/api/global/internal/state.go index db48af7da06..a423aa18255 100644 --- a/api/global/internal/state.go +++ b/api/global/internal/state.go @@ -25,18 +25,22 @@ var ( delegateMeterOnce sync.Once ) +// TraceProvider is the internal implementation for global.TraceProvider. func TraceProvider() trace.Provider { return globalTracer.Load().(traceProviderHolder).tp } +// SetTraceProvider is the internal implementation for global.SetTraceProvider. func SetTraceProvider(tp trace.Provider) { globalTracer.Store(traceProviderHolder{tp: tp}) } +// MeterProvider is the internal implementation for global.MeterProvider. func MeterProvider() metric.Provider { return globalMeter.Load().(meterProviderHolder).mp } +// SetMeterProvider is the internal implementation for global.SetMeterProvider. func SetMeterProvider(mp metric.Provider) { delegateMeterOnce.Do(func() { current := MeterProvider() @@ -64,6 +68,7 @@ func defaultMeterValue() *atomic.Value { return v } +// ResetForTest restores the initial global state, for testing purposes. func ResetForTest() { globalTracer = defaultTracerValue() globalMeter = defaultMeterValue() diff --git a/example/grpc/go.sum b/example/grpc/go.sum index 46a8fdb8027..a0f76c64906 100644 --- a/example/grpc/go.sum +++ b/example/grpc/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -7,6 +8,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -83,6 +85,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= diff --git a/example/http-stackdriver/go.sum b/example/http-stackdriver/go.sum index 77fd6493622..f3b43dc6ca2 100644 --- a/example/http-stackdriver/go.sum +++ b/example/http-stackdriver/go.sum @@ -15,6 +15,7 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -22,6 +23,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -103,6 +105,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= diff --git a/example/http/go.sum b/example/http/go.sum index 5dfc209f5fc..0d20305f518 100644 --- a/example/http/go.sum +++ b/example/http/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -7,6 +8,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -85,6 +87,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= diff --git a/example/jaeger/go.sum b/example/jaeger/go.sum index f8788f8a827..472d39199ad 100644 --- a/example/jaeger/go.sum +++ b/example/jaeger/go.sum @@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -11,6 +12,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -89,6 +91,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= diff --git a/example/namedtracer/go.sum b/example/namedtracer/go.sum index 69a0e4af903..ee2fea89a7f 100644 --- a/example/namedtracer/go.sum +++ b/example/namedtracer/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -7,6 +8,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -84,6 +86,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= diff --git a/exporter/trace/jaeger/go.sum b/exporter/trace/jaeger/go.sum index e6323aab293..c2e3f007963 100644 --- a/exporter/trace/jaeger/go.sum +++ b/exporter/trace/jaeger/go.sum @@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -11,6 +12,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -91,6 +93,7 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= diff --git a/exporter/trace/stackdriver/go.sum b/exporter/trace/stackdriver/go.sum index 4f8cc468197..ef01d44fcae 100644 --- a/exporter/trace/stackdriver/go.sum +++ b/exporter/trace/stackdriver/go.sum @@ -14,6 +14,7 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7 h1:qELHH0AWCvf98Yf+CNIJx9vOZOfHFDDzgDRYsnNk/vs= github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= @@ -21,6 +22,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -102,6 +104,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= From c401181457fd339d82789b7edf4578413363a426 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 23 Dec 2019 10:16:46 -0800 Subject: [PATCH 11/13] Add a second Meter test; fix typo; add a panic --- api/global/global.go | 2 +- api/global/internal/meter_test.go | 35 ++++++++++++++++++++++++------- api/global/internal/state.go | 7 ++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/api/global/global.go b/api/global/global.go index a39013b6c73..8b49619b09e 100644 --- a/api/global/global.go +++ b/api/global/global.go @@ -35,7 +35,7 @@ func SetTraceProvider(tp trace.Provider) { } // MeterProvider returns the registered global meter provider. If -// none is registered then a dewfault meter provider is returned that +// none is registered then a default meter provider is returned that // forwards the Meter interface to the first registered Meter. // // Use the meter provider to create a named meter. E.g. diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index a121987215f..5c51e0c29de 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -17,32 +17,40 @@ func TestDirect(t *testing.T) { internal.ResetForTest() ctx := context.Background() - glob := global.MeterProvider().Meter("test") + meter1 := global.MeterProvider().Meter("test1") + meter2 := global.MeterProvider().Meter("test2") lvals1 := key.String("A", "B") - labels1 := glob.Labels(lvals1) + labels1 := meter1.Labels(lvals1) lvals2 := key.String("C", "D") - labels2 := glob.Labels(lvals2) + labels2 := meter1.Labels(lvals2) + lvals3 := key.String("E", "F") + labels3 := meter2.Labels(lvals3) - counter := glob.NewInt64Counter("test.counter") + counter := meter1.NewInt64Counter("test.counter") counter.Add(ctx, 1, labels1) counter.Add(ctx, 1, labels1) - gauge := glob.NewInt64Gauge("test.gauge") + gauge := meter1.NewInt64Gauge("test.gauge") gauge.Set(ctx, 1, labels2) gauge.Set(ctx, 2, labels2) - measure := glob.NewFloat64Measure("test.measure") + measure := meter1.NewFloat64Measure("test.measure") measure.Record(ctx, 1, labels1) measure.Record(ctx, 2, labels1) + second := meter2.NewFloat64Measure("test.second") + second.Record(ctx, 1, labels3) + second.Record(ctx, 2, labels3) + sdk := metrictest.NewProvider() global.SetMeterProvider(sdk) counter.Add(ctx, 1, labels1) gauge.Set(ctx, 3, labels2) measure.Record(ctx, 3, labels1) + second.Record(ctx, 3, labels3) - mock := sdk.Meter("test").(*metrictest.Meter) + mock := sdk.Meter("test1").(*metrictest.Meter) require.Equal(t, 3, len(mock.MeasurementBatches)) require.Equal(t, map[core.Key]core.Value{ @@ -71,6 +79,19 @@ func TestDirect(t *testing.T) { mock.MeasurementBatches[2].Measurements[0].Number) require.Equal(t, "test.measure", mock.MeasurementBatches[2].Measurements[0].Instrument.Name) + + // This tests the second Meter instance + mock = sdk.Meter("test2").(*metrictest.Meter) + require.Equal(t, 1, len(mock.MeasurementBatches)) + + require.Equal(t, map[core.Key]core.Value{ + lvals3.Key: lvals3.Value, + }, mock.MeasurementBatches[0].LabelSet.Labels) + require.Equal(t, 1, len(mock.MeasurementBatches[0].Measurements)) + require.Equal(t, core.NewFloat64Number(3), + mock.MeasurementBatches[0].Measurements[0].Number) + require.Equal(t, "test.second", + mock.MeasurementBatches[0].Measurements[0].Instrument.Name) } func TestBound(t *testing.T) { diff --git a/api/global/internal/state.go b/api/global/internal/state.go index a423aa18255..a26492d7c4a 100644 --- a/api/global/internal/state.go +++ b/api/global/internal/state.go @@ -46,9 +46,10 @@ func SetMeterProvider(mp metric.Provider) { current := MeterProvider() if current == mp { - // Setting the provider to the prior default - // is nonsense, set it to a noop. - mp = metric.NoopProvider{} + // Setting the provider to the prior default is nonsense, panic. + // Panic is acceptable because we are likely still early in the + // process lifetime. + panic("invalid Provider, the global instance cannot be reinstalled") } else if def, ok := current.(*meterProvider); ok { def.setDelegate(mp) } From 8cf8fc4146907601affa240cb7015bae9e1d345d Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 23 Dec 2019 10:38:52 -0800 Subject: [PATCH 12/13] Add a test for the builtin SDK --- api/global/internal/meter_test.go | 56 +++++++++++++++++++++++++++++++ sdk/metric/sdk.go | 3 ++ 2 files changed, 59 insertions(+) diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 5c51e0c29de..4f65c0ec5e6 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -2,7 +2,10 @@ package internal_test import ( "context" + "io" + "io/ioutil" "testing" + "time" "github.com/stretchr/testify/require" @@ -10,7 +13,11 @@ import ( "go.opentelemetry.io/otel/api/global" "go.opentelemetry.io/otel/api/global/internal" "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/exporter/metric/stdout" metrictest "go.opentelemetry.io/otel/internal/metric" + "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" + "go.opentelemetry.io/otel/sdk/metric/controller/push" + "go.opentelemetry.io/otel/sdk/metric/selector/simple" ) func TestDirect(t *testing.T) { @@ -186,3 +193,52 @@ func TestRelease(t *testing.T) { boundG.Release() boundM.Release() } + +func TestDefaultSDK(t *testing.T) { + internal.ResetForTest() + + ctx := context.Background() + meter1 := global.MeterProvider().Meter("builtin") + lvals1 := key.String("A", "B") + labels1 := meter1.Labels(lvals1) + + counter := meter1.NewInt64Counter("test.builtin") + counter.Add(ctx, 1, labels1) + counter.Add(ctx, 1, labels1) + + in, out := io.Pipe() + // TODO this should equal a stdout.NewPipeline(), use it. + // Consider also moving the io.Pipe() and go func() call + // below into a test helper somewhere. + sdk := func(options stdout.Options) *push.Controller { + selector := simple.NewWithInexpensiveMeasure() + exporter, err := stdout.New(options) + if err != nil { + panic(err) + } + batcher := ungrouped.New(selector, true) + pusher := push.New(batcher, exporter, time.Second) + pusher.Start() + + return pusher + }(stdout.Options{ + File: out, + DoNotPrintTime: true, + }) + + global.SetMeterProvider(sdk) + + counter.Add(ctx, 1, labels1) + + ch := make(chan string) + go func() { + data, _ := ioutil.ReadAll(in) + ch <- string(data) + }() + + sdk.Stop() + out.Close() + + require.Equal(t, `{"updates":[{"name":"test.builtin{A=B}","sum":1}]} +`, <-ch) +} diff --git a/sdk/metric/sdk.go b/sdk/metric/sdk.go index 31237f16b26..4eeb3bcd917 100644 --- a/sdk/metric/sdk.go +++ b/sdk/metric/sdk.go @@ -281,6 +281,9 @@ func (m *SDK) Labels(kvs ...core.KeyValue) api.LabelSet { // labsFor sanitizes the input LabelSet. The input will be rejected // if it was created by another Meter instance, for example. func (m *SDK) labsFor(ls api.LabelSet) *labels { + if del, ok := ls.(api.LabelSetDelegate); ok { + ls = del.Delegate() + } if l, _ := ls.(*labels); l != nil && l.meter == m { return l } From e1ee73c754369bfd0e06aa4dc5645155908a3d88 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 23 Dec 2019 22:51:43 -0800 Subject: [PATCH 13/13] Address feedback --- api/global/internal/meter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index caaba4fbd07..65f331312ed 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -24,10 +24,10 @@ import ( // provider. Mutexes in the Provider and Meters ensure that each // instrument has a delegate before the global provider is set. // -// LabelSets are implemented using the by delegating to the Meter -// instance using the metric.LabelSetDelegator interface. +// LabelSets are implemented by delegating to the Meter instance using +// the metric.LabelSetDelegator interface. // -// Bound instrument operations are implementing by delegating to the +// Bound instrument operations are implemented by delegating to the // instrument after it is registered, with a sync.Once initializer to // protect against races with Release().