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>
71 lines
3.1 KiB
Go
71 lines
3.1 KiB
Go
package metrics
|
|
|
|
import (
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
// poolCollector reports the database connection pool's statistics on every scrape.
|
|
type poolCollector struct {
|
|
pool *pgxpool.Pool
|
|
|
|
acquiredConns *prometheus.Desc
|
|
idleConns *prometheus.Desc
|
|
totalConns *prometheus.Desc
|
|
maxConns *prometheus.Desc
|
|
acquires *prometheus.Desc
|
|
acquireWait *prometheus.Desc
|
|
emptyAcquires *prometheus.Desc
|
|
canceledAcquires *prometheus.Desc
|
|
newConns *prometheus.Desc
|
|
maxLifetimeDestroyed *prometheus.Desc
|
|
maxIdleDestroyed *prometheus.Desc
|
|
}
|
|
|
|
// NewPoolCollector returns a collector for the musicserver_db_pool_* metrics of pool.
|
|
// Register it once, for example with prometheus.MustRegister.
|
|
func NewPoolCollector(pool *pgxpool.Pool) prometheus.Collector {
|
|
desc := func(name, help string) *prometheus.Desc {
|
|
return prometheus.NewDesc("musicserver_db_pool_"+name, help, nil, nil)
|
|
}
|
|
return &poolCollector{
|
|
pool: pool,
|
|
acquiredConns: desc("acquired_conns", "Connections in use."),
|
|
idleConns: desc("idle_conns", "Idle connections."),
|
|
totalConns: desc("total_conns", "Open connections, in use, idle and being opened."),
|
|
maxConns: desc("max_conns", "Most connections the pool opens."),
|
|
acquires: desc("acquires_total", "Connections handed out."),
|
|
acquireWait: desc("acquire_wait_seconds_total", "Total time spent waiting for a connection."),
|
|
emptyAcquires: desc("empty_acquires_total", "Acquires that had to wait because no connection was idle."),
|
|
canceledAcquires: desc("canceled_acquires_total", "Acquires canceled while waiting, for example by a timeout."),
|
|
newConns: desc("new_conns_total", "Connections opened."),
|
|
maxLifetimeDestroyed: desc("max_lifetime_destroyed_total", "Connections closed for reaching their maximum lifetime."),
|
|
maxIdleDestroyed: desc("max_idle_destroyed_total", "Connections closed for being idle too long."),
|
|
}
|
|
}
|
|
|
|
func (c *poolCollector) Describe(ch chan<- *prometheus.Desc) {
|
|
prometheus.DescribeByCollect(c, ch)
|
|
}
|
|
|
|
func (c *poolCollector) Collect(ch chan<- prometheus.Metric) {
|
|
s := c.pool.Stat()
|
|
gauge := func(d *prometheus.Desc, v float64) {
|
|
ch <- prometheus.MustNewConstMetric(d, prometheus.GaugeValue, v)
|
|
}
|
|
counter := func(d *prometheus.Desc, v float64) {
|
|
ch <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, v)
|
|
}
|
|
gauge(c.acquiredConns, float64(s.AcquiredConns()))
|
|
gauge(c.idleConns, float64(s.IdleConns()))
|
|
gauge(c.totalConns, float64(s.TotalConns()))
|
|
gauge(c.maxConns, float64(s.MaxConns()))
|
|
counter(c.acquires, float64(s.AcquireCount()))
|
|
counter(c.acquireWait, s.AcquireDuration().Seconds())
|
|
counter(c.emptyAcquires, float64(s.EmptyAcquireCount()))
|
|
counter(c.canceledAcquires, float64(s.CanceledAcquireCount()))
|
|
counter(c.newConns, float64(s.NewConnsCount()))
|
|
counter(c.maxLifetimeDestroyed, float64(s.MaxLifetimeDestroyCount()))
|
|
counter(c.maxIdleDestroyed, float64(s.MaxIdleDestroyCount()))
|
|
}
|