package tracing import ( "context" "errors" "strings" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "github.com/kedacore/http-add-on/interceptor/config" ) var serviceName = "keda-http-interceptor" func SetupOTelSDK(ctx context.Context, tCfg *config.Tracing) (shutdown func(context.Context) error, err 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(ctx context.Context) error { var err error for _, fn := range shutdownFuncs { err = errors.Join(err, fn(ctx)) } shutdownFuncs = nil return err } handleErr := func(inErr error) { err = errors.Join(inErr, shutdown(ctx)) } res, err := newResource(serviceName) if err != nil { handleErr(err) return } prop := NewPropagator() otel.SetTextMapPropagator(prop) tracerProvider, err := newTraceProvider(ctx, res, tCfg) if err != nil { handleErr(err) return } shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) otel.SetTracerProvider(tracerProvider) return } func newResource(serviceName string) (*resource.Resource, error) { return resource.Merge(resource.Default(), resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName(serviceName), )) } func NewPropagator() propagation.TextMapPropagator { return propagation.NewCompositeTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, b3.New(), ) } func newTraceProvider(ctx context.Context, res *resource.Resource, tCfg *config.Tracing) (*trace.TracerProvider, error) { traceExporter, err := newExporter(ctx, tCfg) if err != nil { return nil, err } traceProvider := trace.NewTracerProvider( trace.WithSampler(trace.AlwaysSample()), trace.WithBatcher(traceExporter), trace.WithResource(res), ) return traceProvider, nil } func newExporter(ctx context.Context, tCfg *config.Tracing) (trace.SpanExporter, error) { switch strings.ToLower(tCfg.Exporter) { case "console": return stdouttrace.New() case "http/protobuf": return otlptracehttp.New(ctx) case "grpc": return otlptracegrpc.New(ctx) default: return nil, errors.New("no valid tracing exporter defined") } }