fix(telemetry): align resource semconv with otel sdk 1.45 detectors

This commit is contained in:
Julien Neuhart
2026-08-07 14:04:37 +02:00
parent 60f5a7b996
commit bb0b874d16
2 changed files with 19 additions and 2 deletions

View File

@@ -17,13 +17,18 @@ import (
"go.opentelemetry.io/otel/sdk/metric/exemplar" "go.opentelemetry.io/otel/sdk/metric/exemplar"
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace" "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, // buildResource assembles the OpenTelemetry resource shared by the tracer,
// meter, and logger providers. Detection is best-effort: a detector or merge // 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 // failure is logged and the build proceeds with whatever was gathered, so a
// flaky environment never prevents telemetry from starting. // 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 { func buildResource(ctx context.Context, logger *slog.Logger, serviceName, serviceVersion string) *resource.Resource {
base := resource.NewWithAttributes( base := resource.NewWithAttributes(
semconv.SchemaURL, semconv.SchemaURL,
@@ -55,9 +60,14 @@ func buildResource(ctx context.Context, logger *slog.Logger, serviceName, servic
return base 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) merged, err := resource.Merge(detected, base)
if err != nil { if err != nil {
logger.WarnContext(ctx, fmt.Sprintf("merge OpenTelemetry resource: %s", err)) logger.WarnContext(ctx, fmt.Sprintf("merge OpenTelemetry resource: %s", err))
}
if merged == nil {
return base return base
} }

View File

@@ -11,7 +11,7 @@ import (
"go.opentelemetry.io/otel/sdk/metric/exemplar" "go.opentelemetry.io/otel/sdk/metric/exemplar"
"go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata"
sdktrace "go.opentelemetry.io/otel/sdk/trace" 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) { func TestBuildResource(t *testing.T) {
@@ -24,6 +24,13 @@ func TestBuildResource(t *testing.T) {
values[string(kv.Key)] = kv.Value.AsString() 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" { if values[string(semconv.ServiceNameKey)] != "gotenberg" {
t.Errorf("service.name = %q, want %q", values[string(semconv.ServiceNameKey)], "gotenberg") t.Errorf("service.name = %q, want %q", values[string(semconv.ServiceNameKey)], "gotenberg")
} }