1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-26 03:52:03 +02:00

Add options to measurement methods (#3971)

* Add options to measurement methods

* Update noop

* Update global impl

* Update SDK impl

* Fix metric API example

* Update prometheus exporter tests

* Update examples

* WithAttributes and WithAttributeSet

* Add changes to changelog

* Accept slice instead of variadic to new conf funcs

* Clarify WithAttributes performance in docs

* Address feedback about WithAttributes comment

* Add changelog entry for WithAttribute{s,Set}

* Remove number scope from measure opts

* Update changelog

* Remove left-over test cases

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
This commit is contained in:
Tyler Yahn 2023-04-18 07:16:06 -07:00 committed by GitHub
parent d1959c9239
commit f8fcfda872
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 742 additions and 364 deletions

View File

@ -13,6 +13,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `go.opentelemetry.io/otel/metric/embedded` package. (#3916)
- The `Version` function to `go.opentelemetry.io/otel/sdk` to return the SDK version. (#3949)
- Add a `WithNamespace` option to `go.opentelemetry.io/otel/exporters/prometheus` to allow users to prefix metrics with a namespace. (#3970)
- The following configuration types were added to `go.opentelemetry.io/otel/metric/instrument` to be used in the configuration of measurement methods. (#3971)
- The `AddConfig` used to hold configuration for addition measurements
- `NewAddConfig` used to create a new `AddConfig`
- `AddOption` used to configure an `AddConfig`
- The `RecordConfig` used to hold configuration for recorded measurements
- `NewRecordConfig` used to create a new `RecordConfig`
- `RecordOption` used to configure a `RecordConfig`
- The `ObserveConfig` used to hold configuration for observed measurements
- `NewObserveConfig` used to create a new `ObserveConfig`
- `ObserveOption` used to configure an `ObserveConfig`
- `WithAttributeSet` and `WithAttributes` are added to `go.opentelemetry.io/otel/metric/instrument`.
They return an option used during a measurement that defines the attribute Set associated with the measurement. (#3971)
- The `Version` function to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` to return the OTLP metrics client version. (#3956)
- The `Version` function to `go.opentelemetry.io/otel/exporters/otlp/otlptrace` to return the OTLP trace client version. (#3956)
@ -24,6 +36,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Move No-Op implementation from `go.opentelemetry.io/otel/metric` into its own package `go.opentelemetry.io/otel/metric/noop`. (#3941)
- `metric.NewNoopMeterProvider` is replaced with `noop.NewMeterProvider`
- Wrap `UploadMetrics` error in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/` to improve error message when encountering generic grpc errors. (#3974)
- The measurement methods for all instruments in `go.opentelemetry.io/otel/metric/instrument` accept an option instead of the variadic `"go.opentelemetry.io/otel/attribute".KeyValue`. (#3971)
- The `Int64Counter.Add` method now accepts `...AddOption`
- The `Float64Counter.Add` method now accepts `...AddOption`
- The `Int64UpDownCounter.Add` method now accepts `...AddOption`
- The `Float64UpDownCounter.Add` method now accepts `...AddOption`
- The `Int64Histogram.Record` method now accepts `...RecordOption`
- The `Float64Histogram.Record` method now accepts `...RecordOption`
- The `Int64Observer.Observe` method now accepts `...ObserveOption`
- The `Float64Observer.Observe` method now accepts `...ObserveOption`
- The `Observer` methods in `go.opentelemetry.io/otel/metric` accept an option instead of the variadic `"go.opentelemetry.io/otel/attribute".KeyValue`. (#3971)
- The `Observer.ObserveInt64` method now accepts `...ObserveOption`
- The `Observer.ObserveFloat64` method now accepts `...ObserveOption`
- Move global metric back to `go.opentelemetry.io/otel/metric/global` from `go.opentelemetry.io/otel`. (#3986)
### Fixed

View File

@ -50,17 +50,17 @@ func main() {
// Start the prometheus HTTP server and pass the exporter Collector to it
go serveMetrics()
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
// This is the equivalent of prometheus.NewCounterVec
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
if err != nil {
log.Fatal(err)
}
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 5, opt)
gauge, err := meter.Float64ObservableGauge("bar", instrument.WithDescription("a fun little gauge"))
if err != nil {
@ -68,7 +68,7 @@ func main() {
}
_, err = meter.RegisterCallback(func(_ context.Context, o api.Observer) error {
n := -10. + rng.Float64()*(90.) // [-10, 100)
o.ObserveFloat64(gauge, n, attrs...)
o.ObserveFloat64(gauge, n, opt)
return nil
}, gauge)
if err != nil {
@ -80,10 +80,10 @@ func main() {
if err != nil {
log.Fatal(err)
}
histogram.Record(ctx, 23, attrs...)
histogram.Record(ctx, 7, attrs...)
histogram.Record(ctx, 101, attrs...)
histogram.Record(ctx, 105, attrs...)
histogram.Record(ctx, 23, opt)
histogram.Record(ctx, 7, opt)
histogram.Record(ctx, 101, opt)
histogram.Record(ctx, 105, opt)
ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
<-ctx.Done()

View File

@ -64,25 +64,25 @@ func main() {
// Start the prometheus HTTP server and pass the exporter Collector to it
go serveMetrics()
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
if err != nil {
log.Fatal(err)
}
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 5, opt)
histogram, err := meter.Float64Histogram("custom_histogram", instrument.WithDescription("a histogram with custom buckets and rename"))
if err != nil {
log.Fatal(err)
}
histogram.Record(ctx, 136, attrs...)
histogram.Record(ctx, 64, attrs...)
histogram.Record(ctx, 701, attrs...)
histogram.Record(ctx, 830, attrs...)
histogram.Record(ctx, 136, opt)
histogram.Record(ctx, 64, opt)
histogram.Record(ctx, 701, opt)
histogram.Record(ctx, 830, opt)
ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
<-ctx.Done()

View File

@ -46,67 +46,67 @@ func TestPrometheusExporter(t *testing.T) {
name: "counter",
expectedFile: "testdata/counter.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
)
counter, err := meter.Float64Counter(
"foo",
instrument.WithDescription("a simple counter"),
instrument.WithUnit("ms"),
)
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
attrs2 := []attribute.KeyValue{
attrs2 := attribute.NewSet(
attribute.Key("A").String("D"),
attribute.Key("C").String("B"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
counter.Add(ctx, 5, attrs2...)
)
counter.Add(ctx, 5, instrument.WithAttributeSet(attrs2))
},
},
{
name: "gauge",
expectedFile: "testdata/gauge.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
gauge, err := meter.Float64UpDownCounter(
"bar",
instrument.WithDescription("a fun little gauge"),
instrument.WithUnit("1"),
)
require.NoError(t, err)
gauge.Add(ctx, 1.0, attrs...)
gauge.Add(ctx, -.25, attrs...)
gauge.Add(ctx, 1.0, opt)
gauge.Add(ctx, -.25, opt)
},
},
{
name: "histogram",
expectedFile: "testdata/histogram.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
histogram, err := meter.Float64Histogram(
"histogram_baz",
instrument.WithDescription("a very nice histogram"),
instrument.WithUnit("By"),
)
require.NoError(t, err)
histogram.Record(ctx, 23, attrs...)
histogram.Record(ctx, 7, attrs...)
histogram.Record(ctx, 101, attrs...)
histogram.Record(ctx, 105, attrs...)
histogram.Record(ctx, 23, opt)
histogram.Record(ctx, 7, opt)
histogram.Record(ctx, 101, opt)
histogram.Record(ctx, 105, opt)
},
},
{
@ -114,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.KeyValue{
opt := instrument.WithAttributes(
// exact match, value should be overwritten
attribute.Key("A.B").String("X"),
attribute.Key("A.B").String("Q"),
@ -122,7 +122,7 @@ func TestPrometheusExporter(t *testing.T) {
// unintended match due to sanitization, values should be concatenated
attribute.Key("C.D").String("Y"),
attribute.Key("C/D").String("Z"),
}
)
counter, err := meter.Float64Counter(
"foo",
instrument.WithDescription("a sanitary counter"),
@ -130,37 +130,37 @@ func TestPrometheusExporter(t *testing.T) {
instrument.WithUnit("By"),
)
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
},
},
{
name: "invalid instruments are renamed",
expectedFile: "testdata/sanitized_names.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
// Valid.
gauge, err := meter.Float64UpDownCounter("bar", instrument.WithDescription("a fun little gauge"))
require.NoError(t, err)
gauge.Add(ctx, 100, attrs...)
gauge.Add(ctx, -25, attrs...)
gauge.Add(ctx, 100, opt)
gauge.Add(ctx, -25, opt)
// Invalid, will be renamed.
gauge, err = meter.Float64UpDownCounter("invalid.gauge.name", instrument.WithDescription("a gauge with an invalid name"))
require.NoError(t, err)
gauge.Add(ctx, 100, attrs...)
gauge.Add(ctx, 100, opt)
counter, err := meter.Float64Counter("0invalid.counter.name", instrument.WithDescription("a counter with an invalid name"))
require.NoError(t, err)
counter.Add(ctx, 100, attrs...)
counter.Add(ctx, 100, opt)
histogram, err := meter.Float64Histogram("invalid.hist.name", instrument.WithDescription("a histogram with an invalid name"))
require.NoError(t, err)
histogram.Record(ctx, 23, attrs...)
histogram.Record(ctx, 23, opt)
},
},
{
@ -168,17 +168,17 @@ func TestPrometheusExporter(t *testing.T) {
emptyResource: true,
expectedFile: "testdata/empty_resource.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
},
},
{
@ -189,17 +189,17 @@ func TestPrometheusExporter(t *testing.T) {
},
expectedFile: "testdata/custom_resource.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
},
},
{
@ -207,17 +207,17 @@ func TestPrometheusExporter(t *testing.T) {
options: []Option{WithoutTargetInfo()},
expectedFile: "testdata/without_target_info.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
},
},
{
@ -225,18 +225,18 @@ func TestPrometheusExporter(t *testing.T) {
options: []Option{WithoutScopeInfo()},
expectedFile: "testdata/without_scope_info.txt",
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
gauge, err := meter.Int64UpDownCounter(
"bar",
instrument.WithDescription("a fun little gauge"),
instrument.WithUnit("1"),
)
require.NoError(t, err)
gauge.Add(ctx, 2, attrs...)
gauge.Add(ctx, -1, attrs...)
gauge.Add(ctx, 2, opt)
gauge.Add(ctx, -1, opt)
},
},
{
@ -244,18 +244,18 @@ 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.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
}
)
counter, err := meter.Int64Counter(
"bar",
instrument.WithDescription("a fun little counter"),
instrument.WithUnit("By"),
)
require.NoError(t, err)
counter.Add(ctx, 2, attrs...)
counter.Add(ctx, 1, attrs...)
counter.Add(ctx, 2, opt)
counter.Add(ctx, 1, opt)
},
},
{
@ -265,17 +265,17 @@ func TestPrometheusExporter(t *testing.T) {
WithNamespace("test"),
},
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
attrs := []attribute.KeyValue{
opt := instrument.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
}
)
counter, err := meter.Float64Counter("foo", instrument.WithDescription("a simple counter"))
require.NoError(t, err)
counter.Add(ctx, 5, attrs...)
counter.Add(ctx, 10.3, attrs...)
counter.Add(ctx, 9, attrs...)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)
},
},
}
@ -388,7 +388,7 @@ func TestMultiScopes(t *testing.T) {
instrument.WithUnit("ms"),
instrument.WithDescription("meter foo counter"))
assert.NoError(t, err)
fooCounter.Add(ctx, 100, attribute.String("type", "foo"))
fooCounter.Add(ctx, 100, instrument.WithAttributes(attribute.String("type", "foo")))
barCounter, err := provider.Meter("meterbar", otelmetric.WithInstrumentationVersion("v0.1.0")).
Int64Counter(
@ -396,7 +396,7 @@ func TestMultiScopes(t *testing.T) {
instrument.WithUnit("ms"),
instrument.WithDescription("meter bar counter"))
assert.NoError(t, err)
barCounter.Add(ctx, 200, attribute.String("type", "bar"))
barCounter.Add(ctx, 200, instrument.WithAttributes(attribute.String("type", "bar")))
file, err := os.Open("testdata/multi_scopes.txt")
require.NoError(t, err)
@ -407,6 +407,12 @@ func TestMultiScopes(t *testing.T) {
}
func TestDuplicateMetrics(t *testing.T) {
ab := attribute.NewSet(attribute.String("A", "B"))
withAB := instrument.WithAttributeSet(ab)
typeBar := attribute.NewSet(attribute.String("type", "bar"))
withTypeBar := instrument.WithAttributeSet(typeBar)
typeFoo := attribute.NewSet(attribute.String("type", "foo"))
withTypeFoo := instrument.WithAttributeSet(typeFoo)
testCases := []struct {
name string
customResouceAttrs []attribute.KeyValue
@ -421,13 +427,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter counter foo"))
assert.NoError(t, err)
fooA.Add(ctx, 100, attribute.String("A", "B"))
fooA.Add(ctx, 100, withAB)
fooB, err := meterB.Int64Counter("foo",
instrument.WithUnit("By"),
instrument.WithDescription("meter counter foo"))
assert.NoError(t, err)
fooB.Add(ctx, 100, attribute.String("A", "B"))
fooB.Add(ctx, 100, withAB)
},
possibleExpectedFiles: []string{"testdata/no_conflict_two_counters.txt"},
},
@ -438,13 +444,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter gauge foo"))
assert.NoError(t, err)
fooA.Add(ctx, 100, attribute.String("A", "B"))
fooA.Add(ctx, 100, withAB)
fooB, err := meterB.Int64UpDownCounter("foo",
instrument.WithUnit("By"),
instrument.WithDescription("meter gauge foo"))
assert.NoError(t, err)
fooB.Add(ctx, 100, attribute.String("A", "B"))
fooB.Add(ctx, 100, withAB)
},
possibleExpectedFiles: []string{"testdata/no_conflict_two_updowncounters.txt"},
},
@ -455,13 +461,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter histogram foo"))
assert.NoError(t, err)
fooA.Record(ctx, 100, attribute.String("A", "B"))
fooA.Record(ctx, 100, withAB)
fooB, err := meterB.Int64Histogram("foo",
instrument.WithUnit("By"),
instrument.WithDescription("meter histogram foo"))
assert.NoError(t, err)
fooB.Record(ctx, 100, attribute.String("A", "B"))
fooB.Record(ctx, 100, withAB)
},
possibleExpectedFiles: []string{"testdata/no_conflict_two_histograms.txt"},
},
@ -472,13 +478,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter a bar"))
assert.NoError(t, err)
barA.Add(ctx, 100, attribute.String("type", "bar"))
barA.Add(ctx, 100, withTypeBar)
barB, err := meterB.Int64Counter("bar",
instrument.WithUnit("By"),
instrument.WithDescription("meter b bar"))
assert.NoError(t, err)
barB.Add(ctx, 100, attribute.String("type", "bar"))
barB.Add(ctx, 100, withTypeBar)
},
possibleExpectedFiles: []string{
"testdata/conflict_help_two_counters_1.txt",
@ -492,13 +498,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter a bar"))
assert.NoError(t, err)
barA.Add(ctx, 100, attribute.String("type", "bar"))
barA.Add(ctx, 100, withTypeBar)
barB, err := meterB.Int64UpDownCounter("bar",
instrument.WithUnit("By"),
instrument.WithDescription("meter b bar"))
assert.NoError(t, err)
barB.Add(ctx, 100, attribute.String("type", "bar"))
barB.Add(ctx, 100, withTypeBar)
},
possibleExpectedFiles: []string{
"testdata/conflict_help_two_updowncounters_1.txt",
@ -512,13 +518,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter a bar"))
assert.NoError(t, err)
barA.Record(ctx, 100, attribute.String("A", "B"))
barA.Record(ctx, 100, withAB)
barB, err := meterB.Int64Histogram("bar",
instrument.WithUnit("By"),
instrument.WithDescription("meter b bar"))
assert.NoError(t, err)
barB.Record(ctx, 100, attribute.String("A", "B"))
barB.Record(ctx, 100, withAB)
},
possibleExpectedFiles: []string{
"testdata/conflict_help_two_histograms_1.txt",
@ -532,13 +538,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter bar"))
assert.NoError(t, err)
bazA.Add(ctx, 100, attribute.String("type", "bar"))
bazA.Add(ctx, 100, withTypeBar)
bazB, err := meterB.Int64Counter("bar",
instrument.WithUnit("ms"),
instrument.WithDescription("meter bar"))
assert.NoError(t, err)
bazB.Add(ctx, 100, attribute.String("type", "bar"))
bazB.Add(ctx, 100, withTypeBar)
},
options: []Option{WithoutUnits()},
possibleExpectedFiles: []string{"testdata/conflict_unit_two_counters.txt"},
@ -550,13 +556,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter gauge bar"))
assert.NoError(t, err)
barA.Add(ctx, 100, attribute.String("type", "bar"))
barA.Add(ctx, 100, withTypeBar)
barB, err := meterB.Int64UpDownCounter("bar",
instrument.WithUnit("ms"),
instrument.WithDescription("meter gauge bar"))
assert.NoError(t, err)
barB.Add(ctx, 100, attribute.String("type", "bar"))
barB.Add(ctx, 100, withTypeBar)
},
options: []Option{WithoutUnits()},
possibleExpectedFiles: []string{"testdata/conflict_unit_two_updowncounters.txt"},
@ -568,13 +574,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter histogram bar"))
assert.NoError(t, err)
barA.Record(ctx, 100, attribute.String("A", "B"))
barA.Record(ctx, 100, withAB)
barB, err := meterB.Int64Histogram("bar",
instrument.WithUnit("ms"),
instrument.WithDescription("meter histogram bar"))
assert.NoError(t, err)
barB.Record(ctx, 100, attribute.String("A", "B"))
barB.Record(ctx, 100, withAB)
},
options: []Option{WithoutUnits()},
possibleExpectedFiles: []string{"testdata/conflict_unit_two_histograms.txt"},
@ -586,13 +592,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter foo"))
assert.NoError(t, err)
counter.Add(ctx, 100, attribute.String("type", "foo"))
counter.Add(ctx, 100, withTypeFoo)
gauge, err := meterA.Int64UpDownCounter("foo_total",
instrument.WithUnit("By"),
instrument.WithDescription("meter foo"))
assert.NoError(t, err)
gauge.Add(ctx, 200, attribute.String("type", "foo"))
gauge.Add(ctx, 200, withTypeFoo)
},
options: []Option{WithoutUnits()},
possibleExpectedFiles: []string{
@ -607,13 +613,13 @@ func TestDuplicateMetrics(t *testing.T) {
instrument.WithUnit("By"),
instrument.WithDescription("meter gauge foo"))
assert.NoError(t, err)
fooA.Add(ctx, 100, attribute.String("A", "B"))
fooA.Add(ctx, 100, withAB)
fooHistogramA, err := meterA.Int64Histogram("foo",
instrument.WithUnit("By"),
instrument.WithDescription("meter histogram foo"))
assert.NoError(t, err)
fooHistogramA.Record(ctx, 100, attribute.String("A", "B"))
fooHistogramA.Record(ctx, 100, withAB)
},
possibleExpectedFiles: []string{
"testdata/conflict_type_histogram_and_updowncounter_1.txt",

View File

@ -63,7 +63,7 @@ func ExampleMeter_asynchronous_single() {
//
// For demonstration purpose, a static value is used here.
usage := 75000
obsrv.Observe(int64(usage), attribute.Int("disk.id", 3))
obsrv.Observe(int64(usage), instrument.WithAttributes(attribute.Int("disk.id", 3)))
return nil
}),
)

View File

@ -17,7 +17,6 @@ package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -207,8 +206,8 @@ type Float64ObservableGaugeOption interface {
type Float64Observer interface {
embedded.Float64Observer
// Observe records the float64 value with attributes.
Observe(value float64, attributes ...attribute.KeyValue)
// Observe records the float64 value.
Observe(value float64, opts ...ObserveOption)
}
// Float64Callback is a function registered with a Meter that makes

View File

@ -21,7 +21,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -89,6 +88,6 @@ type float64Observer struct {
got float64
}
func (o *float64Observer) Observe(v float64, _ ...attribute.KeyValue) {
func (o *float64Observer) Observe(v float64, _ ...ObserveOption) {
o.got = v
}

View File

@ -17,7 +17,6 @@ package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -206,8 +205,8 @@ type Int64ObservableGaugeOption interface {
type Int64Observer interface {
embedded.Int64Observer
// Observe records the int64 value with attributes.
Observe(value int64, attributes ...attribute.KeyValue)
// Observe records the int64 value.
Observe(value int64, opts ...ObserveOption)
}
// Int64Callback is a function registered with a Meter that makes observations

View File

@ -21,7 +21,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -89,6 +88,6 @@ type int64Observer struct {
got int64
}
func (o *int64Observer) Observe(v int64, _ ...attribute.KeyValue) {
func (o *int64Observer) Observe(v int64, _ ...ObserveOption) {
o.got = v
}

View File

@ -14,6 +14,8 @@
package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import "go.opentelemetry.io/otel/attribute"
// Observable is used as a grouping mechanism for all instruments that are
// updated within a Callback.
type Observable interface {
@ -166,3 +168,165 @@ func (o unitOpt) applyInt64ObservableGauge(c Int64ObservableGaugeConfig) Int64Ob
// WithUnit sets the instrument unit.
func WithUnit(u string) Option { return unitOpt(u) }
// AddOption applies options to an addition measurement. See
// [MeasurementOption] for other options that can be used as a AddOption.
type AddOption interface {
applyAdd(AddConfig) AddConfig
}
// AddConfig contains options for an addition measurement.
type AddConfig struct {
attrs attribute.Set
}
// NewAddConfig returns a new [AddConfig] with all opts applied.
func NewAddConfig(opts []AddOption) AddConfig {
config := AddConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyAdd(config)
}
return config
}
// Attributes returns the configured attribute set.
func (c AddConfig) Attributes() attribute.Set {
return c.attrs
}
// RecordOption applies options to an addition measurement. See
// [MeasurementOption] for other options that can be used as a RecordOption.
type RecordOption interface {
applyRecord(RecordConfig) RecordConfig
}
// RecordConfig contains options for a recorded measurement.
type RecordConfig struct {
attrs attribute.Set
}
// NewRecordConfig returns a new [RecordConfig] with all opts applied.
func NewRecordConfig(opts []RecordOption) RecordConfig {
config := RecordConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyRecord(config)
}
return config
}
// Attributes returns the configured attribute set.
func (c RecordConfig) Attributes() attribute.Set {
return c.attrs
}
// ObserveOption applies options to an addition measurement. See
// [MeasurementOption] for other options that can be used as a ObserveOption.
type ObserveOption interface {
applyObserve(ObserveConfig) ObserveConfig
}
// ObserveConfig contains options for an observed measurement.
type ObserveConfig struct {
attrs attribute.Set
}
// NewObserveConfig returns a new [ObserveConfig] with all opts applied.
func NewObserveConfig(opts []ObserveOption) ObserveConfig {
config := ObserveConfig{attrs: *attribute.EmptySet()}
for _, o := range opts {
config = o.applyObserve(config)
}
return config
}
// Attributes returns the configured attribute set.
func (c ObserveConfig) Attributes() attribute.Set {
return c.attrs
}
// MeasurementOption applies options to all instrument measurement.
type MeasurementOption interface {
AddOption
RecordOption
ObserveOption
}
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 {
// 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) applyAdd(c AddConfig) AddConfig {
switch {
case o.set.Len() == 0:
case c.attrs.Len() == 0:
c.attrs = o.set
default:
c.attrs = mergeSets(c.attrs, o.set)
}
return c
}
func (o attrOpt) applyRecord(c RecordConfig) RecordConfig {
switch {
case o.set.Len() == 0:
case c.attrs.Len() == 0:
c.attrs = o.set
default:
c.attrs = mergeSets(c.attrs, o.set)
}
return c
}
func (o attrOpt) applyObserve(c ObserveConfig) ObserveConfig {
switch {
case o.set.Len() == 0:
case c.attrs.Len() == 0:
c.attrs = o.set
default:
c.attrs = mergeSets(c.attrs, o.set)
}
return c
}
// 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}
}
// WithAttributes converts attributes into an attribute Set and sets the Set to
// be associated with a measurement. This is shorthand for:
//
// cp := make([]attribute.KeyValue, len(attributes))
// copy(cp, attributes)
// WithAttributes(attribute.NewSet(cp...))
//
// [attribute.NewSet] may modify the passed attributes so this will make a copy
// of attributes before creating a set in order to ensure this function is
// concurrent safe. This makes this option function less optimized in
// comparison to [WithAttributeSet]. Therefore, [WithAttributeSet] should be
// preferred for performance sensitive code.
//
// See [WithAttributeSet] for information about how multiple WithAttributes are
// merged.
func WithAttributes(attributes ...attribute.KeyValue) MeasurementOption {
cp := make([]attribute.KeyValue, len(attributes))
copy(cp, attributes)
return attrOpt{set: attribute.NewSet(cp...)}
}

View File

@ -0,0 +1,152 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel/attribute"
)
type attrConf interface {
Attributes() attribute.Set
}
func TestConfigAttrs(t *testing.T) {
t.Run("AddConfig", testConfAttr(func(mo ...MeasurementOption) attrConf {
opts := make([]AddOption, len(mo))
for i := range mo {
opts[i] = mo[i].(AddOption)
}
return NewAddConfig(opts)
}))
t.Run("RecordConfig", testConfAttr(func(mo ...MeasurementOption) attrConf {
opts := make([]RecordOption, len(mo))
for i := range mo {
opts[i] = mo[i].(RecordOption)
}
return NewRecordConfig(opts)
}))
t.Run("ObserveConfig", testConfAttr(func(mo ...MeasurementOption) attrConf {
opts := make([]ObserveOption, len(mo))
for i := range mo {
opts[i] = mo[i].(ObserveOption)
}
return NewObserveConfig(opts)
}))
}
func testConfAttr(newConf func(...MeasurementOption) attrConf) func(t *testing.T) {
return func(t *testing.T) {
t.Run("ZeroConfigEmpty", func(t *testing.T) {
c := newConf()
assert.Equal(t, *attribute.EmptySet(), c.Attributes())
})
t.Run("EmptySet", func(t *testing.T) {
c := newConf(WithAttributeSet(*attribute.EmptySet()))
assert.Equal(t, *attribute.EmptySet(), c.Attributes())
})
aliceAttr := attribute.String("user", "Alice")
alice := attribute.NewSet(aliceAttr)
t.Run("SingleWithAttributeSet", func(t *testing.T) {
c := newConf(WithAttributeSet(alice))
assert.Equal(t, alice, c.Attributes())
})
t.Run("SingleWithAttributes", func(t *testing.T) {
c := newConf(WithAttributes(aliceAttr))
assert.Equal(t, alice, c.Attributes())
})
bobAttr := attribute.String("user", "Bob")
bob := attribute.NewSet(bobAttr)
t.Run("MultiWithAttributeSet", func(t *testing.T) {
c := newConf(WithAttributeSet(alice), WithAttributeSet(bob))
assert.Equal(t, bob, c.Attributes())
})
t.Run("MergedWithAttributes", func(t *testing.T) {
c := newConf(WithAttributes(aliceAttr, bobAttr))
assert.Equal(t, bob, c.Attributes())
})
t.Run("MultiWithAttributeSet", func(t *testing.T) {
c := newConf(WithAttributes(aliceAttr), WithAttributes(bobAttr))
assert.Equal(t, bob, c.Attributes())
})
t.Run("MergedEmpty", func(t *testing.T) {
c := newConf(WithAttributeSet(alice), WithAttributeSet(*attribute.EmptySet()))
assert.Equal(t, alice, c.Attributes())
})
}
}
func TestWithAttributesRace(t *testing.T) {
attrs := []attribute.KeyValue{
attribute.String("user", "Alice"),
attribute.Bool("admin", true),
attribute.String("user", "Bob"),
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
opt := []AddOption{WithAttributes(attrs...)}
_ = NewAddConfig(opt)
}()
wg.Add(1)
go func() {
defer wg.Done()
opt := []AddOption{WithAttributes(attrs...)}
_ = NewAddConfig(opt)
}()
wg.Add(1)
go func() {
defer wg.Done()
opt := []RecordOption{WithAttributes(attrs...)}
_ = NewRecordConfig(opt)
}()
wg.Add(1)
go func() {
defer wg.Done()
opt := []RecordOption{WithAttributes(attrs...)}
_ = NewRecordConfig(opt)
}()
wg.Add(1)
go func() {
defer wg.Done()
opt := []ObserveOption{WithAttributes(attrs...)}
_ = NewObserveConfig(opt)
}()
wg.Add(1)
go func() {
defer wg.Done()
opt := []ObserveOption{WithAttributes(attrs...)}
_ = NewObserveConfig(opt)
}()
wg.Wait()
}

View File

@ -17,7 +17,6 @@ package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -31,7 +30,7 @@ type Float64Counter interface {
embedded.Float64Counter
// Add records a change to the counter.
Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue)
Add(ctx context.Context, incr float64, opts ...AddOption)
}
// Float64CounterConfig contains options for synchronous counter instruments that
@ -78,7 +77,7 @@ type Float64UpDownCounter interface {
embedded.Float64UpDownCounter
// Add records a change to the counter.
Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue)
Add(ctx context.Context, incr float64, opts ...AddOption)
}
// Float64UpDownCounterConfig contains options for synchronous counter
@ -126,7 +125,7 @@ type Float64Histogram interface {
embedded.Float64Histogram
// Record adds an additional value to the distribution.
Record(ctx context.Context, incr float64, attrs ...attribute.KeyValue)
Record(ctx context.Context, incr float64, opts ...RecordOption)
}
// Float64HistogramConfig contains options for synchronous counter instruments

View File

@ -17,7 +17,6 @@ package instrument // import "go.opentelemetry.io/otel/metric/instrument"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
)
@ -31,7 +30,7 @@ type Int64Counter interface {
embedded.Int64Counter
// Add records a change to the counter.
Add(ctx context.Context, incr int64, attrs ...attribute.KeyValue)
Add(ctx context.Context, incr int64, opts ...AddOption)
}
// Int64CounterConfig contains options for synchronous counter instruments that
@ -78,7 +77,7 @@ type Int64UpDownCounter interface {
embedded.Int64UpDownCounter
// Add records a change to the counter.
Add(ctx context.Context, incr int64, attrs ...attribute.KeyValue)
Add(ctx context.Context, incr int64, opts ...AddOption)
}
// Int64UpDownCounterConfig contains options for synchronous counter
@ -126,7 +125,7 @@ type Int64Histogram interface {
embedded.Int64Histogram
// Record adds an additional value to the distribution.
Record(ctx context.Context, incr int64, attrs ...attribute.KeyValue)
Record(ctx context.Context, incr int64, opts ...RecordOption)
}
// Int64HistogramConfig contains options for synchronous counter instruments

View File

@ -19,7 +19,6 @@ import (
"sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/instrument"
@ -225,9 +224,9 @@ func (i *sfCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *sfCounter) Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue) {
func (i *sfCounter) Add(ctx context.Context, incr float64, opts ...instrument.AddOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Float64Counter).Add(ctx, incr, attrs...)
ctr.(instrument.Float64Counter).Add(ctx, incr, opts...)
}
}
@ -251,9 +250,9 @@ func (i *sfUpDownCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *sfUpDownCounter) Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue) {
func (i *sfUpDownCounter) Add(ctx context.Context, incr float64, opts ...instrument.AddOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Float64UpDownCounter).Add(ctx, incr, attrs...)
ctr.(instrument.Float64UpDownCounter).Add(ctx, incr, opts...)
}
}
@ -277,9 +276,9 @@ func (i *sfHistogram) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *sfHistogram) Record(ctx context.Context, x float64, attrs ...attribute.KeyValue) {
func (i *sfHistogram) Record(ctx context.Context, x float64, opts ...instrument.RecordOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Float64Histogram).Record(ctx, x, attrs...)
ctr.(instrument.Float64Histogram).Record(ctx, x, opts...)
}
}
@ -303,9 +302,9 @@ func (i *siCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *siCounter) Add(ctx context.Context, x int64, attrs ...attribute.KeyValue) {
func (i *siCounter) Add(ctx context.Context, x int64, opts ...instrument.AddOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Int64Counter).Add(ctx, x, attrs...)
ctr.(instrument.Int64Counter).Add(ctx, x, opts...)
}
}
@ -329,9 +328,9 @@ func (i *siUpDownCounter) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *siUpDownCounter) Add(ctx context.Context, x int64, attrs ...attribute.KeyValue) {
func (i *siUpDownCounter) Add(ctx context.Context, x int64, opts ...instrument.AddOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Int64UpDownCounter).Add(ctx, x, attrs...)
ctr.(instrument.Int64UpDownCounter).Add(ctx, x, opts...)
}
}
@ -355,8 +354,8 @@ func (i *siHistogram) setDelegate(m metric.Meter) {
i.delegate.Store(ctr)
}
func (i *siHistogram) Record(ctx context.Context, x int64, attrs ...attribute.KeyValue) {
func (i *siHistogram) Record(ctx context.Context, x int64, opts ...instrument.RecordOption) {
if ctr := i.delegate.Load(); ctr != nil {
ctr.(instrument.Int64Histogram).Record(ctx, x, attrs...)
ctr.(instrument.Int64Histogram).Record(ctx, x, opts...)
}
}

View File

@ -18,18 +18,17 @@ import (
"context"
"testing"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/metric/noop"
)
func testFloat64Race(interact func(context.Context, float64, ...attribute.KeyValue), setDelegate func(metric.Meter)) {
func testFloat64Race(interact func(float64), setDelegate func(metric.Meter)) {
finish := make(chan struct{})
go func() {
for {
interact(context.Background(), 1)
interact(1)
select {
case <-finish:
return
@ -42,11 +41,11 @@ func testFloat64Race(interact func(context.Context, float64, ...attribute.KeyVal
close(finish)
}
func testInt64Race(interact func(context.Context, int64, ...attribute.KeyValue), setDelegate func(metric.Meter)) {
func testInt64Race(interact func(int64), setDelegate func(metric.Meter)) {
finish := make(chan struct{})
go func() {
for {
interact(context.Background(), 1)
interact(1)
select {
case <-finish:
return
@ -64,19 +63,19 @@ func TestAsyncInstrumentSetDelegateRace(t *testing.T) {
t.Run("Float64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) {
delegate := &afCounter{}
f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(float64) { _ = delegate.Unwrap() }
testFloat64Race(f, delegate.setDelegate)
})
t.Run("UpDownCounter", func(t *testing.T) {
delegate := &afUpDownCounter{}
f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(float64) { _ = delegate.Unwrap() }
testFloat64Race(f, delegate.setDelegate)
})
t.Run("Gauge", func(t *testing.T) {
delegate := &afGauge{}
f := func(context.Context, float64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(float64) { _ = delegate.Unwrap() }
testFloat64Race(f, delegate.setDelegate)
})
})
@ -86,19 +85,19 @@ func TestAsyncInstrumentSetDelegateRace(t *testing.T) {
t.Run("Int64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) {
delegate := &aiCounter{}
f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(int64) { _ = delegate.Unwrap() }
testInt64Race(f, delegate.setDelegate)
})
t.Run("UpDownCounter", func(t *testing.T) {
delegate := &aiUpDownCounter{}
f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(int64) { _ = delegate.Unwrap() }
testInt64Race(f, delegate.setDelegate)
})
t.Run("Gauge", func(t *testing.T) {
delegate := &aiGauge{}
f := func(context.Context, int64, ...attribute.KeyValue) { _ = delegate.Unwrap() }
f := func(int64) { _ = delegate.Unwrap() }
testInt64Race(f, delegate.setDelegate)
})
})
@ -109,17 +108,20 @@ func TestSyncInstrumentSetDelegateRace(t *testing.T) {
t.Run("Float64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) {
delegate := &sfCounter{}
testFloat64Race(delegate.Add, delegate.setDelegate)
f := func(v float64) { delegate.Add(context.Background(), v) }
testFloat64Race(f, delegate.setDelegate)
})
t.Run("UpDownCounter", func(t *testing.T) {
delegate := &sfUpDownCounter{}
testFloat64Race(delegate.Add, delegate.setDelegate)
f := func(v float64) { delegate.Add(context.Background(), v) }
testFloat64Race(f, delegate.setDelegate)
})
t.Run("Histogram", func(t *testing.T) {
delegate := &sfHistogram{}
testFloat64Race(delegate.Record, delegate.setDelegate)
f := func(v float64) { delegate.Record(context.Background(), v) }
testFloat64Race(f, delegate.setDelegate)
})
})
@ -128,17 +130,20 @@ func TestSyncInstrumentSetDelegateRace(t *testing.T) {
t.Run("Int64", func(t *testing.T) {
t.Run("Counter", func(t *testing.T) {
delegate := &siCounter{}
testInt64Race(delegate.Add, delegate.setDelegate)
f := func(v int64) { delegate.Add(context.Background(), v) }
testInt64Race(f, delegate.setDelegate)
})
t.Run("UpDownCounter", func(t *testing.T) {
delegate := &siUpDownCounter{}
testInt64Race(delegate.Add, delegate.setDelegate)
f := func(v int64) { delegate.Add(context.Background(), v) }
testInt64Race(f, delegate.setDelegate)
})
t.Run("Histogram", func(t *testing.T) {
delegate := &siHistogram{}
testInt64Race(delegate.Record, delegate.setDelegate)
f := func(v int64) { delegate.Record(context.Background(), v) }
testInt64Race(f, delegate.setDelegate)
})
})
}
@ -158,10 +163,10 @@ type testCountingFloatInstrument struct {
func (i *testCountingFloatInstrument) observe() {
i.count++
}
func (i *testCountingFloatInstrument) Add(context.Context, float64, ...attribute.KeyValue) {
func (i *testCountingFloatInstrument) Add(context.Context, float64, ...instrument.AddOption) {
i.count++
}
func (i *testCountingFloatInstrument) Record(context.Context, float64, ...attribute.KeyValue) {
func (i *testCountingFloatInstrument) Record(context.Context, float64, ...instrument.RecordOption) {
i.count++
}
@ -180,9 +185,9 @@ type testCountingIntInstrument struct {
func (i *testCountingIntInstrument) observe() {
i.count++
}
func (i *testCountingIntInstrument) Add(context.Context, int64, ...attribute.KeyValue) {
func (i *testCountingIntInstrument) Add(context.Context, int64, ...instrument.AddOption) {
i.count++
}
func (i *testCountingIntInstrument) Record(context.Context, int64, ...attribute.KeyValue) {
func (i *testCountingIntInstrument) Record(context.Context, int64, ...instrument.RecordOption) {
i.count++
}

View File

@ -17,7 +17,6 @@ package global // import "go.opentelemetry.io/otel/metric/internal/global"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/instrument"
@ -157,14 +156,14 @@ type observationRecorder struct {
ctx context.Context
}
func (o observationRecorder) ObserveFloat64(i instrument.Float64Observable, value float64, attr ...attribute.KeyValue) {
func (o observationRecorder) ObserveFloat64(i instrument.Float64Observable, value float64, _ ...instrument.ObserveOption) {
iImpl, ok := i.(*testCountingFloatInstrument)
if ok {
iImpl.observe()
}
}
func (o observationRecorder) ObserveInt64(i instrument.Int64Observable, value int64, attr ...attribute.KeyValue) {
func (o observationRecorder) ObserveInt64(i instrument.Int64Observable, value int64, _ ...instrument.ObserveOption) {
iImpl, ok := i.(*testCountingIntInstrument)
if ok {
iImpl.observe()

View File

@ -17,7 +17,6 @@ package metric // import "go.opentelemetry.io/otel/metric"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/instrument"
)
@ -141,10 +140,10 @@ type Callback func(context.Context, Observer) error
type Observer interface {
embedded.Observer
// ObserveFloat64 records the float64 value with attributes for obsrv.
ObserveFloat64(obsrv instrument.Float64Observable, value float64, attributes ...attribute.KeyValue)
// ObserveInt64 records the int64 value with attributes for obsrv.
ObserveInt64(obsrv instrument.Int64Observable, value int64, attributes ...attribute.KeyValue)
// ObserveFloat64 records the float64 value for obsrv.
ObserveFloat64(obsrv instrument.Float64Observable, value float64, opts ...instrument.ObserveOption)
// ObserveInt64 records the int64 value for obsrv.
ObserveInt64(obsrv instrument.Int64Observable, value int64, opts ...instrument.ObserveOption)
}
// Registration is an token representing the unique registration of a callback

View File

@ -26,7 +26,6 @@ package noop // import "go.opentelemetry.io/otel/metric/noop"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/metric/instrument"
@ -153,11 +152,11 @@ func (Meter) RegisterCallback(metric.Callback, ...instrument.Observable) (metric
type Observer struct{ embedded.Observer }
// ObserveFloat64 performs no operation.
func (Observer) ObserveFloat64(instrument.Float64Observable, float64, ...attribute.KeyValue) {
func (Observer) ObserveFloat64(instrument.Float64Observable, float64, ...instrument.ObserveOption) {
}
// ObserveInt64 performs no operation.
func (Observer) ObserveInt64(instrument.Int64Observable, int64, ...attribute.KeyValue) {
func (Observer) ObserveInt64(instrument.Int64Observable, int64, ...instrument.ObserveOption) {
}
// Registration is the registration of a Callback with a No-Op Meter.
@ -173,42 +172,42 @@ func (Registration) Unregister() error { return nil }
type Int64Counter struct{ embedded.Int64Counter }
// Add performs no operation.
func (Int64Counter) Add(context.Context, int64, ...attribute.KeyValue) {}
func (Int64Counter) Add(context.Context, int64, ...instrument.AddOption) {}
// Float64Counter is an OpenTelemetry Counter used to record float64
// measurements. It produces no telemetry.
type Float64Counter struct{ embedded.Float64Counter }
// Add performs no operation.
func (Float64Counter) Add(context.Context, float64, ...attribute.KeyValue) {}
func (Float64Counter) Add(context.Context, float64, ...instrument.AddOption) {}
// Int64UpDownCounter is an OpenTelemetry UpDownCounter used to record int64
// measurements. It produces no telemetry.
type Int64UpDownCounter struct{ embedded.Int64UpDownCounter }
// Add performs no operation.
func (Int64UpDownCounter) Add(context.Context, int64, ...attribute.KeyValue) {}
func (Int64UpDownCounter) Add(context.Context, int64, ...instrument.AddOption) {}
// Float64UpDownCounter is an OpenTelemetry UpDownCounter used to record
// float64 measurements. It produces no telemetry.
type Float64UpDownCounter struct{ embedded.Float64UpDownCounter }
// Add performs no operation.
func (Float64UpDownCounter) Add(context.Context, float64, ...attribute.KeyValue) {}
func (Float64UpDownCounter) Add(context.Context, float64, ...instrument.AddOption) {}
// Int64Histogram is an OpenTelemetry Histogram used to record int64
// measurements. It produces no telemetry.
type Int64Histogram struct{ embedded.Int64Histogram }
// Record performs no operation.
func (Int64Histogram) Record(context.Context, int64, ...attribute.KeyValue) {}
func (Int64Histogram) Record(context.Context, int64, ...instrument.RecordOption) {}
// Float64Histogram is an OpenTelemetry Histogram used to record float64
// measurements. It produces no telemetry.
type Float64Histogram struct{ embedded.Float64Histogram }
// Record performs no operation.
func (Float64Histogram) Record(context.Context, float64, ...attribute.KeyValue) {}
func (Float64Histogram) Record(context.Context, float64, ...instrument.RecordOption) {}
// Int64ObservableCounter is an OpenTelemetry ObservableCounter used to record
// int64 measurements. It produces no telemetry.
@ -256,11 +255,11 @@ type Float64ObservableUpDownCounter struct {
type Int64Observer struct{ embedded.Int64Observer }
// Observe performs no operation.
func (Int64Observer) Observe(int64, ...attribute.KeyValue) {}
func (Int64Observer) Observe(int64, ...instrument.ObserveOption) {}
// Float64Observer is a recorder of float64 measurements that performs no
// operation.
type Float64Observer struct{ embedded.Float64Observer }
// Observe performs no operation.
func (Float64Observer) Observe(float64, ...attribute.KeyValue) {}
func (Float64Observer) Observe(float64, ...instrument.ObserveOption) {}

View File

@ -66,59 +66,65 @@ func benchSyncViews(views ...View) func(*testing.B) {
iCtr, err := meter.Int64Counter("int64-counter")
assert.NoError(b, err)
b.Run("Int64Counter", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { iCtr.Add(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.AddOption{instrument.WithAttributeSet(s)}
return func() { iCtr.Add(ctx, 1, o...) }
}
}()))
fCtr, err := meter.Float64Counter("float64-counter")
assert.NoError(b, err)
b.Run("Float64Counter", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { fCtr.Add(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.AddOption{instrument.WithAttributeSet(s)}
return func() { fCtr.Add(ctx, 1, o...) }
}
}()))
iUDCtr, err := meter.Int64UpDownCounter("int64-up-down-counter")
assert.NoError(b, err)
b.Run("Int64UpDownCounter", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { iUDCtr.Add(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.AddOption{instrument.WithAttributeSet(s)}
return func() { iUDCtr.Add(ctx, 1, o...) }
}
}()))
fUDCtr, err := meter.Float64UpDownCounter("float64-up-down-counter")
assert.NoError(b, err)
b.Run("Float64UpDownCounter", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { fUDCtr.Add(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.AddOption{instrument.WithAttributeSet(s)}
return func() { fUDCtr.Add(ctx, 1, o...) }
}
}()))
iHist, err := meter.Int64Histogram("int64-histogram")
assert.NoError(b, err)
b.Run("Int64Histogram", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { iHist.Record(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.RecordOption{instrument.WithAttributeSet(s)}
return func() { iHist.Record(ctx, 1, o...) }
}
}()))
fHist, err := meter.Float64Histogram("float64-histogram")
assert.NoError(b, err)
b.Run("Float64Histogram", benchMeasAttrs(func() measF {
return func(attr []attribute.KeyValue) func() {
return func() { fHist.Record(ctx, 1, attr...) }
return func(s attribute.Set) func() {
o := []instrument.RecordOption{instrument.WithAttributeSet(s)}
return func() { fHist.Record(ctx, 1, o...) }
}
}()))
}
}
type measF func(attr []attribute.KeyValue) func()
type measF func(s attribute.Set) func()
func benchMeasAttrs(meas measF) func(*testing.B) {
return func(b *testing.B) {
b.Run("Attributes/0", func(b *testing.B) {
f := meas(nil)
f := meas(*attribute.EmptySet())
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
@ -126,8 +132,7 @@ func benchMeasAttrs(meas measF) func(*testing.B) {
}
})
b.Run("Attributes/1", func(b *testing.B) {
attrs := []attribute.KeyValue{attribute.Bool("K", true)}
f := meas(attrs)
f := meas(attribute.NewSet(attribute.Bool("K", true)))
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
@ -141,7 +146,7 @@ func benchMeasAttrs(meas measF) func(*testing.B) {
for i := 2; i < n; i++ {
attrs = append(attrs, attribute.Int(strconv.Itoa(i), i))
}
f := meas(attrs)
f := meas(attribute.NewSet(attrs...))
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
@ -165,163 +170,163 @@ func benchCollectViews(views ...View) func(*testing.B) {
}
ctx := context.Background()
return func(b *testing.B) {
b.Run("Int64Counter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64Counter/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64Counter")
i, err := m.Int64Counter("int64-counter")
assert.NoError(b, err)
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Int64Counter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64Counter/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64Counter")
i, err := m.Int64Counter("int64-counter")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Float64Counter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64Counter/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64Counter")
i, err := m.Float64Counter("float64-counter")
assert.NoError(b, err)
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Float64Counter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64Counter/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64Counter")
i, err := m.Float64Counter("float64-counter")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Int64UpDownCounter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64UpDownCounter/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64UpDownCounter")
i, err := m.Int64UpDownCounter("int64-up-down-counter")
assert.NoError(b, err)
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Int64UpDownCounter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64UpDownCounter/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64UpDownCounter")
i, err := m.Int64UpDownCounter("int64-up-down-counter")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Float64UpDownCounter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64UpDownCounter/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64UpDownCounter")
i, err := m.Float64UpDownCounter("float64-up-down-counter")
assert.NoError(b, err)
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Float64UpDownCounter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64UpDownCounter/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64UpDownCounter")
i, err := m.Float64UpDownCounter("float64-up-down-counter")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Add(ctx, 1, attr...)
i.Add(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Int64Histogram/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64Histogram/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64Histogram")
i, err := m.Int64Histogram("int64-histogram")
assert.NoError(b, err)
i.Record(ctx, 1, attr...)
i.Record(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Int64Histogram/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64Histogram/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64Histogram")
i, err := m.Int64Histogram("int64-histogram")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Record(ctx, 1, attr...)
i.Record(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Float64Histogram/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64Histogram/1", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64Histogram")
i, err := m.Float64Histogram("float64-histogram")
assert.NoError(b, err)
i.Record(ctx, 1, attr...)
i.Record(ctx, 1, instrument.WithAttributeSet(s))
return r
}))
b.Run("Float64Histogram/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64Histogram/10", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64Histogram")
i, err := m.Float64Histogram("float64-histogram")
assert.NoError(b, err)
for n := 0; n < 10; n++ {
i.Record(ctx, 1, attr...)
i.Record(ctx, 1, instrument.WithAttributeSet(s))
}
return r
}))
b.Run("Int64ObservableCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64ObservableCounter", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64ObservableCounter")
_, err := m.Int64ObservableCounter(
"int64-observable-counter",
instrument.WithInt64Callback(int64Cback(attr)),
instrument.WithInt64Callback(int64Cback(s)),
)
assert.NoError(b, err)
return r
}))
b.Run("Float64ObservableCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64ObservableCounter", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64ObservableCounter")
_, err := m.Float64ObservableCounter(
"float64-observable-counter",
instrument.WithFloat64Callback(float64Cback(attr)),
instrument.WithFloat64Callback(float64Cback(s)),
)
assert.NoError(b, err)
return r
}))
b.Run("Int64ObservableUpDownCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64ObservableUpDownCounter", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64ObservableUpDownCounter")
_, err := m.Int64ObservableUpDownCounter(
"int64-observable-up-down-counter",
instrument.WithInt64Callback(int64Cback(attr)),
instrument.WithInt64Callback(int64Cback(s)),
)
assert.NoError(b, err)
return r
}))
b.Run("Float64ObservableUpDownCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64ObservableUpDownCounter", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64ObservableUpDownCounter")
_, err := m.Float64ObservableUpDownCounter(
"float64-observable-up-down-counter",
instrument.WithFloat64Callback(float64Cback(attr)),
instrument.WithFloat64Callback(float64Cback(s)),
)
assert.NoError(b, err)
return r
}))
b.Run("Int64ObservableGauge", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Int64ObservableGauge", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Int64ObservableGauge")
_, err := m.Int64ObservableGauge(
"int64-observable-gauge",
instrument.WithInt64Callback(int64Cback(attr)),
instrument.WithInt64Callback(int64Cback(s)),
)
assert.NoError(b, err)
return r
}))
b.Run("Float64ObservableGauge", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
b.Run("Float64ObservableGauge", benchCollectAttrs(func(s attribute.Set) Reader {
m, r := setup("benchCollectViews/Float64ObservableGauge")
_, err := m.Float64ObservableGauge(
"float64-observable-gauge",
instrument.WithFloat64Callback(float64Cback(attr)),
instrument.WithFloat64Callback(float64Cback(s)),
)
assert.NoError(b, err)
return r
@ -329,21 +334,23 @@ func benchCollectViews(views ...View) func(*testing.B) {
}
}
func int64Cback(attr []attribute.KeyValue) instrument.Int64Callback {
func int64Cback(s attribute.Set) instrument.Int64Callback {
opt := []instrument.ObserveOption{instrument.WithAttributeSet(s)}
return func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(1, attr...)
o.Observe(1, opt...)
return nil
}
}
func float64Cback(attr []attribute.KeyValue) instrument.Float64Callback {
func float64Cback(s attribute.Set) instrument.Float64Callback {
opt := []instrument.ObserveOption{instrument.WithAttributeSet(s)}
return func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(1, attr...)
o.Observe(1, opt...)
return nil
}
}
func benchCollectAttrs(setup func([]attribute.KeyValue) Reader) func(*testing.B) {
func benchCollectAttrs(setup func(attribute.Set) Reader) func(*testing.B) {
ctx := context.Background()
out := new(metricdata.ResourceMetrics)
run := func(reader Reader) func(b *testing.B) {
@ -355,14 +362,14 @@ func benchCollectAttrs(setup func([]attribute.KeyValue) Reader) func(*testing.B)
}
}
return func(b *testing.B) {
b.Run("Attributes/0", run(setup(nil)))
b.Run("Attributes/0", run(setup(*attribute.EmptySet())))
attrs := []attribute.KeyValue{attribute.Bool("K", true)}
b.Run("Attributes/1", run(setup(attrs)))
b.Run("Attributes/1", run(setup(attribute.NewSet(attrs...))))
for i := 2; i < 10; i++ {
attrs = append(attrs, attribute.Int(strconv.Itoa(i), i))
}
b.Run("Attributes/10", run(setup(attrs)))
b.Run("Attributes/10", run(setup(attribute.NewSet(attrs...))))
}
}

View File

@ -170,40 +170,63 @@ type streamID struct {
Number string
}
type instrumentImpl[N int64 | float64] struct {
aggregators []internal.Aggregator[N]
type int64Inst struct {
aggregators []internal.Aggregator[int64]
embedded.Float64Counter
embedded.Float64UpDownCounter
embedded.Float64Histogram
embedded.Int64Counter
embedded.Int64UpDownCounter
embedded.Int64Histogram
}
var _ instrument.Float64Counter = (*instrumentImpl[float64])(nil)
var _ instrument.Float64UpDownCounter = (*instrumentImpl[float64])(nil)
var _ instrument.Float64Histogram = (*instrumentImpl[float64])(nil)
var _ instrument.Int64Counter = (*instrumentImpl[int64])(nil)
var _ instrument.Int64UpDownCounter = (*instrumentImpl[int64])(nil)
var _ instrument.Int64Histogram = (*instrumentImpl[int64])(nil)
var _ instrument.Int64Counter = (*int64Inst)(nil)
var _ instrument.Int64UpDownCounter = (*int64Inst)(nil)
var _ instrument.Int64Histogram = (*int64Inst)(nil)
func (i *instrumentImpl[N]) Add(ctx context.Context, val N, attrs ...attribute.KeyValue) {
i.aggregate(ctx, val, attrs)
func (i *int64Inst) Add(ctx context.Context, val int64, opts ...instrument.AddOption) {
c := instrument.NewAddConfig(opts)
i.aggregate(ctx, val, c.Attributes())
}
func (i *instrumentImpl[N]) Record(ctx context.Context, val N, attrs ...attribute.KeyValue) {
i.aggregate(ctx, val, attrs)
func (i *int64Inst) Record(ctx context.Context, val int64, opts ...instrument.RecordOption) {
c := instrument.NewRecordConfig(opts)
i.aggregate(ctx, val, c.Attributes())
}
func (i *instrumentImpl[N]) aggregate(ctx context.Context, val N, attrs []attribute.KeyValue) {
func (i *int64Inst) aggregate(ctx context.Context, val int64, s attribute.Set) {
if err := ctx.Err(); err != nil {
return
}
for _, agg := range i.aggregators {
agg.Aggregate(val, s)
}
}
type float64Inst struct {
aggregators []internal.Aggregator[float64]
embedded.Float64Counter
embedded.Float64UpDownCounter
embedded.Float64Histogram
}
var _ instrument.Float64Counter = (*float64Inst)(nil)
var _ instrument.Float64UpDownCounter = (*float64Inst)(nil)
var _ instrument.Float64Histogram = (*float64Inst)(nil)
func (i *float64Inst) Add(ctx context.Context, val float64, opts ...instrument.AddOption) {
c := instrument.NewAddConfig(opts)
i.aggregate(ctx, val, c.Attributes())
}
func (i *float64Inst) Record(ctx context.Context, val float64, opts ...instrument.RecordOption) {
c := instrument.NewRecordConfig(opts)
i.aggregate(ctx, val, c.Attributes())
}
func (i *float64Inst) aggregate(ctx context.Context, val float64, s attribute.Set) {
if err := ctx.Err(); err != nil {
return
}
// Do not use single attribute.Sortable and attribute.NewSetWithSortable,
// this method needs to be concurrent safe. Let the sync.Pool in the
// attribute package handle allocations of the Sortable.
s := attribute.NewSet(attrs...)
for _, agg := range i.aggregators {
agg.Aggregate(val, s)
}
@ -277,11 +300,7 @@ func newObservable[N int64 | float64](scope instrumentation.Scope, kind Instrume
}
// observe records the val for the set of attrs.
func (o *observable[N]) observe(val N, attrs []attribute.KeyValue) {
// Do not use single attribute.Sortable and attribute.NewSetWithSortable,
// this method needs to be concurrent safe. Let the sync.Pool in the
// attribute package handle allocations of the Sortable.
s := attribute.NewSet(attrs...)
func (o *observable[N]) observe(val N, s attribute.Set) {
for _, agg := range o.aggregators {
agg.Aggregate(val, s)
}

View File

@ -23,16 +23,16 @@ import (
)
func BenchmarkInstrument(b *testing.B) {
attr := func(id int) []attribute.KeyValue {
return []attribute.KeyValue{
attr := func(id int) attribute.Set {
return attribute.NewSet(
attribute.String("user", "Alice"),
attribute.Bool("admin", true),
attribute.Int("id", id),
}
)
}
b.Run("instrumentImpl/aggregate", func(b *testing.B) {
inst := instrumentImpl[int64]{aggregators: []internal.Aggregator[int64]{
inst := int64Inst{aggregators: []internal.Aggregator[int64]{
internal.NewLastValue[int64](),
internal.NewCumulativeSum[int64](true),
internal.NewDeltaSum[int64](true),

View File

@ -94,8 +94,8 @@ type inst struct {
embedded.Int64Histogram
}
func (inst) Add(context.Context, int64, ...attribute.KeyValue) {}
func (inst) Record(context.Context, int64, ...attribute.KeyValue) {}
func (inst) Add(context.Context, int64, ...instrument.AddOption) {}
func (inst) Record(context.Context, int64, ...instrument.RecordOption) {}
func Example() {
m := meter{}

View File

@ -19,7 +19,6 @@ import (
"errors"
"fmt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
@ -38,8 +37,8 @@ type meter struct {
scope instrumentation.Scope
pipes pipelines
int64IP *instProvider[int64]
float64IP *instProvider[float64]
int64IP *int64InstProvider
float64IP *float64InstProvider
}
func newMeter(s instrumentation.Scope, p pipelines) *meter {
@ -50,8 +49,8 @@ func newMeter(s instrumentation.Scope, p pipelines) *meter {
return &meter{
scope: s,
pipes: p,
int64IP: newInstProvider[int64](s, p, &viewCache),
float64IP: newInstProvider[float64](s, p, &viewCache),
int64IP: newInt64InstProvider(s, p, &viewCache),
float64IP: newFloat64InstProvider(s, p, &viewCache),
}
}
@ -297,7 +296,7 @@ var (
errUnregObserver = errors.New("observable instrument not registered for callback")
)
func (r observer) ObserveFloat64(o instrument.Float64Observable, v float64, a ...attribute.KeyValue) {
func (r observer) ObserveFloat64(o instrument.Float64Observable, v float64, opts ...instrument.ObserveOption) {
var oImpl float64Observable
switch conv := o.(type) {
case float64Observable:
@ -326,10 +325,11 @@ func (r observer) ObserveFloat64(o instrument.Float64Observable, v float64, a ..
)
return
}
oImpl.observe(v, a)
c := instrument.NewObserveConfig(opts)
oImpl.observe(v, c.Attributes())
}
func (r observer) ObserveInt64(o instrument.Int64Observable, v int64, a ...attribute.KeyValue) {
func (r observer) ObserveInt64(o instrument.Int64Observable, v int64, opts ...instrument.ObserveOption) {
var oImpl int64Observable
switch conv := o.(type) {
case int64Observable:
@ -358,7 +358,8 @@ func (r observer) ObserveInt64(o instrument.Int64Observable, v int64, a ...attri
)
return
}
oImpl.observe(v, a)
c := instrument.NewObserveConfig(opts)
oImpl.observe(v, c.Attributes())
}
type noopRegister struct{ embedded.Registration }
@ -367,18 +368,18 @@ func (noopRegister) Unregister() error {
return nil
}
// instProvider provides all OpenTelemetry instruments.
type instProvider[N int64 | float64] struct {
// int64InstProvider provides int64 OpenTelemetry instruments.
type int64InstProvider struct {
scope instrumentation.Scope
pipes pipelines
resolve resolver[N]
resolve resolver[int64]
}
func newInstProvider[N int64 | float64](s instrumentation.Scope, p pipelines, c *cache[string, streamID]) *instProvider[N] {
return &instProvider[N]{scope: s, pipes: p, resolve: newResolver[N](p, c)}
func newInt64InstProvider(s instrumentation.Scope, p pipelines, c *cache[string, streamID]) *int64InstProvider {
return &int64InstProvider{scope: s, pipes: p, resolve: newResolver[int64](p, c)}
}
func (p *instProvider[N]) aggs(kind InstrumentKind, name, desc, u string) ([]internal.Aggregator[N], error) {
func (p *int64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]internal.Aggregator[int64], error) {
inst := Instrument{
Name: name,
Description: desc,
@ -390,12 +391,40 @@ func (p *instProvider[N]) aggs(kind InstrumentKind, name, desc, u string) ([]int
}
// lookup returns the resolved instrumentImpl.
func (p *instProvider[N]) lookup(kind InstrumentKind, name, desc, u string) (*instrumentImpl[N], error) {
func (p *int64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*int64Inst, error) {
aggs, err := p.aggs(kind, name, desc, u)
return &instrumentImpl[N]{aggregators: aggs}, err
return &int64Inst{aggregators: aggs}, err
}
type int64ObservProvider struct{ *instProvider[int64] }
// float64InstProvider provides float64 OpenTelemetry instruments.
type float64InstProvider struct {
scope instrumentation.Scope
pipes pipelines
resolve resolver[float64]
}
func newFloat64InstProvider(s instrumentation.Scope, p pipelines, c *cache[string, streamID]) *float64InstProvider {
return &float64InstProvider{scope: s, pipes: p, resolve: newResolver[float64](p, c)}
}
func (p *float64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]internal.Aggregator[float64], error) {
inst := Instrument{
Name: name,
Description: desc,
Unit: u,
Kind: kind,
Scope: p.scope,
}
return p.resolve.Aggregators(inst)
}
// lookup returns the resolved instrumentImpl.
func (p *float64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*float64Inst, error) {
aggs, err := p.aggs(kind, name, desc, u)
return &float64Inst{aggregators: aggs}, err
}
type int64ObservProvider struct{ *int64InstProvider }
func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (int64Observable, error) {
aggs, err := p.aggs(kind, name, desc, u)
@ -423,11 +452,12 @@ type int64Observer struct {
int64Observable
}
func (o int64Observer) Observe(val int64, attrs ...attribute.KeyValue) {
o.observe(val, attrs)
func (o int64Observer) Observe(val int64, opts ...instrument.ObserveOption) {
c := instrument.NewObserveConfig(opts)
o.observe(val, c.Attributes())
}
type float64ObservProvider struct{ *instProvider[float64] }
type float64ObservProvider struct{ *float64InstProvider }
func (p float64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (float64Observable, error) {
aggs, err := p.aggs(kind, name, desc, u)
@ -455,6 +485,7 @@ type float64Observer struct {
float64Observable
}
func (o float64Observer) Observe(val float64, attrs ...attribute.KeyValue) {
o.observe(val, attrs)
func (o float64Observer) Observe(val float64, opts ...instrument.ObserveOption) {
c := instrument.NewObserveConfig(opts)
o.observe(val, c.Attributes())
}

View File

@ -169,7 +169,8 @@ func TestCallbackUnregisterConcurrency(t *testing.T) {
// Instruments should produce correct ResourceMetrics.
func TestMeterCreatesInstruments(t *testing.T) {
attrs := []attribute.KeyValue{attribute.String("name", "alice")}
attrs := attribute.NewSet(attribute.String("name", "alice"))
opt := instrument.WithAttributeSet(attrs)
testCases := []struct {
name string
fn func(*testing.T, metric.Meter)
@ -179,7 +180,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableInt64Count",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
ctr, err := m.Int64ObservableCounter("aint", instrument.WithInt64Callback(cback))
@ -196,7 +197,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 3},
},
},
@ -206,7 +207,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableInt64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
ctr, err := m.Int64ObservableUpDownCounter("aint", instrument.WithInt64Callback(cback))
@ -223,7 +224,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 11},
},
},
@ -233,7 +234,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableInt64Gauge",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Int64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
gauge, err := m.Int64ObservableGauge("agauge", instrument.WithInt64Callback(cback))
@ -248,7 +249,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Name: "agauge",
Data: metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 11},
},
},
@ -258,7 +259,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableFloat64Count",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
ctr, err := m.Float64ObservableCounter("afloat", instrument.WithFloat64Callback(cback))
@ -275,7 +276,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 3},
},
},
@ -285,7 +286,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableFloat64UpDownCount",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
ctr, err := m.Float64ObservableUpDownCounter("afloat", instrument.WithFloat64Callback(cback))
@ -302,7 +303,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: false,
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 11},
},
},
@ -312,7 +313,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
name: "ObservableFloat64Gauge",
fn: func(t *testing.T, m metric.Meter) {
cback := func(_ context.Context, o instrument.Float64Observer) error {
o.Observe(4, attrs...)
o.Observe(4, opt)
return nil
}
gauge, err := m.Float64ObservableGauge("agauge", instrument.WithFloat64Callback(cback))
@ -327,7 +328,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
Name: "agauge",
Data: metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{Attributes: attribute.NewSet(attrs...), Value: 4},
{Attributes: attrs, Value: 4},
{Value: 11},
},
},
@ -885,6 +886,12 @@ func TestAttributeFilter(t *testing.T) {
}
func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
fooBar := attribute.NewSet(attribute.String("foo", "bar"))
withFooBar := instrument.WithAttributeSet(fooBar)
v1 := attribute.NewSet(attribute.String("foo", "bar"), attribute.Int("version", 1))
withV1 := instrument.WithAttributeSet(v1)
v2 := attribute.NewSet(attribute.String("foo", "bar"), attribute.Int("version", 2))
withV2 := instrument.WithAttributeSet(v2)
testcases := []struct {
name string
register func(t *testing.T, mtr metric.Meter) error
@ -898,9 +905,9 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveFloat64(ctr, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveFloat64(ctr, 2.0, attribute.String("foo", "bar"))
o.ObserveFloat64(ctr, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveFloat64(ctr, 1.0, withV1)
o.ObserveFloat64(ctr, 2.0, withFooBar)
o.ObserveFloat64(ctr, 1.0, withV2)
return nil
}, ctr)
return err
@ -909,10 +916,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Name: "afcounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 4.0,
},
{Attributes: fooBar, Value: 4.0},
},
Temporality: temporality,
IsMonotonic: true,
@ -927,9 +931,9 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveFloat64(ctr, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveFloat64(ctr, 2.0, attribute.String("foo", "bar"))
o.ObserveFloat64(ctr, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveFloat64(ctr, 1.0, withV1)
o.ObserveFloat64(ctr, 2.0, withFooBar)
o.ObserveFloat64(ctr, 1.0, withV2)
return nil
}, ctr)
return err
@ -956,8 +960,8 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveFloat64(ctr, 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveFloat64(ctr, 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveFloat64(ctr, 1.0, withV1)
o.ObserveFloat64(ctr, 2.0, withV2)
return nil
}, ctr)
return err
@ -966,10 +970,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Name: "afgauge",
Data: metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 2.0,
},
{Attributes: fooBar, Value: 2.0},
},
},
},
@ -982,9 +983,9 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveInt64(ctr, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveInt64(ctr, 20, attribute.String("foo", "bar"))
o.ObserveInt64(ctr, 10, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveInt64(ctr, 10, withV1)
o.ObserveInt64(ctr, 20, withFooBar)
o.ObserveInt64(ctr, 10, withV2)
return nil
}, ctr)
return err
@ -993,10 +994,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Name: "aicounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 40,
},
{Attributes: fooBar, Value: 40},
},
Temporality: temporality,
IsMonotonic: true,
@ -1011,9 +1009,9 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveInt64(ctr, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveInt64(ctr, 20, attribute.String("foo", "bar"))
o.ObserveInt64(ctr, 10, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveInt64(ctr, 10, withV1)
o.ObserveInt64(ctr, 20, withFooBar)
o.ObserveInt64(ctr, 10, withV2)
return nil
}, ctr)
return err
@ -1022,10 +1020,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Name: "aiupdowncounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 40,
},
{Attributes: fooBar, Value: 40},
},
Temporality: temporality,
IsMonotonic: false,
@ -1040,8 +1035,8 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
_, err = mtr.RegisterCallback(func(_ context.Context, o metric.Observer) error {
o.ObserveInt64(ctr, 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
o.ObserveInt64(ctr, 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
o.ObserveInt64(ctr, 10, withV1)
o.ObserveInt64(ctr, 20, withV2)
return nil
}, ctr)
return err
@ -1050,10 +1045,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Name: "aigauge",
Data: metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 20,
},
{Attributes: fooBar, Value: 20},
},
},
},
@ -1066,18 +1058,15 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Add(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Add(context.Background(), 1.0, withV1)
ctr.Add(context.Background(), 2.0, withV2)
return nil
},
wantMetric: metricdata.Metrics{
Name: "sfcounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 3.0,
},
{Attributes: fooBar, Value: 3.0},
},
Temporality: temporality,
IsMonotonic: true,
@ -1092,18 +1081,15 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Add(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Add(context.Background(), 1.0, withV1)
ctr.Add(context.Background(), 2.0, withV2)
return nil
},
wantMetric: metricdata.Metrics{
Name: "sfupdowncounter",
Data: metricdata.Sum[float64]{
DataPoints: []metricdata.DataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 3.0,
},
{Attributes: fooBar, Value: 3.0},
},
Temporality: temporality,
IsMonotonic: false,
@ -1118,8 +1104,8 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Record(context.Background(), 1.0, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Record(context.Background(), 2.0, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Record(context.Background(), 1.0, withV1)
ctr.Record(context.Background(), 2.0, withV2)
return nil
},
wantMetric: metricdata.Metrics{
@ -1127,7 +1113,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Data: metricdata.Histogram[float64]{
DataPoints: []metricdata.HistogramDataPoint[float64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Attributes: fooBar,
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Count: 2,
@ -1148,18 +1134,15 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Add(context.Background(), 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Add(context.Background(), 10, withV1)
ctr.Add(context.Background(), 20, withV2)
return nil
},
wantMetric: metricdata.Metrics{
Name: "sicounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 30,
},
{Attributes: fooBar, Value: 30},
},
Temporality: temporality,
IsMonotonic: true,
@ -1174,18 +1157,15 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Add(context.Background(), 10, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Add(context.Background(), 20, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Add(context.Background(), 10, withV1)
ctr.Add(context.Background(), 20, withV2)
return nil
},
wantMetric: metricdata.Metrics{
Name: "siupdowncounter",
Data: metricdata.Sum[int64]{
DataPoints: []metricdata.DataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Value: 30,
},
{Attributes: fooBar, Value: 30},
},
Temporality: temporality,
IsMonotonic: false,
@ -1200,8 +1180,8 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
return err
}
ctr.Record(context.Background(), 1, attribute.String("foo", "bar"), attribute.Int("version", 1))
ctr.Record(context.Background(), 2, attribute.String("foo", "bar"), attribute.Int("version", 2))
ctr.Record(context.Background(), 1, withV1)
ctr.Record(context.Background(), 2, withV2)
return nil
},
wantMetric: metricdata.Metrics{
@ -1209,7 +1189,7 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
Data: metricdata.Histogram[int64]{
DataPoints: []metricdata.HistogramDataPoint[int64]{
{
Attributes: attribute.NewSet(attribute.String("foo", "bar")),
Attributes: fooBar,
Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Count: 2,
@ -1296,7 +1276,7 @@ func TestObservableExample(t *testing.T) {
_, err := meter.Int64ObservableCounter(instName, instrument.WithInt64Callback(
func(_ context.Context, o instrument.Int64Observer) error {
for attrSet, val := range observations {
o.Observe(val, attrSet.ToSlice()...)
o.Observe(val, instrument.WithAttributeSet(attrSet))
}
return nil
},