diff --git a/api/global/global.go b/api/global/global.go index af7f8ac8c12..8b49619b09e 100644 --- a/api/global/global.go +++ b/api/global/global.go @@ -15,55 +15,36 @@ 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. -// 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 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. // 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/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) + } +} diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go new file mode 100644 index 00000000000..65f331312ed --- /dev/null +++ b/api/global/internal/meter.go @@ -0,0 +1,293 @@ +package internal + +import ( + "context" + "sync" + "sync/atomic" + "unsafe" + + "go.opentelemetry.io/otel/api/core" + "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 by delegating to the Meter instance using +// the metric.LabelSetDelegator interface. +// +// 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(). + +type metricKind int8 + +const ( + counterKind metricKind = iota + gaugeKind + measureKind +) + +type meterProvider struct { + lock sync.Mutex + meters []*meter + delegate metric.Provider +} + +type meter struct { + provider *meterProvider + name string + + lock sync.Mutex + instruments []*instImpl + + delegate unsafe.Pointer // (*metric.Meter) +} + +type instImpl struct { + name string + mkind metricKind + nkind core.NumberKind + opts interface{} + + 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 + + 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{} + +// 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 { + 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 +} + +// 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) newInst(name string, mkind metricKind, nkind core.NumberKind, opts interface{}) metric.InstrumentImpl { + m.lock.Lock() + defer m.lock.Unlock() + + if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return newInstDelegate(*meterPtr, name, mkind, nkind, opts) + } + + inst := &instImpl{ + 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() + } + return m.NewFloat64Counter(name, opts.([]metric.CounterOptionApplier)...).Impl() + case gaugeKind: + if nkind == core.Int64NumberKind { + return m.NewInt64Gauge(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() + } + return m.NewFloat64Measure(name, opts.([]metric.MeasureOptionApplier)...).Impl() + } + return nil +} + +// Instrument delegation + +func (inst *instImpl) setDelegate(d metric.Meter) { + implPtr := new(metric.InstrumentImpl) + + *implPtr = newInstDelegate(d, inst.name, inst.mkind, inst.nkind, inst.opts) + + atomic.StorePointer(&inst.delegate, unsafe.Pointer(implPtr)) +} + +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 (bound *instHandle) Release() { + bound.initialize.Do(func() {}) + + implPtr := (*metric.HandleImpl)(atomic.LoadPointer(&bound.delegate)) + + if implPtr == nil { + return + } + + (*implPtr).Release() +} + +// Metric updates + +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 (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) + } +} + +// 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. + return labels + } + 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 + +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)) +} diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go new file mode 100644 index 00000000000..4f65c0ec5e6 --- /dev/null +++ b/api/global/internal/meter_test.go @@ -0,0 +1,244 @@ +package internal_test + +import ( + "context" + "io" + "io/ioutil" + "testing" + "time" + + "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" + "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) { + internal.ResetForTest() + + ctx := context.Background() + meter1 := global.MeterProvider().Meter("test1") + meter2 := global.MeterProvider().Meter("test2") + lvals1 := key.String("A", "B") + labels1 := meter1.Labels(lvals1) + lvals2 := key.String("C", "D") + labels2 := meter1.Labels(lvals2) + lvals3 := key.String("E", "F") + labels3 := meter2.Labels(lvals3) + + counter := meter1.NewInt64Counter("test.counter") + counter.Add(ctx, 1, labels1) + counter.Add(ctx, 1, labels1) + + gauge := meter1.NewInt64Gauge("test.gauge") + gauge.Set(ctx, 1, labels2) + gauge.Set(ctx, 2, labels2) + + 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("test1").(*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) + + // 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) { + 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.String("A", "B") + labels1 := glob.Labels(lvals1) + lvals2 := key.String("C", "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) + + 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() +} + +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/api/global/internal/state.go b/api/global/internal/state.go new file mode 100644 index 00000000000..a26492d7c4a --- /dev/null +++ b/api/global/internal/state.go @@ -0,0 +1,77 @@ +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 +) + +// 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() + + if current == mp { + // 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) + } + }) + 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 +} + +// ResetForTest restores the initial global state, for testing purposes. +func ResetForTest() { + globalTracer = defaultTracerValue() + globalMeter = defaultMeterValue() + delegateMeterOnce = sync.Once{} +} 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 { 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= 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{} } 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 }