[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 (
|
var (
|
||||||
authModule = api.NewAuth(dbService, processor, idp, routerSession, sessionName) // auth/oauth paths
|
authModule = api.NewAuth(dbService, processor, idp, routerSession, sessionName) // auth/oauth paths
|
||||||
clientModule = api.NewClient(dbService, processor) // api client endpoints
|
clientModule = api.NewClient(dbService, processor) // api client endpoints
|
||||||
|
metricsModule = api.NewMetrics() // Metrics endpoints
|
||||||
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
||||||
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
||||||
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
|
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
|
||||||
|
@ -322,6 +323,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
// apply throttling *after* rate limiting
|
// apply throttling *after* rate limiting
|
||||||
authModule.Route(router, clLimit, clThrottle, gzip)
|
authModule.Route(router, clLimit, clThrottle, gzip)
|
||||||
clientModule.Route(router, clLimit, clThrottle, gzip)
|
clientModule.Route(router, clLimit, clThrottle, gzip)
|
||||||
|
metricsModule.Route(router, clLimit, clThrottle, gzip)
|
||||||
fileserverModule.Route(router, fsLimit, fsThrottle)
|
fileserverModule.Route(router, fsLimit, fsThrottle)
|
||||||
wellKnownModule.Route(router, gzip, s2sLimit, s2sThrottle)
|
wellKnownModule.Route(router, gzip, s2sLimit, s2sThrottle)
|
||||||
nodeInfoModule.Route(router, s2sLimit, s2sThrottle, gzip)
|
nodeInfoModule.Route(router, s2sLimit, s2sThrottle, gzip)
|
||||||
|
|
|
@ -212,6 +212,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
var (
|
var (
|
||||||
authModule = api.NewAuth(state.DB, processor, idp, routerSession, sessionName) // auth/oauth paths
|
authModule = api.NewAuth(state.DB, processor, idp, routerSession, sessionName) // auth/oauth paths
|
||||||
clientModule = api.NewClient(state.DB, processor) // api client endpoints
|
clientModule = api.NewClient(state.DB, processor) // api client endpoints
|
||||||
|
metricsModule = api.NewMetrics() // Metrics endpoints
|
||||||
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
|
||||||
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
|
||||||
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
|
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
|
// these should be routed in order
|
||||||
authModule.Route(router)
|
authModule.Route(router)
|
||||||
clientModule.Route(router)
|
clientModule.Route(router)
|
||||||
|
metricsModule.Route(router)
|
||||||
fileserverModule.Route(router)
|
fileserverModule.Route(router)
|
||||||
wellKnownModule.Route(router)
|
wellKnownModule.Route(router)
|
||||||
nodeInfoModule.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
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package web
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type Module struct {
|
||||||
metricsPath = "/metrics"
|
handler http.Handler
|
||||||
metricsUser = "metrics"
|
}
|
||||||
)
|
|
||||||
|
func New() *Module {
|
||||||
func (m *Module) metricsGETHandler(c *gin.Context) {
|
// Use our own gzip handler.
|
||||||
h := promhttp.Handler()
|
opts := promhttp.HandlerOpts{
|
||||||
h.ServeHTTP(c.Writer, c.Request)
|
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, domainBlockListPath, m.domainBlockListGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, tagsPath, m.tagGETHandler)
|
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
|
// 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, "/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) })
|
r.AttachHandler(http.MethodGet, "/user", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, userPanelPath) })
|
||||||
|
|
Loading…
Reference in New Issue