Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global meter forwarding implementation #392

Merged
merged 15 commits into from
Dec 24, 2019
41 changes: 11 additions & 30 deletions api/global/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
102 changes: 102 additions & 0 deletions api/global/internal/benchmark_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading