From ca8967b8cb11c881c378ed8a985fae8e0ffee046 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Fri, 8 Nov 2024 15:54:48 -0600 Subject: [PATCH] detect: sever semconv relationship to otel sdk Copies over the telemetry sdk detection to utilize our own version of semconv rather than mix the versions between different packages. This will keep a consistent schema url instead of constantly chasing whichever one the otel sdk is using. The only thing left from the otel sdk is `WithFromEnv` which is schemaless and won't conflict for that reason so we can continue to use it. Backport adjustments for v0.13.0-beta1-m.x: - use otel.Version() instead of sdk.Version(): the otel sdk root package does not exist at the otel version pinned by this branch, and its builtin telemetrySDK detector reports otel.Version() too - introduce the exported Resource variable (not previously present on this branch) so importing programs can override the detected resource with one matching their own semconv schema version Signed-off-by: Jonathan A. Sternberg (cherry picked from commit 9863dd307d56a1f2055a836d0bc2182d9b6d32cf) Signed-off-by: Cory Snider (cherry picked from commit 9cbf3ac60b012fb3c2f93eba7e991b37d5797bac) Signed-off-by: Sopho Merkviladze --- util/tracing/detect/detect.go | 17 ++++++----- util/tracing/detect/resource.go | 45 ++++++++++++++++++++++++++++ util/tracing/detect/resource_test.go | 29 ++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 util/tracing/detect/resource.go create mode 100644 util/tracing/detect/resource_test.go diff --git a/util/tracing/detect/detect.go b/util/tracing/detect/detect.go index 27c969180a63..cb94490e28c2 100644 --- a/util/tracing/detect/detect.go +++ b/util/tracing/detect/detect.go @@ -26,6 +26,12 @@ type detector struct { var ServiceName string var Recorder *TraceRecorder +// Resource is the resource used by the tracer provider. It may be set +// by an importing program before TracerProvider is first invoked to +// override the detected resource (e.g. to keep the semconv schema URL +// consistent with the program's own). +var Resource *resource.Resource + var detectors map[string]detector var once sync.Once var tp trace.TracerProvider @@ -97,13 +103,8 @@ func detect() error { // enable log with traceID when valid exporter bklog.EnableLogWithTraceID(true) - res, err := resource.Detect(context.Background(), serviceNameDetector{}) - if err != nil { - return err - } - res, err = resource.Merge(resource.Default(), res) - if err != nil { - return err + if Resource == nil { + Resource = detectResource() } sp := sdktrace.NewBatchSpanProcessor(exp) @@ -112,7 +113,7 @@ func detect() error { Recorder.flush = sp.ForceFlush } - sdktp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sp), sdktrace.WithResource(res)) + sdktp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sp), sdktrace.WithResource(Resource)) closers = append(closers, sdktp.Shutdown) exporter = exp diff --git a/util/tracing/detect/resource.go b/util/tracing/detect/resource.go new file mode 100644 index 000000000000..95e406fbc9fa --- /dev/null +++ b/util/tracing/detect/resource.go @@ -0,0 +1,45 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package detect + +import ( + "context" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/sdk/resource" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" +) + +func detectResource() *resource.Resource { + res, err := resource.New(context.Background(), + resource.WithDetectors(serviceNameDetector{}), + resource.WithFromEnv(), + resource.WithDetectors(telemetrySDK{}), + ) + if err != nil { + otel.Handle(err) + } + return res +} + +type ( + telemetrySDK struct{} +) + +var ( + _ resource.Detector = telemetrySDK{} +) + +// Detect returns a *Resource that describes the OpenTelemetry SDK used. +func (telemetrySDK) Detect(context.Context) (*resource.Resource, error) { + return resource.NewWithAttributes( + semconv.SchemaURL, + semconv.TelemetrySDKName("opentelemetry"), + semconv.TelemetrySDKLanguageGo, + // otel.Version instead of sdk.Version: the root sdk package + // does not exist yet at the otel version pinned by this branch, + // and its builtin telemetrySDK detector reports otel.Version too. + semconv.TelemetrySDKVersion(otel.Version()), + ), nil +} diff --git a/util/tracing/detect/resource_test.go b/util/tracing/detect/resource_test.go new file mode 100644 index 000000000000..5327f5336f1b --- /dev/null +++ b/util/tracing/detect/resource_test.go @@ -0,0 +1,29 @@ +package detect + +import ( + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" +) + +func TestResource(t *testing.T) { + prevHandler := otel.GetErrorHandler() + t.Cleanup(func() { + otel.SetErrorHandler(prevHandler) + }) + + var resourceErr error + otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) { + resourceErr = err + })) + + res := detectResource() + + // Should not have an empty schema url. Only happens when + // there is a schema conflict. + require.NotEqual(t, "", res.SchemaURL()) + + // No error should have been invoked. + require.NoError(t, resourceErr) +}