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,49 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
httpRequests = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "http_requests_total",
|
||||
Help: "HTTP requests by method, route and status code.",
|
||||
}, []string{"method", "route", "code"})
|
||||
|
||||
httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "http_request_duration_seconds",
|
||||
Help: "HTTP request latency by method and route. Song downloads include the transfer.",
|
||||
// Up to 30 s, since songs can take long to send to slow clients.
|
||||
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 30},
|
||||
}, []string{"method", "route"})
|
||||
)
|
||||
|
||||
// unmatchedRoute labels requests that matched no route, so raw URLs never become labels.
|
||||
const unmatchedRoute = "unmatched"
|
||||
|
||||
// Middleware records the count and latency of requests per route. The route label is the
|
||||
// registered pattern, like /api/v1/songs/:uuid, never the URL with its IDs and query.
|
||||
// Register it outside Recover, so requests that panic are counted as 500.
|
||||
func Middleware() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c *echo.Context) error {
|
||||
start := time.Now()
|
||||
err := next(c)
|
||||
|
||||
route := c.Path()
|
||||
if route == "" {
|
||||
route = unmatchedRoute
|
||||
}
|
||||
_, status := echo.ResolveResponseStatus(c.Response(), err)
|
||||
method := c.Request().Method
|
||||
httpRequests.WithLabelValues(method, route, strconv.Itoa(status)).Inc()
|
||||
httpDuration.WithLabelValues(method, route).Observe(time.Since(start).Seconds())
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user