autobrr/internal/http/metrics_server.go
Antoine 3f8bc0140c
feat(metrics): add metrics server (#1930)
* feat(metrics): add metrics server

* chore: update license headers

* feat(metrics): add optional basic auth

* feat(metrics): add go and process collectors

---------

Co-authored-by: ze0s <43699394+zze0s@users.noreply.github.com>
Co-authored-by: ze0s <ze0s@riseup.net>
2025-01-25 17:58:18 +01:00

96 lines
2.2 KiB
Go

// Copyright (c) 2021 - 2025, Ludvig Lundgren and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later
package http
import (
"fmt"
"net"
"net/http"
"time"
"github.com/autobrr/autobrr/internal/config"
"github.com/autobrr/autobrr/internal/logger"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog"
)
type metricsManager interface {
GetRegistry() *prometheus.Registry
}
type MetricsServer struct {
log zerolog.Logger
config *config.AppConfig
version string
commit string
date string
metricsManager metricsManager
}
func NewMetricsServer(log logger.Logger, config *config.AppConfig, version string, commit string, date string, metricsManager metricsManager) MetricsServer {
return MetricsServer{
log: log.With().Str("module", "http").Logger(),
config: config,
version: version,
commit: commit,
date: date,
metricsManager: metricsManager,
}
}
func (s MetricsServer) Open() error {
addr := fmt.Sprintf("%v:%v", s.config.Config.MetricsHost, s.config.Config.MetricsPort)
var err error
for _, proto := range []string{"tcp", "tcp4", "tcp6"} {
if err = s.tryToServe(addr, proto); err == nil {
break
}
s.log.Error().Err(err).Msgf("Failed to start %s server. Attempted to listen on %s", proto, addr)
}
return err
}
func (s MetricsServer) tryToServe(addr, protocol string) error {
listener, err := net.Listen(protocol, addr)
if err != nil {
return err
}
s.log.Info().Msgf("Starting Metrics %s server. Listening on %s", protocol, listener.Addr().String())
server := http.Server{
Handler: s.Handler(),
ReadHeaderTimeout: time.Second * 15,
}
return server.Serve(listener)
}
func (s MetricsServer) Handler() http.Handler {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Recoverer)
r.Use(LoggerMiddleware(&s.log))
if s.config.Config.MetricsBasicAuthUsers != "" {
r.Use(BasicAuth("metrics", s.config.Config.MetricsBasicAuthUsers))
}
r.Get("/metrics", promhttp.HandlerFor(s.metricsManager.GetRegistry(), promhttp.HandlerOpts{}).ServeHTTP)
return r
}