package obsx import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" ) // TracerConfig configures the OpenTelemetry tracer. type TracerConfig struct { ServiceName string ServiceVersion string Endpoint string // OTLP gRPC endpoint, e.g. "localhost:4317" Sampler float64 // sampling ratio, default: 1.0 (sample everything) } func (c *TracerConfig) defaults() { if c.Sampler <= 0 { c.Sampler = 1.0 } } // SetupTracer initializes an OpenTelemetry tracer provider with OTLP gRPC exporter. // Returns a shutdown function that must be called on application exit. func SetupTracer(ctx context.Context, cfg TracerConfig) (shutdown func(context.Context) error, err error) { cfg.defaults() exporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint(cfg.Endpoint), otlptracegrpc.WithInsecure(), ) if err != nil { return nil, err } attrs := []resource.Option{ resource.WithAttributes(semconv.ServiceName(cfg.ServiceName)), } if cfg.ServiceVersion != "" { attrs = append(attrs, resource.WithAttributes(semconv.ServiceVersion(cfg.ServiceVersion))) } res, err := resource.New(ctx, attrs...) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(res), sdktrace.WithSampler(sdktrace.TraceIDRatioBased(cfg.Sampler)), ) otel.SetTracerProvider(tp) return tp.Shutdown, nil } // StartSpan starts a new span using the global tracer provider. func StartSpan(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { return otel.Tracer("obsx").Start(ctx, name, opts...) }