From 3555297119fccb806b875e3f406975c250cd1e97 Mon Sep 17 00:00:00 2001 From: Tigran Najaryan Date: Wed, 19 May 2021 19:13:13 -0400 Subject: [PATCH] [WIP] Add schema URL support to Tracer [Do not merge, this is a draft to get maintainers' feedback] This adds support for schema URL according to the specification: https://github.com/open-telemetry/opentelemetry-specification/pull/1666 (Link to replaced by the link to the spec after that PR is merged) TODO: Populate the schema_url field in the OTLP after this PR https://github.com/open-telemetry/opentelemetry-proto/pull/298 is merged and the field is available in the proto message. This is the first in the series of changes that are necessary to add support for schemas in Go SDK. Subsequent PRs will add support in Meter and Resource. We will also see if we can find a good way to group semantic conventions with the schema version that declares them. --- CHANGELOG.md | 1 + exporters/otlp/internal/transform/span.go | 2 ++ exporters/otlp/internal/transform/span_test.go | 6 ++++-- exporters/stdout/example_test.go | 1 + exporters/stdout/trace_test.go | 3 ++- sdk/instrumentation/library.go | 2 ++ sdk/trace/provider.go | 5 +++-- sdk/trace/provider_test.go | 12 ++++++++++++ sdk/trace/trace_test.go | 8 +++++--- trace/config.go | 15 +++++++++++++++ trace/config_test.go | 9 +++++++++ 11 files changed, 56 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c59e6c59c8fb..a2d2ed7a9bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm This type can be used as a testing replacement for the `SpanSnapshot` that was removed from the `go.opentelemetry.io/otel/sdk/trace` package. (#1873) - Adds support for scheme in `OTEL_EXPORTER_OTLP_ENDPOINT` according to the spec. (#1886) - An example of using OpenTelemetry Go as a trace context forwarder. (#1912) +- Adds `trace.WithSchemaURL` option for configuring the tracer with a Schema URL. (#1889) ### Changed diff --git a/exporters/otlp/internal/transform/span.go b/exporters/otlp/internal/transform/span.go index bcf540e4e435..7bcdeeedfdc1 100644 --- a/exporters/otlp/internal/transform/span.go +++ b/exporters/otlp/internal/transform/span.go @@ -61,6 +61,8 @@ func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans { InstrumentationLibrary: instrumentationLibrary(sd.InstrumentationLibrary()), Spans: []*tracepb.Span{}, } + // TODO: set schema_url field of ils when it is available in the proto. + _ = sd.InstrumentationLibrary().SchemaURL } ils.Spans = append(ils.Spans, span(sd)) ilsm[iKey] = ils diff --git a/exporters/otlp/internal/transform/span_test.go b/exporters/otlp/internal/transform/span_test.go index d32fefed14ea..adb52d72dd13 100644 --- a/exporters/otlp/internal/transform/span_test.go +++ b/exporters/otlp/internal/transform/span_test.go @@ -262,8 +262,9 @@ func TestSpanData(t *testing.T) { DroppedLinks: 3, Resource: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)), InstrumentationLibrary: instrumentation.Library{ - Name: "go.opentelemetry.io/test/otel", - Version: "v0.0.1", + Name: "go.opentelemetry.io/test/otel", + Version: "v0.0.1", + SchemaURL: "https://opentelemetry.io/schemas/1.2.0", }, } @@ -294,6 +295,7 @@ func TestSpanData(t *testing.T) { assert.Equal(t, got[0].GetResource(), Resource(spanData.Resource)) ilSpans := got[0].GetInstrumentationLibrarySpans() require.Len(t, ilSpans, 1) + // TODO: Add SchemaURL field checking once the field is added to the proto. assert.Equal(t, ilSpans[0].GetInstrumentationLibrary(), instrumentationLibrary(spanData.InstrumentationLibrary)) require.Len(t, ilSpans[0].Spans, 1) actualSpan := ilSpans[0].Spans[0] diff --git a/exporters/stdout/example_test.go b/exporters/stdout/example_test.go index 82da5665bf95..f38a572bb824 100644 --- a/exporters/stdout/example_test.go +++ b/exporters/stdout/example_test.go @@ -35,6 +35,7 @@ var ( tracer = otel.GetTracerProvider().Tracer( instrumentationName, trace.WithInstrumentationVersion(instrumentationVersion), + trace.WithSchemaURL("https://opentelemetry.io/schemas/1.2.0"), ) meter = global.GetMeterProvider().Meter( diff --git a/exporters/stdout/trace_test.go b/exporters/stdout/trace_test.go index 8b60790dfcb6..2027d9b14f69 100644 --- a/exporters/stdout/trace_test.go +++ b/exporters/stdout/trace_test.go @@ -177,7 +177,8 @@ func TestExporter_ExportSpan(t *testing.T) { ], "InstrumentationLibrary": { "Name": "", - "Version": "" + "Version": "", + "SchemaURL": "" } } ] diff --git a/sdk/instrumentation/library.go b/sdk/instrumentation/library.go index c897c04de37a..5e54ee484bd4 100644 --- a/sdk/instrumentation/library.go +++ b/sdk/instrumentation/library.go @@ -32,4 +32,6 @@ type Library struct { Name string // Version is the version of the instrumentation library. Version string + // SchemaURL of the telemetry emitted by the library. + SchemaURL string } diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index 083c0b9946ae..3fbffa2da596 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -115,8 +115,9 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T name = defaultTracerName } il := instrumentation.Library{ - Name: name, - Version: c.InstrumentationVersion, + Name: name, + Version: c.InstrumentationVersion, + SchemaURL: c.SchemaURL, } t, ok := p.namedTracer[il] if !ok { diff --git a/sdk/trace/provider_test.go b/sdk/trace/provider_test.go index 6a55b50bb2df..e2fce31d7f79 100644 --- a/sdk/trace/provider_test.go +++ b/sdk/trace/provider_test.go @@ -20,6 +20,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/otel/trace" ) type basicSpanProcesor struct { @@ -82,3 +84,13 @@ func TestFailedProcessorShutdownInUnregister(t *testing.T) { err := stp.Shutdown(context.Background()) assert.NoError(t, err) } + +func TestSchemaURL(t *testing.T) { + stp := NewTracerProvider() + schemaURL := "https://opentelemetry.io/schemas/1.2.0" + tracerIface := stp.Tracer("tracername", trace.WithSchemaURL(schemaURL)) + + // Verify that the SchemaURL of the constructed Tracer is correctly populated. + tracerStruct := tracerIface.(*tracer) + assert.EqualValues(t, schemaURL, tracerStruct.instrumentationLibrary.SchemaURL) +} diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index a340ddb1baea..826359340f46 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -1284,7 +1284,7 @@ func TestWithResource(t *testing.T) { } } -func TestWithInstrumentationVersion(t *testing.T) { +func TestWithInstrumentationVersionAndSchema(t *testing.T) { te := NewTestExporter() tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) @@ -1293,6 +1293,7 @@ func TestWithInstrumentationVersion(t *testing.T) { _, span := tp.Tracer( "WithInstrumentationVersion", trace.WithInstrumentationVersion("v0.1.0"), + trace.WithSchemaURL("https://opentelemetry.io/schemas/1.2.0"), ).Start(ctx, "span0") got, err := endSpan(te, span) if err != nil { @@ -1308,8 +1309,9 @@ func TestWithInstrumentationVersion(t *testing.T) { name: "span0", spanKind: trace.SpanKindInternal, instrumentationLibrary: instrumentation.Library{ - Name: "WithInstrumentationVersion", - Version: "v0.1.0", + Name: "WithInstrumentationVersion", + Version: "v0.1.0", + SchemaURL: "https://opentelemetry.io/schemas/1.2.0", }, } if diff := cmpDiff(got, want); diff != "" { diff --git a/trace/config.go b/trace/config.go index ea30ee35f153..ddee8d20792d 100644 --- a/trace/config.go +++ b/trace/config.go @@ -25,6 +25,8 @@ type TracerConfig struct { // InstrumentationVersion is the version of the library providing // instrumentation. InstrumentationVersion string + // SchemaURL of the telemetry emitted by the Tracer. + SchemaURL string } // NewTracerConfig applies all the options to a returned TracerConfig. @@ -203,3 +205,16 @@ func (i instrumentationVersionOption) ApplyTracer(config *TracerConfig) { } func (instrumentationVersionOption) private() {} + +// WithSchemaURL sets the schema URL for the Tracer. +func WithSchemaURL(schemaURL string) InstrumentationOption { + return schemaURLOption(schemaURL) +} + +type schemaURLOption string + +func (i schemaURLOption) ApplyTracer(config *TracerConfig) { + config.SchemaURL = string(i) +} + +func (schemaURLOption) private() {} diff --git a/trace/config_test.go b/trace/config_test.go index 9375191c40ac..e8cc623bb8fd 100644 --- a/trace/config_test.go +++ b/trace/config_test.go @@ -177,6 +177,7 @@ func TestNewSpanConfig(t *testing.T) { func TestTracerConfig(t *testing.T) { v1 := "semver:0.0.1" v2 := "semver:1.0.0" + schemaURL := "https://opentelemetry.io/schemas/1.2.0" tests := []struct { options []TracerOption expected *TracerConfig @@ -204,6 +205,14 @@ func TestTracerConfig(t *testing.T) { InstrumentationVersion: v2, }, }, + { + []TracerOption{ + WithSchemaURL(schemaURL), + }, + &TracerConfig{ + SchemaURL: schemaURL, + }, + }, } for _, test := range tests { config := NewTracerConfig(test.options...)