// Package instrumentation initializes and configures telemetry and logging instrumentation. // After [Start] is called, the instrumentation providers can be accessed using global getters. package instrumentation import ( "context" "net/http" "slices" "strings" "sync" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/trace" ) const Name = "zitadel/backend/v3/instrumentation/tracing" type Config struct { ServiceName string // Detectors enrich the resource of every exported signal with attributes // describing the platform we run on. Empty by default. Detectors []DetectorType Trace TraceConfig Metric MetricConfig Log LogConfig Profile ProfileConfig } type ShutdownFunc func(context.Context) error var ( startOnce sync.Once shutdown ShutdownFunc errStart error ) // Start initializes global instrumentation once, based on the provided configuration. // It is safe to call multiple times; subsequent calls will return the same shutdown function and error as the first call. func Start(ctx context.Context, cfg Config) (ShutdownFunc, error) { startOnce.Do(func() { errStart = startProfiler(cfg.Profile, cfg.ServiceName) if errStart != nil { return } var logProvider *log.LoggerProvider logProvider, shutdown, errStart = setupOTelSDK(ctx, cfg) if errStart != nil { return } setLogger(logProvider, cfg.Log) }) return shutdown, errStart } // NewTracer creates a new tracer from the global provider. // See [trace.TracerProvider.Tracer] for details. func NewTracer(name string, options ...trace.TracerOption) *Tracer { provider := otel.GetTracerProvider() return &Tracer{provider.Tracer(name, options...)} } // NewMeter creates a new meter from the global provider. // See [metric.MeterProvider.Meter] for details. func NewMeter(name string, options ...metric.MeterOption) *Meter { provider := otel.GetMeterProvider() return &Meter{ Meter: provider.Meter(name, options...), } } // RequestFilter returns an [otelhttp.Filter] that excludes requests // with paths starting with any of the specified prefixes. func RequestFilter(ignoredPrefix ...string) otelhttp.Filter { return func(r *http.Request) bool { return !slices.ContainsFunc( ignoredPrefix, func(endpoint string) bool { return strings.HasPrefix(r.URL.RequestURI(), endpoint) }, ) } }