From 387728f09aeb15affe5d5f6c4e09043adee0297d Mon Sep 17 00:00:00 2001 From: Julien Neuhart Date: Tue, 2 Jun 2026 19:13:38 +0200 Subject: [PATCH] refactor(otel): extract shared buildResource helper --- pkg/gotenberg/internal/otel/otel.go | 54 +++++++++--------------- pkg/gotenberg/internal/otel/otel_test.go | 23 ++++++++++ 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/pkg/gotenberg/internal/otel/otel.go b/pkg/gotenberg/internal/otel/otel.go index 804ab22..67b8d1e 100644 --- a/pkg/gotenberg/internal/otel/otel.go +++ b/pkg/gotenberg/internal/otel/otel.go @@ -20,11 +20,9 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) -// InitTracerProvider initializes the OpenTelemetry tracer provider. -func InitTracerProvider(logger *slog.Logger, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { - initOtelLogger(logger) - - ctx := context.Background() +// buildResource assembles the OpenTelemetry resource shared by the tracer, +// meter, and logger providers. +func buildResource(serviceName, serviceVersion string) (*resource.Resource, error) { hostname, err := os.Hostname() if err != nil { return nil, fmt.Errorf("get hostname: %w", err) @@ -43,6 +41,20 @@ func InitTracerProvider(logger *slog.Logger, serviceName, serviceVersion string) return nil, fmt.Errorf("merge resource: %w", err) } + return res, nil +} + +// InitTracerProvider initializes the OpenTelemetry tracer provider. +func InitTracerProvider(logger *slog.Logger, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { + initOtelLogger(logger) + + ctx := context.Background() + + res, err := buildResource(serviceName, serviceVersion) + if err != nil { + return nil, fmt.Errorf("build resource: %w", err) + } + traceOpts := []trace.TracerProviderOption{ trace.WithResource(res), } @@ -72,22 +84,10 @@ func InitMeterProvider(logger *slog.Logger, serviceName, serviceVersion string) initOtelLogger(logger) ctx := context.Background() - hostname, err := os.Hostname() - if err != nil { - return nil, fmt.Errorf("get hostname: %w", err) - } - res, err := resource.Merge( - resource.Default(), - resource.NewWithAttributes( - semconv.SchemaURL, - semconv.ServiceName(serviceName), - semconv.ServiceVersion(serviceVersion), - semconv.HostName(hostname), - ), - ) + res, err := buildResource(serviceName, serviceVersion) if err != nil { - return nil, fmt.Errorf("merge resource: %w", err) + return nil, fmt.Errorf("build resource: %w", err) } metricOpts := []metric.Option{ @@ -126,22 +126,10 @@ func InitLoggerProvider(logger *slog.Logger, serviceName, serviceVersion string) initOtelLogger(logger) ctx := context.Background() - hostname, err := os.Hostname() - if err != nil { - return nil, nil, fmt.Errorf("get hostname: %w", err) - } - res, err := resource.Merge( - resource.Default(), - resource.NewWithAttributes( - semconv.SchemaURL, - semconv.ServiceName(serviceName), - semconv.ServiceVersion(serviceVersion), - semconv.HostName(hostname), - ), - ) + res, err := buildResource(serviceName, serviceVersion) if err != nil { - return nil, nil, fmt.Errorf("merge resource: %w", err) + return nil, nil, fmt.Errorf("build resource: %w", err) } logOpts := []log.LoggerProviderOption{ diff --git a/pkg/gotenberg/internal/otel/otel_test.go b/pkg/gotenberg/internal/otel/otel_test.go index a5751c9..b269af7 100644 --- a/pkg/gotenberg/internal/otel/otel_test.go +++ b/pkg/gotenberg/internal/otel/otel_test.go @@ -11,8 +11,31 @@ 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" ) +func TestBuildResource(t *testing.T) { + res, err := buildResource("gotenberg", "v8.0.0") + if err != nil { + t.Fatalf("build resource: %v", err) + } + + got := map[string]string{} + for _, kv := range res.Attributes() { + got[string(kv.Key)] = kv.Value.AsString() + } + + if got[string(semconv.ServiceNameKey)] != "gotenberg" { + t.Errorf("service.name = %q, want %q", got[string(semconv.ServiceNameKey)], "gotenberg") + } + if got[string(semconv.ServiceVersionKey)] != "v8.0.0" { + t.Errorf("service.version = %q, want %q", got[string(semconv.ServiceVersionKey)], "v8.0.0") + } + if _, ok := got[string(semconv.HostNameKey)]; !ok { + t.Error("expected host.name attribute to be present") + } +} + // TestInitTracerProvider_HonorsSamplerEnv guards the contract that the tracer // provider keeps honoring OTEL_TRACES_SAMPLER. The SDK reads it only when no // explicit sampler is configured, so any future WithSampler() would silently