From bb0b874d160d7de3a416207db0c53ac153ac6552 Mon Sep 17 00:00:00 2001 From: Julien Neuhart Date: Fri, 7 Aug 2026 14:04:37 +0200 Subject: [PATCH] fix(telemetry): align resource semconv with otel sdk 1.45 detectors --- pkg/gotenberg/internal/otel/otel.go | 12 +++++++++++- pkg/gotenberg/internal/otel/otel_test.go | 9 ++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/gotenberg/internal/otel/otel.go b/pkg/gotenberg/internal/otel/otel.go index 77b2a787..fe02c8f4 100644 --- a/pkg/gotenberg/internal/otel/otel.go +++ b/pkg/gotenberg/internal/otel/otel.go @@ -17,13 +17,18 @@ import ( "go.opentelemetry.io/otel/sdk/metric/exemplar" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.41.0" + semconv "go.opentelemetry.io/otel/semconv/v1.43.0" ) // buildResource assembles the OpenTelemetry resource shared by the tracer, // meter, and logger providers. Detection is best-effort: a detector or merge // failure is logged and the build proceeds with whatever was gathered, so a // flaky environment never prevents telemetry from starting. +// +// The semconv version imported here must match the one the SDK resource +// detectors use (go.opentelemetry.io/otel/sdk/resource). Drift makes +// [resource.Merge] fail with [resource.ErrSchemaURLConflict] and strips the +// schema URL off every exported signal. func buildResource(ctx context.Context, logger *slog.Logger, serviceName, serviceVersion string) *resource.Resource { base := resource.NewWithAttributes( semconv.SchemaURL, @@ -55,9 +60,14 @@ func buildResource(ctx context.Context, logger *slog.Logger, serviceName, servic return base } + // A schema URL conflict still yields a resource holding every attribute, only + // without a schema URL. Keep it: falling back to base would drop the host, + // OS, container, process, and OTEL_RESOURCE_ATTRIBUTES data. merged, err := resource.Merge(detected, base) if err != nil { logger.WarnContext(ctx, fmt.Sprintf("merge OpenTelemetry resource: %s", err)) + } + if merged == nil { return base } diff --git a/pkg/gotenberg/internal/otel/otel_test.go b/pkg/gotenberg/internal/otel/otel_test.go index 0488fa9b..3873d813 100644 --- a/pkg/gotenberg/internal/otel/otel_test.go +++ b/pkg/gotenberg/internal/otel/otel_test.go @@ -11,7 +11,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/exemplar" "go.opentelemetry.io/otel/sdk/metric/metricdata" sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.41.0" + semconv "go.opentelemetry.io/otel/semconv/v1.43.0" ) func TestBuildResource(t *testing.T) { @@ -24,6 +24,13 @@ func TestBuildResource(t *testing.T) { values[string(kv.Key)] = kv.Value.AsString() } + // Guards the semconv version pinned in buildResource against the one the SDK + // resource detectors use. Drift makes resource.Merge conflict and drops the + // schema URL from every exported signal. + if res.SchemaURL() != semconv.SchemaURL { + t.Errorf("resource schema URL = %q, want %q", res.SchemaURL(), semconv.SchemaURL) + } + if values[string(semconv.ServiceNameKey)] != "gotenberg" { t.Errorf("service.name = %q, want %q", values[string(semconv.ServiceNameKey)], "gotenberg") }