package internal import ( "context" "errors" "time" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/log/global" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/trace" ) var ( otelEndpoint = "otel-collector:4317" ) // setupOTelSDK bootstraps the OpenTelemetry pipeline. // If it does not return an error, make sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context) (func(context.Context) error, error) { var shutdownFuncs []func(context.Context) error // shutdown calls cleanup functions registered via shutdownFuncs. // The errors from the calls are joined. // Each registered cleanup will be invoked once. shutdown := func(ctxInternal context.Context) error { var err error for _, fn := range shutdownFuncs { err = errors.Join(err, fn(ctxInternal)) } shutdownFuncs = nil return err } var err error // handleErr calls shutdown for cleanup and makes sure that all errors are returned. handleErr := func(ctxInternal context.Context, inErr error) { err = errors.Join(inErr, shutdown(ctxInternal)) } // Set up propagator. prop := newPropagator() otel.SetTextMapPropagator(prop) // Set up trace provider. tracerProvider, err := newTracerProvider(ctx) if err != nil { handleErr(ctx, err) return nil, err } shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) otel.SetTracerProvider(tracerProvider) // Set up meter provider. meterProvider, err := newMeterProvider(ctx) if err != nil { handleErr(ctx, err) return nil, err } shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) otel.SetMeterProvider(meterProvider) // Set up logger provider. loggerProvider, err := newLoggerProvider(ctx) if err != nil { handleErr(ctx, err) return nil, err } shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) global.SetLoggerProvider(loggerProvider) return shutdown, nil } func newPropagator() propagation.TextMapPropagator { return propagation.NewCompositeTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, ) } func newTracerProvider(ctx context.Context) (*trace.TracerProvider, error) { exp, err := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint(otelEndpoint), otlptracegrpc.WithInsecure(), ) if err != nil { return nil, err } return trace.NewTracerProvider(trace.WithBatcher(exp)), nil } func newMeterProvider(ctx context.Context) (*metric.MeterProvider, error) { exp, err := otlpmetricgrpc.New(ctx, otlpmetricgrpc.WithInsecure(), otlpmetricgrpc.WithEndpoint(otelEndpoint)) if err != nil { return nil, err } return metric.NewMeterProvider( metric.WithReader( metric.NewPeriodicReader( exp, metric.WithInterval(15*time.Second)))), nil } func newLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) { logExporter, err := otlploggrpc.New( ctx, otlploggrpc.WithInsecure(), otlploggrpc.WithEndpoint(otelEndpoint)) if err != nil { return nil, err } loggerProvider := log.NewLoggerProvider( log.WithProcessor(log.NewBatchProcessor(logExporter)), ) return loggerProvider, nil }