[chore/bugfix] Fix double gzip on prometheus endpoint (#2383)
* [chore] Move "/metrics" into separate API module * use our own gzip middleware for prom
This commit is contained in:
parent
2033915aaf
commit
2b9cf56f56
|
@ -293,6 +293,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
|||
var (
|
||||
authModule = api.NewAuth(dbService, processor, idp, routerSession, sessionName) // auth/oauth paths
|
||||
clientModule = api.NewClient(dbService, processor) // api client endpoints
|
||||
metricsModule = api.NewMetrics() // Metrics endpoints
|
||||
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
||||
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
||||
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
|
||||
|
@ -322,6 +323,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
|||
// apply throttling *after* rate limiting
|
||||
authModule.Route(router, clLimit, clThrottle, gzip)
|
||||
clientModule.Route(router, clLimit, clThrottle, gzip)
|
||||
metricsModule.Route(router, clLimit, clThrottle, gzip)
|
||||
fileserverModule.Route(router, fsLimit, fsThrottle)
|
||||
wellKnownModule.Route(router, gzip, s2sLimit, s2sThrottle)
|
||||
nodeInfoModule.Route(router, s2sLimit, s2sThrottle, gzip)
|
||||
|
|
|
@ -212,6 +212,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
|||
var (
|
||||
authModule = api.NewAuth(state.DB, processor, idp, routerSession, sessionName) // auth/oauth paths
|
||||
clientModule = api.NewClient(state.DB, processor) // api client endpoints
|
||||
metricsModule = api.NewMetrics() // Metrics endpoints
|
||||
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
||||
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
||||
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
|
||||
|
@ -222,6 +223,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
|||
// these should be routed in order
|
||||
authModule.Route(router)
|
||||
clientModule.Route(router)
|
||||
metricsModule.Route(router)
|
||||
fileserverModule.Route(router)
|
||||
wellKnownModule.Route(router)
|
||||
nodeInfoModule.Route(router)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/metrics"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/middleware"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/router"
|
||||
)
|
||||
|
||||
type Metrics struct {
|
||||
metrics *metrics.Module
|
||||
}
|
||||
|
||||
func (mt *Metrics) Route(r *router.Router, m ...gin.HandlerFunc) {
|
||||
if !config.GetMetricsEnabled() {
|
||||
// Noop: metrics
|
||||
// not enabled.
|
||||
return
|
||||
}
|
||||
|
||||
// Create new group on top level "metrics" prefix.
|
||||
metricsGroup := r.AttachGroup("metrics")
|
||||
metricsGroup.Use(m...)
|
||||
metricsGroup.Use(
|
||||
middleware.CacheControl(middleware.CacheControlConfig{
|
||||
// Never cache metrics responses.
|
||||
Directives: []string{"no-store"},
|
||||
}),
|
||||
)
|
||||
|
||||
// Attach basic auth if enabled.
|
||||
if config.GetMetricsAuthEnabled() {
|
||||
var (
|
||||
username = config.GetMetricsAuthUsername()
|
||||
password = config.GetMetricsAuthPassword()
|
||||
accounts = gin.Accounts{username: password}
|
||||
)
|
||||
metricsGroup.Use(gin.BasicAuth(accounts))
|
||||
}
|
||||
|
||||
mt.metrics.Route(metricsGroup.Handle)
|
||||
}
|
||||
|
||||
func NewMetrics() *Metrics {
|
||||
return &Metrics{
|
||||
metrics: metrics.New(),
|
||||
}
|
||||
}
|
|
@ -15,19 +15,40 @@
|
|||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package web
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
const (
|
||||
metricsPath = "/metrics"
|
||||
metricsUser = "metrics"
|
||||
)
|
||||
|
||||
func (m *Module) metricsGETHandler(c *gin.Context) {
|
||||
h := promhttp.Handler()
|
||||
h.ServeHTTP(c.Writer, c.Request)
|
||||
type Module struct {
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func New() *Module {
|
||||
// Use our own gzip handler.
|
||||
opts := promhttp.HandlerOpts{
|
||||
DisableCompression: true,
|
||||
}
|
||||
|
||||
// Instrument handler itself.
|
||||
handler := promhttp.InstrumentMetricHandler(
|
||||
prometheus.DefaultRegisterer,
|
||||
promhttp.HandlerFor(prometheus.DefaultGatherer, opts),
|
||||
)
|
||||
|
||||
return &Module{
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
|
||||
attachHandler(http.MethodGet, "", func(c *gin.Context) {
|
||||
// Defer all "/metrics" handling to prom.
|
||||
m.handler.ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
}
|
|
@ -110,19 +110,6 @@ func (m *Module) Route(r *router.Router, mi ...gin.HandlerFunc) {
|
|||
r.AttachHandler(http.MethodGet, domainBlockListPath, m.domainBlockListGETHandler)
|
||||
r.AttachHandler(http.MethodGet, tagsPath, m.tagGETHandler)
|
||||
|
||||
// Prometheus metrics export endpoint
|
||||
if config.GetMetricsEnabled() {
|
||||
metricsGroup := r.AttachGroup(metricsPath)
|
||||
metricsGroup.Use(mi...)
|
||||
// Attach basic auth if enabled
|
||||
if config.GetMetricsAuthEnabled() {
|
||||
metricsGroup.Use(gin.BasicAuth(gin.Accounts{
|
||||
config.GetMetricsAuthUsername(): config.GetMetricsAuthPassword(),
|
||||
}))
|
||||
}
|
||||
metricsGroup.Handle(http.MethodGet, "", m.metricsGETHandler)
|
||||
}
|
||||
|
||||
// Attach redirects from old endpoints to current ones for backwards compatibility
|
||||
r.AttachHandler(http.MethodGet, "/auth/edit", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, userPanelPath) })
|
||||
r.AttachHandler(http.MethodGet, "/user", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, userPanelPath) })
|
||||
|
|
Loading…
Reference in New Issue