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" ) type Metrics struct { r *prometheus.Registry } func New() *Metrics { r := prometheus.NewRegistry() m := &Metrics{ r: r, } return m } func (m *Metrics) Registry() prometheus.Registerer { return m.r } 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 goroutine with a server running on // the specified port. The server will shutdown and return when // the provided context is done 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() }