Files
gerbil/internal/observability/config.go

130 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package observability provides a backend-neutral metrics abstraction for Gerbil.
//
// Exactly one metrics backend may be enabled at runtime:
// - "prometheus" native Prometheus client; exposes /metrics (no OTel SDK required)
// - "otel" OpenTelemetry metrics pushed via OTLP (gRPC or HTTP)
// - "none" metrics disabled; a safe noop implementation is used
//
// Future OTel tracing and logging can be added to this package alongside the
// existing otel sub-package without touching the Prometheus-native path.
package observability
import (
"fmt"
"time"
)
// MetricsConfig is the top-level metrics configuration.
type MetricsConfig struct {
// Enabled controls whether any metrics backend is started.
// When false the noop backend is used regardless of Backend.
Enabled bool
// Backend selects the active backend: "prometheus", "otel", or "none".
Backend string
// Prometheus holds settings used only by the Prometheus-native backend.
Prometheus PrometheusConfig
// OTel holds settings used only by the OTel backend.
OTel OTelConfig
// ServiceName is propagated to OTel resource attributes.
ServiceName string
// ServiceVersion is propagated to OTel resource attributes.
ServiceVersion string
// DeploymentEnvironment is an optional OTel resource attribute.
DeploymentEnvironment string
}
// PrometheusConfig holds Prometheus-native backend settings.
type PrometheusConfig struct {
// Path is the HTTP path to expose the /metrics endpoint.
// Defaults to "/metrics".
Path string
}
// OTelConfig holds OpenTelemetry backend settings.
type OTelConfig struct {
// Protocol is the OTLP transport: "grpc" (default) or "http".
Protocol string
// Endpoint is the OTLP collector address (e.g. "localhost:4317").
Endpoint string
// Insecure disables TLS for the OTLP connection.
Insecure bool
// ExportInterval is how often metrics are pushed to the collector.
// Defaults to 60 s.
ExportInterval time.Duration
// Timeout bounds OTLP exporter construction calls.
// Defaults to 10 s.
Timeout time.Duration
}
// DefaultMetricsConfig returns a MetricsConfig with sensible defaults.
func DefaultMetricsConfig() MetricsConfig {
return MetricsConfig{
Enabled: true,
Backend: "prometheus",
Prometheus: PrometheusConfig{
Path: "/metrics",
},
OTel: OTelConfig{
Protocol: "grpc",
Endpoint: "localhost:4317",
Insecure: true,
ExportInterval: 60 * time.Second,
Timeout: 10 * time.Second,
},
ServiceName: "gerbil",
ServiceVersion: "1.0.0",
}
}
// Validate checks the configuration for logical errors.
func (c *MetricsConfig) Validate() error {
if !c.Enabled {
return nil
}
switch c.Backend {
case "prometheus", "none":
// valid
case "":
return fmt.Errorf("metrics: enabled requires a non-empty backend")
case "otel":
if c.OTel.Endpoint == "" {
return fmt.Errorf("metrics: backend=otel requires a non-empty OTel endpoint")
}
if c.OTel.Protocol != "grpc" && c.OTel.Protocol != "http" {
return fmt.Errorf("metrics: otel protocol must be \"grpc\" or \"http\", got %q", c.OTel.Protocol)
}
if c.OTel.ExportInterval <= 0 {
return fmt.Errorf("metrics: otel export interval must be positive")
}
if c.OTel.Timeout <= 0 {
return fmt.Errorf("metrics: otel timeout must be positive")
}
default:
return fmt.Errorf("metrics: unknown backend %q (must be \"prometheus\", \"otel\", or \"none\")", c.Backend)
}
return nil
}
// effectiveBackend resolves the backend string, treating "" and "none" as noop.
func (c *MetricsConfig) effectiveBackend() string {
if !c.Enabled {
return "none"
}
if c.Backend == "" {
return "none"
}
return c.Backend
}