package telemetry import ( "context" "errors" "fmt" "go.opentelemetry.io/otel/metric" metricnoop "go.opentelemetry.io/otel/metric/noop" sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdkresource "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" tracenoop "go.opentelemetry.io/otel/trace/noop" ) type Providers struct { Tracer trace.TracerProvider Meter metric.MeterProvider shutdown func(context.Context) error } type Config struct { Resource *sdkresource.Resource TraceExporter sdktrace.SpanExporter MetricReader sdkmetric.Reader } func New(config Config) (*Providers, error) { if config.Resource == nil { return nil, errors.New("OpenTelemetry resource is required") } providers := &Providers{ Tracer: tracenoop.NewTracerProvider(), Meter: metricnoop.NewMeterProvider(), } var tracerProvider *sdktrace.TracerProvider if config.TraceExporter != nil { tracerProvider = sdktrace.NewTracerProvider( sdktrace.WithBatcher(config.TraceExporter), sdktrace.WithResource(config.Resource), ) providers.Tracer = tracerProvider } var meterProvider *sdkmetric.MeterProvider if config.MetricReader != nil { meterProvider = sdkmetric.NewMeterProvider( sdkmetric.WithReader(config.MetricReader), sdkmetric.WithResource(config.Resource), ) providers.Meter = meterProvider } providers.shutdown = func(ctx context.Context) error { var shutdownErrors []error if meterProvider != nil { shutdownErrors = append(shutdownErrors, meterProvider.Shutdown(ctx)) } if tracerProvider != nil { shutdownErrors = append(shutdownErrors, tracerProvider.Shutdown(ctx)) } if err := errors.Join(shutdownErrors...); err != nil { return fmt.Errorf("shutdown OpenTelemetry providers: %w", err) } return nil } return providers, nil } func (p *Providers) Shutdown(ctx context.Context) error { return p.shutdown(ctx) }