From 30c0f3fa6efc1f73657087e610b608dbadcb1805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Tue, 29 Oct 2024 13:47:14 +0100 Subject: [PATCH] sdk/instrumentation: Add Attributes to Scope (#5903) Towards https://github.com/open-telemetry/opentelemetry-go/issues/3368 --- CHANGELOG.md | 1 + exporters/stdout/stdoutlog/exporter_test.go | 5 +++-- exporters/stdout/stdoutmetric/example_test.go | 3 ++- exporters/stdout/stdouttrace/trace_test.go | 6 ++++-- sdk/instrumentation/scope.go | 4 ++++ sdk/log/provider_test.go | 14 +++++++++----- sdk/metric/provider_test.go | 2 ++ sdk/trace/provider_test.go | 15 +++++++++++++++ sdk/trace/trace_test.go | 6 +++++- 9 files changed, 45 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8eb772a62a..2bf75a3cdcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add `ReservoirProvider`, `HistogramReservoirProvider` and `FixedSizeReservoirProvider` to `go.opentelemetry.io/otel/sdk/metric/exemplar` to make it convenient to use providers of Reservoirs. (#5861) - The `go.opentelemetry.io/otel/semconv/v1.27.0` package. The package contains semantic conventions from the `v1.27.0` version of the OpenTelemetry Semantic Conventions. (#5894) +- Add `Attributes attribute.Set` field to `Scope` in `go.opentelemetry.io/otel/sdk/instrumentation`. (#5903) ### Fixed diff --git a/exporters/stdout/stdoutlog/exporter_test.go b/exporters/stdout/stdoutlog/exporter_test.go index 368a663a687..99fd480727f 100644 --- a/exporters/stdout/stdoutlog/exporter_test.go +++ b/exporters/stdout/stdoutlog/exporter_test.go @@ -183,7 +183,7 @@ func getJSON(now *time.Time) string { timestamps = "\"Timestamp\":" + string(serializedNow) + ",\"ObservedTimestamp\":" + string(serializedNow) + "," } - return "{" + timestamps + "\"Severity\":9,\"SeverityText\":\"INFO\",\"Body\":{\"Type\":\"String\",\"Value\":\"test\"},\"Attributes\":[{\"Key\":\"key\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key2\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key3\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key4\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key5\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"bool\",\"Value\":{\"Type\":\"Bool\",\"Value\":true}}],\"TraceID\":\"0102030405060708090a0b0c0d0e0f10\",\"SpanID\":\"0102030405060708\",\"TraceFlags\":\"01\",\"Resource\":[{\"Key\":\"foo\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"bar\"}}],\"Scope\":{\"Name\":\"name\",\"Version\":\"version\",\"SchemaURL\":\"https://example.com/custom-schema\"},\"DroppedAttributes\":10}\n" + return "{" + timestamps + "\"Severity\":9,\"SeverityText\":\"INFO\",\"Body\":{\"Type\":\"String\",\"Value\":\"test\"},\"Attributes\":[{\"Key\":\"key\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key2\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key3\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key4\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"key5\",\"Value\":{\"Type\":\"String\",\"Value\":\"value\"}},{\"Key\":\"bool\",\"Value\":{\"Type\":\"Bool\",\"Value\":true}}],\"TraceID\":\"0102030405060708090a0b0c0d0e0f10\",\"SpanID\":\"0102030405060708\",\"TraceFlags\":\"01\",\"Resource\":[{\"Key\":\"foo\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"bar\"}}],\"Scope\":{\"Name\":\"name\",\"Version\":\"version\",\"SchemaURL\":\"https://example.com/custom-schema\",\"Attributes\":{}},\"DroppedAttributes\":10}\n" } func getJSONs(now *time.Time) string { @@ -263,7 +263,8 @@ func getPrettyJSON(now *time.Time) string { "Scope": { "Name": "name", "Version": "version", - "SchemaURL": "https://example.com/custom-schema" + "SchemaURL": "https://example.com/custom-schema", + "Attributes": {} }, "DroppedAttributes": 10 } diff --git a/exporters/stdout/stdoutmetric/example_test.go b/exporters/stdout/stdoutmetric/example_test.go index b2a4ebbd74d..1df2df38ef4 100644 --- a/exporters/stdout/stdoutmetric/example_test.go +++ b/exporters/stdout/stdoutmetric/example_test.go @@ -184,7 +184,8 @@ func Example() { // "Scope": { // "Name": "example", // "Version": "0.0.1", - // "SchemaURL": "" + // "SchemaURL": "", + // "Attributes": null // }, // "Metrics": [ // { diff --git a/exporters/stdout/stdouttrace/trace_test.go b/exporters/stdout/stdouttrace/trace_test.go index 8c3b868c96a..a034eb40187 100644 --- a/exporters/stdout/stdouttrace/trace_test.go +++ b/exporters/stdout/stdouttrace/trace_test.go @@ -189,12 +189,14 @@ func expectedJSON(now time.Time) string { "InstrumentationScope": { "Name": "", "Version": "", - "SchemaURL": "" + "SchemaURL": "", + "Attributes": null }, "InstrumentationLibrary": { "Name": "", "Version": "", - "SchemaURL": "" + "SchemaURL": "", + "Attributes": null } } ` diff --git a/sdk/instrumentation/scope.go b/sdk/instrumentation/scope.go index 728115045bb..34852a47b21 100644 --- a/sdk/instrumentation/scope.go +++ b/sdk/instrumentation/scope.go @@ -3,6 +3,8 @@ package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" +import "go.opentelemetry.io/otel/attribute" + // Scope represents the instrumentation scope. type Scope struct { // Name is the name of the instrumentation scope. This should be the @@ -12,4 +14,6 @@ type Scope struct { Version string // SchemaURL of the telemetry emitted by the scope. SchemaURL string + // Attributes of the telemetry emitted by the scope. + Attributes attribute.Set } diff --git a/sdk/log/provider_test.go b/sdk/log/provider_test.go index b9374e9d934..fecd8f10127 100644 --- a/sdk/log/provider_test.go +++ b/sdk/log/provider_test.go @@ -300,11 +300,15 @@ func TestLoggerProviderLogger(t *testing.T) { t.Run("SameLoggers", func(t *testing.T) { p := NewLoggerProvider() - l0, l1 := p.Logger("l0"), p.Logger("l1") - l2, l3 := p.Logger("l0"), p.Logger("l1") - - assert.Same(t, l0, l2) - assert.Same(t, l1, l3) + l0, l1, l2 := p.Logger("l0"), p.Logger("l1"), p.Logger("l0", log.WithInstrumentationAttributes(attribute.String("foo", "bar"))) + assert.NotSame(t, l0, l1) + assert.Same(t, l0, l2) // TODO (#3368): Change to assert.NotSame. + assert.NotSame(t, l1, l2) + + l3, l4, l5 := p.Logger("l0"), p.Logger("l1"), p.Logger("l0", log.WithInstrumentationAttributes(attribute.String("foo", "bar"))) + assert.Same(t, l0, l3) + assert.Same(t, l1, l4) + assert.Same(t, l2, l5) }) } diff --git a/sdk/metric/provider_test.go b/sdk/metric/provider_test.go index fc4537ecbbb..e5ef498ad5d 100644 --- a/sdk/metric/provider_test.go +++ b/sdk/metric/provider_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" api "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/sdk/metric/metricdata" @@ -95,6 +96,7 @@ func TestMeterProviderReturnsSameMeter(t *testing.T) { assert.Same(t, mtr, mp.Meter("")) assert.NotSame(t, mtr, mp.Meter("diff")) + assert.Same(t, mtr, mp.Meter("", api.WithInstrumentationAttributes(attribute.String("k", "v")))) // TODO (#3368): Change to assert.NotSame. } func TestEmptyMeterName(t *testing.T) { diff --git a/sdk/trace/provider_test.go b/sdk/trace/provider_test.go index 3644e377316..371120fe33f 100644 --- a/sdk/trace/provider_test.go +++ b/sdk/trace/provider_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/attribute" ottest "go.opentelemetry.io/otel/sdk/internal/internaltest" "go.opentelemetry.io/otel/trace" ) @@ -380,3 +381,17 @@ func testStoredError(t *testing.T, target interface{}) { assert.ErrorAs(t, err, target) } } + +func TestTracerProviderReturnsSameTracer(t *testing.T) { + p := NewTracerProvider() + + t0, t1, t2 := p.Tracer("t0"), p.Tracer("t1"), p.Tracer("t0", trace.WithInstrumentationAttributes(attribute.String("foo", "bar"))) + assert.NotSame(t, t0, t1) + assert.Same(t, t0, t2) // TODO (#3368): Change to assert.NotSame. + assert.NotSame(t, t1, t2) + + t3, t4, t5 := p.Tracer("t0"), p.Tracer("t1"), p.Tracer("t0", trace.WithInstrumentationAttributes(attribute.String("foo", "bar"))) + assert.Same(t, t0, t3) + assert.Same(t, t1, t4) + assert.Same(t, t2, t5) +} diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index ce492e1b05d..36565b10c4b 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -900,7 +900,11 @@ func cmpDiff(x, y interface{}) string { cmp.AllowUnexported(snapshot{}), cmp.AllowUnexported(attribute.Value{}), cmp.AllowUnexported(Event{}), - cmp.AllowUnexported(trace.TraceState{})) + cmp.AllowUnexported(trace.TraceState{}), + cmp.Comparer(func(x, y attribute.Set) bool { + return x.Equals(&y) + }), + ) } // checkChild is test utility function that tests that c has fields set appropriately,