// Package metrics exposes Prometheus metrics: the Go runtime and process metrics that the // default registry collects, HTTP request metrics and MusicServer's own metrics. package metrics import ( "context" "errors" "fmt" "net" "net/http" "time" "music-server/internal/logging" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/zap" ) // Server serves /metrics on a port of its own, so it is never reachable through the // public port. type Server struct { httpServer *http.Server } // NewServer creates a metrics server for the given port. func NewServer(port int) *Server { mux := http.NewServeMux() mux.Handle("GET /metrics", promhttp.Handler()) return &Server{httpServer: &http.Server{ Addr: fmt.Sprintf(":%d", port), Handler: mux, ReadHeaderTimeout: 5 * time.Second, }} } // Handler returns the handler that serves /metrics. func (s *Server) Handler() http.Handler { return s.httpServer.Handler } // Start listens on the port and serves metrics in the background. It returns an error // when the port cannot be opened. func (s *Server) Start() error { ln, err := net.Listen("tcp", s.httpServer.Addr) if err != nil { return err } logging.GetLogger().Info("Metrics server starting", zap.String("address", s.httpServer.Addr)) go func() { if err := s.httpServer.Serve(ln); !errors.Is(err, http.ErrServerClosed) { logging.GetLogger().Error("Metrics server error", zap.Error(err)) } }() return nil } // Shutdown stops the metrics server. func (s *Server) Shutdown(ctx context.Context) error { return s.httpServer.Shutdown(ctx) }