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

Add support for Resources in the SDK #552

Merged
merged 16 commits into from
Mar 20, 2020
Merged
22 changes: 22 additions & 0 deletions api/metric/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"go.opentelemetry.io/otel/api/core"
"go.opentelemetry.io/otel/api/unit"
"go.opentelemetry.io/otel/sdk/resource"
)

// Provider supports named Meter instances.
Expand All @@ -45,6 +46,8 @@ type Config struct {
// Keys are recommended keys determined in the handles
// obtained for the metric.
Keys []core.Key
// Resource describes the entity for which measurements are made.
Resource resource.Resource
}

// Option is an interface for applying metric options.
Expand Down Expand Up @@ -141,6 +144,12 @@ func (d Descriptor) NumberKind() core.NumberKind {
return d.numberKind
}

// Resource returns the Resource describing the entity for which the metric
// instrument measures.
func (d Descriptor) Resource() resource.Resource {
return d.config.Resource
}

// Meter is an interface to the metrics portion of the OpenTelemetry SDK.
type Meter interface {
// Labels returns a reference to a set of labels that cannot
Expand Down Expand Up @@ -212,3 +221,16 @@ type keysOption []core.Key
func (k keysOption) Apply(config *Config) {
config.Keys = append(config.Keys, k...)
}

// WithResource applies provided Resource.
//
// This will override any existing Resource.
func WithResource(r resource.Resource) Option {
return resourceOption(r)
}

type resourceOption resource.Resource

func (r resourceOption) Apply(config *Config) {
config.Resource = resource.Resource(r)
}
67 changes: 43 additions & 24 deletions api/metric/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"go.opentelemetry.io/otel/api/metric"
"go.opentelemetry.io/otel/api/unit"
mockTest "go.opentelemetry.io/otel/internal/metric"
"go.opentelemetry.io/otel/sdk/resource"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
Expand All @@ -35,19 +36,21 @@ var Must = metric.Must

func TestOptions(t *testing.T) {
type testcase struct {
name string
opts []metric.Option
keys []core.Key
desc string
unit unit.Unit
name string
opts []metric.Option
keys []core.Key
desc string
unit unit.Unit
resource resource.Resource
}
testcases := []testcase{
{
name: "no opts",
opts: nil,
keys: nil,
desc: "",
unit: "",
name: "no opts",
opts: nil,
keys: nil,
desc: "",
unit: "",
resource: resource.Resource{},
},
{
name: "keys keys keys",
Expand All @@ -61,46 +64,61 @@ func TestOptions(t *testing.T) {
key.New("bar"), key.New("bar2"),
key.New("baz"), key.New("baz2"),
},
desc: "",
unit: "",
desc: "",
unit: "",
resource: resource.Resource{},
},
{
name: "description",
opts: []metric.Option{
metric.WithDescription("stuff"),
},
keys: nil,
desc: "stuff",
unit: "",
keys: nil,
desc: "stuff",
unit: "",
resource: resource.Resource{},
},
{
name: "description override",
opts: []metric.Option{
metric.WithDescription("stuff"),
metric.WithDescription("things"),
},
keys: nil,
desc: "things",
unit: "",
keys: nil,
desc: "things",
unit: "",
resource: resource.Resource{},
},
{
name: "unit",
opts: []metric.Option{
metric.WithUnit("s"),
},
keys: nil,
desc: "",
unit: "s",
keys: nil,
desc: "",
unit: "s",
resource: resource.Resource{},
},
{
name: "unit override",
opts: []metric.Option{
metric.WithUnit("s"),
metric.WithUnit("h"),
},
keys: nil,
desc: "",
unit: "h",
keys: nil,
desc: "",
unit: "h",
resource: resource.Resource{},
},
{
name: "resource override",
opts: []metric.Option{
metric.WithResource(*resource.New(key.New("name").String("test-name"))),
},
keys: nil,
desc: "",
unit: "",
resource: *resource.New(key.New("name").String("test-name")),
},
}
for idx, tt := range testcases {
Expand All @@ -109,6 +127,7 @@ func TestOptions(t *testing.T) {
Description: tt.desc,
Unit: tt.unit,
Keys: tt.keys,
Resource: tt.resource,
}); diff != "" {
t.Errorf("Compare options: -got +want %s", diff)
}
Expand Down
26 changes: 26 additions & 0 deletions api/metric/sdkhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"

"go.opentelemetry.io/otel/api/core"
"go.opentelemetry.io/otel/sdk/resource"
)

// MeterImpl is a convenient interface for SDK and test
Expand Down Expand Up @@ -133,6 +134,29 @@ func Configure(opts []Option) Config {
return config
}

// Resourcer is implemented by any value that has a Resource method,
// which returns the Resource associated with the value.
// The Resource method is used to set the Resource for Descriptors of new
// metric instruments.
type Resourcer interface {
Resource() resource.Resource
}

// insertResource inserts a WithResource option at the beginning of opts
// using the resource defined by impl if impl implements Resourcer.
//
// If opts contains a WithResource option already, that Option will take
// precedence and overwrite the Resource set from impl.
//
// The returned []Option may uses the same underlying array as opts.
func insertResource(impl MeterImpl, opts []Option) []Option {
if r, ok := impl.(Resourcer); ok {
// default to the impl resource and override if passed in opts.
return append([]Option{WithResource(r.Resource())}, opts...)
}
return opts
}

// WrapMeterImpl constructs a `Meter` implementation from a
// `MeterImpl` implementation.
func WrapMeterImpl(impl MeterImpl) Meter {
Expand All @@ -159,6 +183,7 @@ func (m *wrappedMeterImpl) RecordBatch(ctx context.Context, ls LabelSet, ms ...M
}

func (m *wrappedMeterImpl) newSync(name string, metricKind Kind, numberKind core.NumberKind, opts []Option) (SyncImpl, error) {
opts = insertResource(m.impl, opts)
return m.impl.NewSyncInstrument(NewDescriptor(name, metricKind, numberKind, opts...))
}

Expand Down Expand Up @@ -219,6 +244,7 @@ func WrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure,
}

func (m *wrappedMeterImpl) newAsync(name string, mkind Kind, nkind core.NumberKind, opts []Option, callback func(func(core.Number, LabelSet))) (AsyncImpl, error) {
opts = insertResource(m.impl, opts)
return m.impl.NewAsyncInstrument(
NewDescriptor(name, mkind, nkind, opts...),
callback)
Expand Down
2 changes: 1 addition & 1 deletion sdk/export/metric/metric.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019, OpenTelemetry Authors
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
44 changes: 44 additions & 0 deletions sdk/metric/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package metric

import "go.opentelemetry.io/otel/sdk/resource"

// Config contains configuration for an SDK.
type Config struct {
// ErrorHandler is the function called when the SDK encounters an error.
//
// This option can be overridden after instantiation of the SDK
// with the `SetErrorHandler` method.
ErrorHandler ErrorHandler

// Resource is the OpenTelemetry resource associated with all Meters
// created by the SDK.
Resource resource.Resource
}

// Option is the interface that applies the value to a configuration option.
type Option interface {
MrAlias marked this conversation as resolved.
Show resolved Hide resolved
// Apply sets the Option value of a Config.
Apply(*Config)
}

// WithErrorHandler sets the ErrorHandler configuration option of a Config.
func WithErrorHandler(fn ErrorHandler) Option {
return errorHandlerOption(fn)
}

type errorHandlerOption ErrorHandler

func (o errorHandlerOption) Apply(config *Config) {
config.ErrorHandler = ErrorHandler(o)
}

// WithResource sets the Resource configuration option of a Config.
func WithResource(r resource.Resource) Option {
return resourceOption(r)
}

type resourceOption resource.Resource

func (o resourceOption) Apply(config *Config) {
config.Resource = resource.Resource(o)
}
47 changes: 47 additions & 0 deletions sdk/metric/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package metric

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"

"go.opentelemetry.io/otel/api/core"
"go.opentelemetry.io/otel/sdk/resource"
)

func TestWithErrorHandler(t *testing.T) {
errH, reg := func() (ErrorHandler, *error) {
e := fmt.Errorf("default invalid")
reg := &e
return func(err error) {
*reg = err
}, reg
}()

c := &Config{}
WithErrorHandler(errH).Apply(c)
err1 := fmt.Errorf("error 1")
c.ErrorHandler(err1)
assert.EqualError(t, *reg, err1.Error())

// Ensure overwriting works.
c = &Config{ErrorHandler: DefaultErrorHandler}
WithErrorHandler(errH).Apply(c)
err2 := fmt.Errorf("error 2")
c.ErrorHandler(err2)
assert.EqualError(t, *reg, err2.Error())
}

func TestWithResource(t *testing.T) {
r := resource.New(core.Key("A").String("a"))

c := &Config{}
WithResource(*r).Apply(c)
assert.Equal(t, *r, c.Resource)

// Ensure overwriting works.
c = &Config{Resource: resource.Resource{}}
WithResource(*r).Apply(c)
assert.Equal(t, *r, c.Resource)
}
47 changes: 47 additions & 0 deletions sdk/metric/controller/push/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package push

import (
sdk "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
)

// Config contains configuration for a push Controller.
type Config struct {
// ErrorHandler is the function called when the Controller encounters an error.
//
// This option can be overridden after instantiation of the Controller
// with the `SetErrorHandler` method.
ErrorHandler sdk.ErrorHandler

// Resource is the OpenTelemetry resource associated with all Meters
// created by the Controller.
Resource resource.Resource
}

// Option is the interface that applies the value to a configuration option.
type Option interface {
MrAlias marked this conversation as resolved.
Show resolved Hide resolved
// Apply sets the Option value of a Config.
Apply(*Config)
}

// WithErrorHandler sets the ErrorHandler configuration option of a Config.
func WithErrorHandler(fn sdk.ErrorHandler) Option {
return errorHandlerOption(fn)
}

type errorHandlerOption sdk.ErrorHandler

func (o errorHandlerOption) Apply(config *Config) {
config.ErrorHandler = sdk.ErrorHandler(o)
}

// WithResource sets the Resource configuration option of a Config.
func WithResource(r resource.Resource) Option {
return resourceOption(r)
}

type resourceOption resource.Resource

func (o resourceOption) Apply(config *Config) {
config.Resource = resource.Resource(o)
}
Loading