A community based topic aggregation platform built on atproto
at main 121 lines 3.7 kB view raw
1// Package observability provides OpenTelemetry tracing configuration and middleware for Coves. 2package observability 3 4import ( 5 "errors" 6 "fmt" 7 "log/slog" 8 "os" 9 "strconv" 10) 11 12// Config validation errors 13var ( 14 // ErrInvalidSampleRatio is returned when SampleRatio is outside the valid range [0.0, 1.0] 15 ErrInvalidSampleRatio = errors.New("SampleRatio must be between 0.0 and 1.0") 16 // ErrMissingEndpoint is returned when Endpoint is empty while tracing is enabled 17 ErrMissingEndpoint = errors.New("Endpoint is required when observability is enabled") 18) 19 20// Config holds the configuration for OpenTelemetry tracing. 21type Config struct { 22 // Enabled determines whether OpenTelemetry tracing is active. 23 Enabled bool 24 25 // ServiceName is the name of this service in traces. 26 ServiceName string 27 28 // Endpoint is the OTLP collector endpoint (e.g., "http://localhost:4317"). 29 Endpoint string 30 31 // Headers contains optional headers for the OTLP exporter (key=value,key2=value2 format). 32 Headers string 33 34 // SampleRatio is the trace sampling ratio between 0.0 and 1.0. 35 // 1.0 means all traces are sampled, 0.5 means 50% are sampled. 36 SampleRatio float64 37 38 // Insecure determines whether to use an insecure gRPC connection to the collector. 39 Insecure bool 40} 41 42// DefaultConfig returns a Config with sensible default values. 43// By default, tracing is disabled to avoid unexpected overhead. 44func DefaultConfig() Config { 45 return Config{ 46 Enabled: false, 47 ServiceName: "coves-appview", 48 Endpoint: "http://localhost:4317", 49 Headers: "", 50 SampleRatio: 1.0, 51 Insecure: false, 52 } 53} 54 55// ConfigFromEnv creates a Config from environment variables. 56// Uses defaults for any missing environment variables. 57// 58// Environment variables: 59// - OTEL_ENABLED: "true"/"1" to enable, "false"/"0" to disable (default: false) 60// - OTEL_SERVICE_NAME: service name for traces (default: "coves-appview") 61// - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector endpoint (default: "http://localhost:4317") 62// - OTEL_EXPORTER_OTLP_HEADERS: headers for OTLP exporter in key=value,key2=value2 format (default: "") 63// - OTEL_TRACES_SAMPLER_ARG: sampling ratio 0.0-1.0 (default: 1.0) 64// - OTEL_EXPORTER_OTLP_INSECURE: "true"/"1" for insecure connection (default: false) 65func ConfigFromEnv() Config { 66 cfg := DefaultConfig() 67 68 if v := os.Getenv("OTEL_ENABLED"); v != "" { 69 cfg.Enabled = v == "true" || v == "1" 70 } 71 72 if v := os.Getenv("OTEL_SERVICE_NAME"); v != "" { 73 cfg.ServiceName = v 74 } 75 76 if v := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"); v != "" { 77 cfg.Endpoint = v 78 } 79 80 if v := os.Getenv("OTEL_EXPORTER_OTLP_HEADERS"); v != "" { 81 cfg.Headers = v 82 } 83 84 if v := os.Getenv("OTEL_TRACES_SAMPLER_ARG"); v != "" { 85 if ratio, err := strconv.ParseFloat(v, 64); err == nil && ratio >= 0.0 && ratio <= 1.0 { 86 cfg.SampleRatio = ratio 87 } else { 88 slog.Warn("[OTEL] invalid OTEL_TRACES_SAMPLER_ARG value, using default", 89 "value", v, 90 "default", cfg.SampleRatio, 91 "error", err, 92 ) 93 } 94 } 95 96 if v := os.Getenv("OTEL_EXPORTER_OTLP_INSECURE"); v != "" { 97 cfg.Insecure = v == "true" || v == "1" 98 } 99 100 return cfg 101} 102 103// Validate checks the configuration for invalid values. 104// Returns nil if the configuration is valid, or an error describing the problem. 105// When Enabled is false, only the SampleRatio is validated (for safety). 106// When Enabled is true, all required fields must be set. 107func (c Config) Validate() error { 108 // Always validate SampleRatio regardless of enabled state 109 if c.SampleRatio < 0.0 || c.SampleRatio > 1.0 { 110 return fmt.Errorf("%w: got %f", ErrInvalidSampleRatio, c.SampleRatio) 111 } 112 113 // When enabled, validate required fields 114 if c.Enabled { 115 if c.Endpoint == "" { 116 return ErrMissingEndpoint 117 } 118 } 119 120 return nil 121}