check / check (push) Successful in 2m53s
With METRICS_USERNAME and METRICS_PASSWORD both set, the backend records request metrics through go-http-metrics in a registry of its own, with Go's runtime and process metrics, and serves them at GET /metrics behind basic auth; nginx passes /metrics to it. With neither set there is no such route; one alone, or a METRICS_USERNAME containing ":", stops the start with an error naming the setting. Only requests that reach the health check or POST /api/v1/reports are recorded, as the labels are path and method, which clients could otherwise make up without end; POST /api/v1/reports is registered by its full path for that. Deviation: go get and go mod tidy ran directly; no entrypoint added a Go dependency yet (issue #45). Model: opus-5-5
69 lines
2.1 KiB
Go
69 lines
2.1 KiB
Go
package server
|
|
|
|
import (
|
|
"time"
|
|
|
|
"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/collectors"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
)
|
|
|
|
const (
|
|
requestTimeout = 60 * time.Second
|
|
|
|
// maxRequestBodyBytes caps every request body. A route group
|
|
// can mount s.mw.MaxBodyBytes with a smaller value to lower
|
|
// its bound, but cannot raise it: this cap runs first.
|
|
maxRequestBodyBytes int64 = 1 << 20 // 1 MiB
|
|
)
|
|
|
|
// SetupRoutes configures the chi router with middleware and
|
|
// all application routes.
|
|
func (s *Server) SetupRoutes() {
|
|
s.router = chi.NewRouter()
|
|
|
|
s.router.Use(s.mw.Recoverer())
|
|
s.router.Use(middleware.RequestID)
|
|
s.router.Use(s.mw.Logging())
|
|
s.router.Use(s.mw.SecurityHeaders())
|
|
s.router.Use(s.mw.CORS(s.params.Config.CORSAllowedOrigins))
|
|
s.router.Use(s.mw.MaxBodyBytes(maxRequestBodyBytes))
|
|
s.router.Use(middleware.Timeout(requestTimeout))
|
|
|
|
// The metrics go in a registry of this server's own, not in
|
|
// Prometheus' default one, which takes them only once per process.
|
|
registry := prometheus.NewRegistry()
|
|
registry.MustRegister(
|
|
collectors.NewGoCollector(),
|
|
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
|
)
|
|
|
|
// Requests are measured only once chi has matched them to one of
|
|
// these routes, by path and method. The metrics are labelled with
|
|
// both, which any client can make up, so measuring every request
|
|
// would let clients add labels without bound. A Route here would
|
|
// be matched by its path prefix alone, so each path is given in
|
|
// full.
|
|
s.router.Group(func(r chi.Router) {
|
|
// config.New refuses one of the two credentials without the
|
|
// other.
|
|
if s.params.Config.MetricsUsername != "" {
|
|
r.Use(s.mw.Metrics(registry))
|
|
}
|
|
|
|
r.Get("/.well-known/healthcheck", s.h.HandleHealthCheck())
|
|
|
|
r.With(s.mw.RateLimit(s.params.Config.ReportsPerMinute)).
|
|
Post("/api/v1/reports", s.h.HandleReport())
|
|
})
|
|
|
|
if s.params.Config.MetricsUsername != "" {
|
|
s.router.With(s.mw.MetricsAuth()).
|
|
Get("/metrics", promhttp.HandlerFor(
|
|
registry, promhttp.HandlerOpts{},
|
|
).ServeHTTP)
|
|
}
|
|
}
|