Skip to content

Commit

Permalink
WithAttributes and WithAttributeSet
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlias committed Apr 10, 2023
1 parent 122d147 commit dceba98
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 63 deletions.
3 changes: 1 addition & 2 deletions example/prometheus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@ func main() {
// Start the prometheus HTTP server and pass the exporter Collector to it
go serveMetrics()

attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)

// This is the equivalent of prometheus.NewCounterVec
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
Expand Down
3 changes: 1 addition & 2 deletions example/view/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,10 @@ func main() {
// Start the prometheus HTTP server and pass the exporter Collector to it
go serveMetrics()

attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)

counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
if err != nil {
Expand Down
44 changes: 16 additions & 28 deletions exporters/prometheus/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,12 @@ func TestPrometheusExporter(t *testing.T) {
name: "counter",
expectedFile: "testdata/counter.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Float64Counter(
"foo",
instrument.WithDescription("a simple counter"),
Expand All @@ -69,18 +68,17 @@ func TestPrometheusExporter(t *testing.T) {
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
counter.Add(ctx, 5, instrument.WithAttributes(attrs2))
counter.Add(ctx, 5, instrument.WithAttributeSet(attrs2))
},
},
{
name: "gauge",
expectedFile: "testdata/gauge.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)
gauge, err := meter.Float64UpDownCounter(
"bar",
instrument.WithDescription("a fun little gauge"),
Expand All @@ -95,11 +93,10 @@ func TestPrometheusExporter(t *testing.T) {
name: "histogram",
expectedFile: "testdata/histogram.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)
histogram, err := meter.Float64Histogram(
"histogram_baz",
instrument.WithDescription("a very nice histogram"),
Expand All @@ -117,7 +114,7 @@ func TestPrometheusExporter(t *testing.T) {
expectedFile: "testdata/sanitized_labels.txt",
options: []Option{WithoutUnits()},
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
// exact match, value should be overwritten
attribute.Key("A.B").String("X"),
attribute.Key("A.B").String("Q"),
Expand All @@ -126,7 +123,6 @@ func TestPrometheusExporter(t *testing.T) {
attribute.Key("C.D").String("Y"),
attribute.Key("C/D").String("Z"),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Float64Counter(
"foo",
instrument.WithDescription("a sanitary counter"),
Expand All @@ -143,11 +139,10 @@ func TestPrometheusExporter(t *testing.T) {
name: "invalid instruments are renamed",
expectedFile: "testdata/sanitized_names.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)
// Valid.
gauge, err := meter.Float64UpDownCounter("bar", instrument.WithDescription("a fun little gauge"))
require.NoError(t, err)
Expand All @@ -173,13 +168,12 @@ func TestPrometheusExporter(t *testing.T) {
emptyResource: true,
expectedFile: "testdata/empty_resource.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, opt)
Expand All @@ -195,13 +189,12 @@ func TestPrometheusExporter(t *testing.T) {
},
expectedFile: "testdata/custom_resource.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, opt)
Expand All @@ -214,13 +207,12 @@ func TestPrometheusExporter(t *testing.T) {
options: []Option{WithoutTargetInfo()},
expectedFile: "testdata/without_target_info.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, opt)
Expand All @@ -233,11 +225,10 @@ func TestPrometheusExporter(t *testing.T) {
options: []Option{WithoutScopeInfo()},
expectedFile: "testdata/without_scope_info.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)
gauge, err := meter.Int64UpDownCounter(
"bar",
instrument.WithDescription("a fun little gauge"),
Expand All @@ -253,11 +244,10 @@ func TestPrometheusExporter(t *testing.T) {
options: []Option{WithoutScopeInfo(), WithoutTargetInfo()},
expectedFile: "testdata/without_scope_and_target_info.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := attribute.NewSet(
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
)
opt := instrument.WithAttributes(attrs)
counter, err := meter.Int64Counter(
"bar",
instrument.WithDescription("a fun little counter"),
Expand Down Expand Up @@ -398,17 +388,15 @@ func TestMultiScopes(t *testing.T) {
instrument.WithUnit("ms"),
instrument.WithDescription("meter foo counter"))
assert.NoError(t, err)
s := attribute.NewSet(attribute.String("type", "foo"))
fooCounter.Add(ctx, 100, instrument.WithAttributes(s))
fooCounter.Add(ctx, 100, instrument.WithAttributes(attribute.String("type", "foo")))

barCounter, err := provider.Meter("meterbar", otelmetric.WithInstrumentationVersion("v0.1.0")).
Int64Counter(
"bar",
instrument.WithUnit("ms"),
instrument.WithDescription("meter bar counter"))
assert.NoError(t, err)
s = attribute.NewSet(attribute.String("type", "bar"))
barCounter.Add(ctx, 200, instrument.WithAttributes(s))
barCounter.Add(ctx, 200, instrument.WithAttributes(attribute.String("type", "bar")))

file, err := os.Open("testdata/multi_scopes.txt")
require.NoError(t, err)
Expand All @@ -420,11 +408,11 @@ func TestMultiScopes(t *testing.T) {

func TestDuplicateMetrics(t *testing.T) {
ab := attribute.NewSet(attribute.String("A", "B"))
withAB := instrument.WithAttributes(ab)
withAB := instrument.WithAttributeSet(ab)
typeBar := attribute.NewSet(attribute.String("type", "bar"))
withTypeBar := instrument.WithAttributes(typeBar)
withTypeBar := instrument.WithAttributeSet(typeBar)
typeFoo := attribute.NewSet(attribute.String("type", "foo"))
withTypeFoo := instrument.WithAttributes(typeFoo)
withTypeFoo := instrument.WithAttributeSet(typeFoo)
testCases := []struct {
name string
customResouceAttrs []attribute.KeyValue
Expand Down
3 changes: 1 addition & 2 deletions metric/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ func ExampleMeter_asynchronous_single() {
//
// For demonstration purpose, a static value is used here.
usage := 75000
s := attribute.NewSet(attribute.Int("disk.id", 3))
obsrv.Observe(int64(usage), instrument.WithAttributes(s))
obsrv.Observe(int64(usage), instrument.WithAttributes(attribute.Int("disk.id", 3)))
return nil
}),
)
Expand Down
62 changes: 48 additions & 14 deletions metric/instrument/instrument.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ type Int64AddConfig struct {

// NewInt64AddConfig returns a new [Int64AddConfig] with all opts applied.
func NewInt64AddConfig(opts ...Int64AddOption) Int64AddConfig {
var config Int64AddConfig
config := Int64AddConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyInt64Add(config)
}
Expand All @@ -208,7 +208,7 @@ type Float64AddConfig struct {

// NewFloat64AddConfig returns a new [Float64AddConfig] with all opts applied.
func NewFloat64AddConfig(opts ...Float64AddOption) Float64AddConfig {
var config Float64AddConfig
config := Float64AddConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyFloat64Add(config)
}
Expand All @@ -235,7 +235,7 @@ type Int64RecordConfig struct {
// NewInt64RecordConfig returns a new [Int64RecordConfig] with all opts
// applied.
func NewInt64RecordConfig(opts ...Int64RecordOption) Int64RecordConfig {
var config Int64RecordConfig
config := Int64RecordConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyInt64Record(config)
}
Expand All @@ -262,7 +262,7 @@ type Float64RecordConfig struct {
// NewFloat64RecordConfig returns a new [Float64RecordConfig] with all opts
// applied.
func NewFloat64RecordConfig(opts ...Float64RecordOption) Float64RecordConfig {
var config Float64RecordConfig
config := Float64RecordConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyFloat64Record(config)
}
Expand All @@ -289,7 +289,7 @@ type Int64ObserveConfig struct {
// NewInt64ObserveConfig returns a new [Int64ObserveConfig] with all opts
// applied.
func NewInt64ObserveConfig(opts ...Int64ObserveOption) Int64ObserveConfig {
var config Int64ObserveConfig
config := Int64ObserveConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyInt64Observe(config)
}
Expand All @@ -316,7 +316,7 @@ type Float64ObserveConfig struct {
// NewFloat64ObserveConfig returns a new [Float64ObserveConfig] with all opts
// applied.
func NewFloat64ObserveConfig(opts ...Float64ObserveOption) Float64ObserveConfig {
var config Float64ObserveConfig
config := Float64ObserveConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyFloat64Observe(config)
}
Expand All @@ -342,37 +342,71 @@ type attrOpt struct {
set attribute.Set
}

// mergeSets returns the union of keys between a and b. Any duplicate keys will
// use the value associated with b.
func mergeSets(a, b attribute.Set) attribute.Set {
switch 0 {
case a.Len():
return b
case b.Len():
return a
}

// NewMergeIterator uses the first value for any duplicates.
iter := attribute.NewMergeIterator(&b, &a)
merged := make([]attribute.KeyValue, 0, a.Len()+b.Len())
for iter.Next() {
merged = append(merged, iter.Attribute())
}
return attribute.NewSet(merged...)
}

func (o attrOpt) applyInt64Add(c Int64AddConfig) Int64AddConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

func (o attrOpt) applyFloat64Add(c Float64AddConfig) Float64AddConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

func (o attrOpt) applyInt64Record(c Int64RecordConfig) Int64RecordConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

func (o attrOpt) applyFloat64Record(c Float64RecordConfig) Float64RecordConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

func (o attrOpt) applyInt64Observe(c Int64ObserveConfig) Int64ObserveConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

func (o attrOpt) applyFloat64Observe(c Float64ObserveConfig) Float64ObserveConfig {
c.attrs = o.set
c.attrs = mergeSets(c.attrs, o.set)
return c
}

// WithAttributes sets the attributes a measurement is made with.
func WithAttributes(attributes attribute.Set) MeasurementOption {
// WithAttributeSet sets the attribute Set associated with a measurement is
// made with.
//
// If multiple WithAttributeSet or WithAttributes options are passed the
// attributes will be merged together in the order they are passed. Attributes
// with duplicate keys will use the last value passed.
func WithAttributeSet(attributes attribute.Set) MeasurementOption {
return attrOpt{set: attributes}
}

// WithAttributeSet converts attributes into an attribute Set and sets the Set
// to be associated with a measurement. This is shorthand for:
//
// WithAttributes(attribute.NewSet(attributes...))
//
// See [WithAttributeSet] for how multiple WithAttributes are merged.
func WithAttributes(attributes ...attribute.KeyValue) MeasurementOption {
return attrOpt{set: attribute.NewSet(attributes...)}
}

0 comments on commit dceba98

Please sign in to comment.