Files
schemas/monitoring/otel.go
T
argoyleandClaude Opus 5.5 6f6fb5be68
schemas / check-release (pull_request) Failing after 2m45s
schemas / vulnerabilities (pull_request) Successful in 3m29s
schemas / check (pull_request) Successful in 4m5s
schemas / build (pull_request) Skipped
schemas / deploy-prod (pull_request) Skipped
pre-commit / pre-commit (pull_request) Successful in 9m44s
fix(monitoring): use otel.SetLoggerProvider
opentelemetry-go v1.47.0 deprecates go.opentelemetry.io/otel/log/global in
favour of the equivalent otel APIs; staticcheck (SA1019) fails pre-commit
on every PR since the monorepo bump (#990).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ma8eHhW59hLAJuLzBnLvUu
2026-10-07 21:11:55 +02:00

100 lines
2.9 KiB
Go

package monitoring
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/trace"
)
// SetupOTelSDK bootstraps the OpenTelemetry pipeline.
func SetupOTelSDK(ctx context.Context, enabled bool, serviceName, buildVersion, environment string) (func(context.Context) error, error) {
if os.Getenv("OTEL_RESOURCE_ATTRIBUTES") == "" {
if err := os.Setenv("OTEL_RESOURCE_ATTRIBUTES", fmt.Sprintf("service.name=%s,service.version=%s,service.environment=%s", serviceName, buildVersion, environment)); err != nil {
return func(context.Context) error {
return nil
}, err
}
}
var shutdownFuncs []func(context.Context) error
if !enabled {
return func(context.Context) error {
return nil
}, nil
}
shutdown := func(ctx context.Context) error {
var err error
for _, fn := range shutdownFuncs {
err = errors.Join(err, fn(ctx))
}
shutdownFuncs = nil
return err
}
// handleErr calls shutdown for cleanup and makes sure that all errors are returned.
handleErr := func(inErr error) (func(context.Context) error, error) {
return nil, errors.Join(inErr, shutdown(ctx))
}
// Set up the propagator.
prop := propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
)
otel.SetTextMapPropagator(prop)
traceExporter, err := otlptracehttp.New(ctx)
if err != nil {
return handleErr(err)
}
shutdownFuncs = append(shutdownFuncs, traceExporter.Shutdown)
tracerProvider := trace.NewTracerProvider(
trace.WithBatcher(traceExporter,
trace.WithBatchTimeout(5*time.Second)),
)
shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown)
otel.SetTracerProvider(tracerProvider)
logExporter, err := stdoutlog.New()
if err != nil {
return handleErr(err)
}
processor := log.NewSimpleProcessor(logExporter)
logProvider := log.NewLoggerProvider(log.WithProcessor(processor))
otel.SetLoggerProvider(logProvider)
shutdownFuncs = append(shutdownFuncs, logProvider.Shutdown)
exp, err := otlpmetrichttp.New(ctx)
if err != nil {
return handleErr(err)
}
meterProvider := metric.NewMeterProvider(metric.WithReader(metric.NewPeriodicReader(exp)))
shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown)
otel.SetMeterProvider(meterProvider)
return shutdown, err
}
func Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
spanCtx, s := StartSpan(ctx, "http")
defer s.Finish()
h.ServeHTTP(w, r.WithContext(spanCtx))
})
}