Expose Prometheus metrics on a separate port
Metrics are served on METRICS_PORT (default 2112, "off" to disable), never on the public port. Besides the Go runtime and process metrics this adds: - http_requests_total and http_request_duration_seconds per route pattern, from an Echo middleware. - musicserver_songs_requested_total and musicserver_songs_played_total by pick mode (random, low, classic). The mode is now stored with each queued song (migration 000006, not released yet). - Library size, sync duration, last successful sync, broken songs from the last full sync, and the database connection pool. Refs #35, #36, #37 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c62b65d7cd
commit
f79f51ea4c
28 files changed
+864
-70
No files matched your search
@@ -0,0 +1,60 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in new issue
Block a user