// Package metricsserver provides a standalone HTTP server for exposing Prometheus metrics. // // This package implements a dedicated metrics server that exposes application metrics // via HTTP. It uses a custom Prometheus registry to avoid conflicts with other metric // collectors and provides graceful shutdown capabilities. package metricsserver import ( "context" "net/http" "strconv" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "golang.org/x/sync/errgroup" "go.ntppool.org/common/logger" ) // Metrics provides a custom Prometheus registry and HTTP handlers for metrics exposure. // It isolates application metrics from the default global registry. type Metrics struct { r *prometheus.Registry } // New creates a new Metrics instance with a custom Prometheus registry. func New() *Metrics { r := prometheus.NewRegistry() m := &Metrics{ r: r, } return m } // Registry returns the custom Prometheus registry. // Use this to register your application's metrics collectors. func (m *Metrics) Registry() *prometheus.Registry { return m.r } // Handler returns an HTTP handler for the /metrics endpoint with OpenMetrics support. func (m *Metrics) Handler() http.Handler { log := logger.NewStdLog("prom http", false, nil) return promhttp.HandlerFor(m.r, promhttp.HandlerOpts{ ErrorLog: log, Registry: m.r, EnableOpenMetrics: true, }) } // ListenAndServe starts a metrics server on the specified port and blocks until ctx is done. // The server exposes the metrics handler and shuts down gracefully when the context is cancelled. func (m *Metrics) ListenAndServe(ctx context.Context, port int) error { log := logger.Setup() srv := &http.Server{ Addr: ":" + strconv.Itoa(port), ReadTimeout: 10 * time.Second, WriteTimeout: 20 * time.Second, IdleTimeout: 120 * time.Second, Handler: m.Handler(), } g, ctx := errgroup.WithContext(ctx) g.Go(func() error { err := srv.ListenAndServe() if err != nil && err != http.ErrServerClosed { log.Warn("metrics server done listening", "err", err) return err } return nil }) <-ctx.Done() if err := srv.Shutdown(ctx); err != nil { log.Error("metrics server shutdown failed", "err", err) return err } return g.Wait() }