Skip to content

Commit

Permalink
Restructure instrument creation code paths (#3256)
Browse files Browse the repository at this point in the history
* Add BenchmarkInstrumentCreation

* Unify instrument provider

* Resolve import shadow

* Update sdk/metric/pipeline.go

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Punctuate to fix lint

Co-authored-by: Chester Cheung <cheung.zhy.csu@gmail.com>
Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
  • Loading branch information
3 people committed Nov 11, 2022
1 parent 496c086 commit acd8777
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 238 deletions.
237 changes: 63 additions & 174 deletions sdk/metric/instrument_provider.go
Expand Up @@ -22,251 +22,140 @@ import (
"go.opentelemetry.io/otel/metric/instrument/asyncint64"
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
"go.opentelemetry.io/otel/metric/unit"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/metric/view"
)

type asyncInt64Provider struct {
scope instrumentation.Scope
resolve *resolver[int64]
// instProviderKey uniquely describes an instrument creation request received
// by an instrument provider.
type instProviderKey struct {
// Name is the name of the instrument.
Name string
// Description is the description of the instrument.
Description string
// Unit is the unit of the instrument.
Unit unit.Unit
// Kind is the instrument Kind provided.
Kind view.InstrumentKind
}

// viewInst returns the instProviderKey as a view Instrument using scope s.
func (k instProviderKey) viewInst(s instrumentation.Scope) view.Instrument {
return view.Instrument{
Scope: s,
Name: k.Name,
Description: k.Description,
Kind: k.Kind,
}
}

var _ asyncint64.InstrumentProvider = asyncInt64Provider{}
// instProvider provides all OpenTelemetry instruments.
type instProvider[N int64 | float64] struct {
resolve resolver[N]
}

// Counter creates an instrument for recording increasing values.
func (p asyncInt64Provider) Counter(name string, opts ...instrument.Option) (asyncint64.Counter, error) {
cfg := instrument.NewConfig(opts...)
func newInstProvider[N int64 | float64](r resolver[N]) *instProvider[N] {
return &instProvider[N]{resolve: r}
}

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
// lookup returns the resolved instrumentImpl.
func (p *instProvider[N]) lookup(kind view.InstrumentKind, name string, opts []instrument.Option) (*instrumentImpl[N], error) {
cfg := instrument.NewConfig(opts...)
key := instProviderKey{
Name: name,
Description: cfg.Description(),
Kind: view.AsyncCounter,
}, cfg.Unit())
Unit: cfg.Unit(),
Kind: kind,
}

aggs, err := p.resolve.Aggregators(key)
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[N]{aggregators: aggs}, err
}

return &instrumentImpl[int64]{
aggregators: aggs,
}, err
type asyncInt64Provider struct {
*instProvider[int64]
}

var _ asyncint64.InstrumentProvider = asyncInt64Provider{}

// Counter creates an instrument for recording increasing values.
func (p asyncInt64Provider) Counter(name string, opts ...instrument.Option) (asyncint64.Counter, error) {
return p.lookup(view.AsyncCounter, name, opts)
}

// UpDownCounter creates an instrument for recording changes of a value.
func (p asyncInt64Provider) UpDownCounter(name string, opts ...instrument.Option) (asyncint64.UpDownCounter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.AsyncUpDownCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[int64]{
aggregators: aggs,
}, err
return p.lookup(view.AsyncUpDownCounter, name, opts)
}

// Gauge creates an instrument for recording the current value.
func (p asyncInt64Provider) Gauge(name string, opts ...instrument.Option) (asyncint64.Gauge, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.AsyncGauge,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[int64]{
aggregators: aggs,
}, err
return p.lookup(view.AsyncGauge, name, opts)
}

type asyncFloat64Provider struct {
scope instrumentation.Scope
resolve *resolver[float64]
*instProvider[float64]
}

var _ asyncfloat64.InstrumentProvider = asyncFloat64Provider{}

// Counter creates an instrument for recording increasing values.
func (p asyncFloat64Provider) Counter(name string, opts ...instrument.Option) (asyncfloat64.Counter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.AsyncCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.AsyncCounter, name, opts)
}

// UpDownCounter creates an instrument for recording changes of a value.
func (p asyncFloat64Provider) UpDownCounter(name string, opts ...instrument.Option) (asyncfloat64.UpDownCounter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.AsyncUpDownCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.AsyncUpDownCounter, name, opts)
}

// Gauge creates an instrument for recording the current value.
func (p asyncFloat64Provider) Gauge(name string, opts ...instrument.Option) (asyncfloat64.Gauge, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.AsyncGauge,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.AsyncGauge, name, opts)
}

type syncInt64Provider struct {
scope instrumentation.Scope
resolve *resolver[int64]
*instProvider[int64]
}

var _ syncint64.InstrumentProvider = syncInt64Provider{}

// Counter creates an instrument for recording increasing values.
func (p syncInt64Provider) Counter(name string, opts ...instrument.Option) (syncint64.Counter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[int64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncCounter, name, opts)
}

// UpDownCounter creates an instrument for recording changes of a value.
func (p syncInt64Provider) UpDownCounter(name string, opts ...instrument.Option) (syncint64.UpDownCounter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncUpDownCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[int64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncUpDownCounter, name, opts)
}

// Histogram creates an instrument for recording the current value.
func (p syncInt64Provider) Histogram(name string, opts ...instrument.Option) (syncint64.Histogram, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncHistogram,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[int64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncHistogram, name, opts)
}

type syncFloat64Provider struct {
scope instrumentation.Scope
resolve *resolver[float64]
*instProvider[float64]
}

var _ syncfloat64.InstrumentProvider = syncFloat64Provider{}

// Counter creates an instrument for recording increasing values.
func (p syncFloat64Provider) Counter(name string, opts ...instrument.Option) (syncfloat64.Counter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncCounter, name, opts)
}

// UpDownCounter creates an instrument for recording changes of a value.
func (p syncFloat64Provider) UpDownCounter(name string, opts ...instrument.Option) (syncfloat64.UpDownCounter, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncUpDownCounter,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncUpDownCounter, name, opts)
}

// Histogram creates an instrument for recording the current value.
func (p syncFloat64Provider) Histogram(name string, opts ...instrument.Option) (syncfloat64.Histogram, error) {
cfg := instrument.NewConfig(opts...)

aggs, err := p.resolve.Aggregators(view.Instrument{
Scope: p.scope,
Name: name,
Description: cfg.Description(),
Kind: view.SyncHistogram,
}, cfg.Unit())
if len(aggs) == 0 && err != nil {
err = fmt.Errorf("instrument does not match any view: %w", err)
}
return &instrumentImpl[float64]{
aggregators: aggs,
}, err
return p.lookup(view.SyncHistogram, name, opts)
}
30 changes: 13 additions & 17 deletions sdk/metric/meter.go
Expand Up @@ -31,15 +31,10 @@ import (
// produced by an instrumentation scope will use metric instruments from a
// single meter.
type meter struct {
instrumentation.Scope

// *Resolvers are used by the provided instrument providers to resolve new
// instruments aggregators and maintain a cache across instruments this
// meter owns.
int64Resolver resolver[int64]
float64Resolver resolver[float64]

pipes pipelines

instProviderInt64 *instProvider[int64]
instProviderFloat64 *instProvider[float64]
}

func newMeter(s instrumentation.Scope, p pipelines) *meter {
Expand All @@ -52,12 +47,13 @@ func newMeter(s instrumentation.Scope, p pipelines) *meter {
ic := newInstrumentCache[int64](nil, &viewCache)
fc := newInstrumentCache[float64](nil, &viewCache)

return &meter{
Scope: s,
pipes: p,
ir := newResolver(s, p, ic)
fr := newResolver(s, p, fc)

int64Resolver: newResolver(p, ic),
float64Resolver: newResolver(p, fc),
return &meter{
pipes: p,
instProviderInt64: newInstProvider(ir),
instProviderFloat64: newInstProvider(fr),
}
}

Expand All @@ -66,12 +62,12 @@ var _ metric.Meter = (*meter)(nil)

// AsyncInt64 returns the asynchronous integer instrument provider.
func (m *meter) AsyncInt64() asyncint64.InstrumentProvider {
return asyncInt64Provider{scope: m.Scope, resolve: &m.int64Resolver}
return asyncInt64Provider{m.instProviderInt64}
}

// AsyncFloat64 returns the asynchronous floating-point instrument provider.
func (m *meter) AsyncFloat64() asyncfloat64.InstrumentProvider {
return asyncFloat64Provider{scope: m.Scope, resolve: &m.float64Resolver}
return asyncFloat64Provider{m.instProviderFloat64}
}

// RegisterCallback registers the function f to be called when any of the
Expand All @@ -83,10 +79,10 @@ func (m *meter) RegisterCallback(insts []instrument.Asynchronous, f func(context

// SyncInt64 returns the synchronous integer instrument provider.
func (m *meter) SyncInt64() syncint64.InstrumentProvider {
return syncInt64Provider{scope: m.Scope, resolve: &m.int64Resolver}
return syncInt64Provider{m.instProviderInt64}
}

// SyncFloat64 returns the synchronous floating-point instrument provider.
func (m *meter) SyncFloat64() syncfloat64.InstrumentProvider {
return syncFloat64Provider{scope: m.Scope, resolve: &m.float64Resolver}
return syncFloat64Provider{m.instProviderFloat64}
}

0 comments on commit acd8777

Please sign in to comment.