diff --git a/authentik/lib/sentry.py b/authentik/lib/sentry.py index 94b48b8aa..10057d84e 100644 --- a/authentik/lib/sentry.py +++ b/authentik/lib/sentry.py @@ -85,8 +85,9 @@ def sentry_init(**sentry_init_kwargs): def traces_sampler(sampling_context: dict) -> float: """Custom sampler to ignore certain routes""" + path = sampling_context.get("asgi_scope", {}).get("path", "") # Ignore all healthcheck routes - if sampling_context.get("asgi_scope", {}).get("path", "").startswith("/-/health/"): + if path.startswith("/-/health") or path.startswith("/-/metrics"): return 0 return float(CONFIG.y("error_reporting.sample_rate", 0.5)) diff --git a/authentik/root/urls.py b/authentik/root/urls.py index 6a7385d28..e1874a041 100644 --- a/authentik/root/urls.py +++ b/authentik/root/urls.py @@ -44,7 +44,7 @@ for _authentik_app in get_apps(): ) urlpatterns += [ - path("metrics/", MetricsView.as_view(), name="metrics"), + path("-/metrics/", MetricsView.as_view(), name="metrics"), path("-/health/live/", LiveView.as_view(), name="health-live"), path("-/health/ready/", ReadyView.as_view(), name="health-ready"), ] diff --git a/cmd/server/main.go b/cmd/server/main.go index 583925b3a..02b0164a5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -15,6 +15,7 @@ import ( "goauthentik.io/internal/gounicorn" "goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/proxyv2" + sentryutils "goauthentik.io/internal/utils/sentry" "goauthentik.io/internal/web" "goauthentik.io/internal/web/tenant_tls" ) @@ -51,7 +52,7 @@ func main() { err := sentry.Init(sentry.ClientOptions{ Dsn: config.G.ErrorReporting.DSN, AttachStacktrace: true, - TracesSampleRate: config.G.ErrorReporting.SampleRate, + TracesSampler: sentryutils.SamplerFunc(config.G.ErrorReporting.SampleRate), Release: fmt.Sprintf("authentik@%s", constants.VERSION), Environment: config.G.ErrorReporting.Environment, IgnoreErrors: []string{ diff --git a/internal/outpost/ak/global.go b/internal/outpost/ak/global.go index 154ce4a0d..1b7136fd8 100644 --- a/internal/outpost/ak/global.go +++ b/internal/outpost/ak/global.go @@ -11,6 +11,7 @@ import ( log "github.com/sirupsen/logrus" "goauthentik.io/api/v3" "goauthentik.io/internal/constants" + sentryutils "goauthentik.io/internal/utils/sentry" ) var initialSetup = false @@ -47,10 +48,10 @@ func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) { l.WithField("env", globalConfig.ErrorReporting.Environment).Debug("Error reporting enabled") } err := sentry.Init(sentry.ClientOptions{ - Dsn: dsn, - Environment: globalConfig.ErrorReporting.Environment, - TracesSampleRate: float64(globalConfig.ErrorReporting.TracesSampleRate), - Release: fmt.Sprintf("authentik@%s", constants.VERSION), + Dsn: dsn, + Environment: globalConfig.ErrorReporting.Environment, + TracesSampler: sentryutils.SamplerFunc(float64(globalConfig.ErrorReporting.TracesSampleRate)), + Release: fmt.Sprintf("authentik@%s", constants.VERSION), IgnoreErrors: []string{ http.ErrAbortHandler.Error(), }, diff --git a/internal/outpost/ldap/metrics/metrics.go b/internal/outpost/ldap/metrics/metrics.go index ecccb73d9..bbe233691 100644 --- a/internal/outpost/ldap/metrics/metrics.go +++ b/internal/outpost/ldap/metrics/metrics.go @@ -4,6 +4,7 @@ import ( "net/http" log "github.com/sirupsen/logrus" + "goauthentik.io/internal/utils/sentry" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" @@ -25,6 +26,7 @@ var ( func RunServer() { m := mux.NewRouter() l := log.WithField("logger", "authentik.outpost.metrics") + m.Use(sentry.SentryNoSampleMiddleware) m.HandleFunc("/outpost.goauthentik.io/ping", func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(204) }) diff --git a/internal/outpost/proxyv2/handlers.go b/internal/outpost/proxyv2/handlers.go index d547542af..bbcd567b2 100644 --- a/internal/outpost/proxyv2/handlers.go +++ b/internal/outpost/proxyv2/handlers.go @@ -11,6 +11,7 @@ import ( "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/proxyv2/application" "goauthentik.io/internal/outpost/proxyv2/metrics" + sentryutils "goauthentik.io/internal/utils/sentry" "goauthentik.io/internal/utils/web" staticWeb "goauthentik.io/web" ) @@ -89,7 +90,7 @@ func (ps *ProxyServer) Handle(rw http.ResponseWriter, r *http.Request) { return } if strings.HasPrefix(r.URL.Path, "/outpost.goauthentik.io/ping") { - ps.HandlePing(rw, r) + sentryutils.SentryNoSample(ps.HandlePing)(rw, r) return } a, host := ps.lookupApp(r) diff --git a/internal/outpost/proxyv2/metrics/metrics.go b/internal/outpost/proxyv2/metrics/metrics.go index 770d2ce01..2848fff94 100644 --- a/internal/outpost/proxyv2/metrics/metrics.go +++ b/internal/outpost/proxyv2/metrics/metrics.go @@ -4,6 +4,7 @@ import ( "net/http" log "github.com/sirupsen/logrus" + "goauthentik.io/internal/utils/sentry" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" @@ -25,6 +26,7 @@ var ( func RunServer() { m := mux.NewRouter() l := log.WithField("logger", "authentik.outpost.metrics") + m.Use(sentry.SentryNoSampleMiddleware) m.HandleFunc("/outpost.goauthentik.io/ping", func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(204) }) diff --git a/internal/outpost/proxyv2/proxyv2.go b/internal/outpost/proxyv2/proxyv2.go index 8159e27c0..7cf87b66a 100644 --- a/internal/outpost/proxyv2/proxyv2.go +++ b/internal/outpost/proxyv2/proxyv2.go @@ -18,6 +18,7 @@ import ( "goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/proxyv2/application" "goauthentik.io/internal/outpost/proxyv2/metrics" + sentryutils "goauthentik.io/internal/utils/sentry" "goauthentik.io/internal/utils/web" ) @@ -65,7 +66,7 @@ func NewProxyServer(ac *ak.APIController, portOffset int) *ProxyServer { defaultCert: defaultCert, } globalMux.PathPrefix("/outpost.goauthentik.io/static").HandlerFunc(s.HandleStatic) - globalMux.Path("/outpost.goauthentik.io/ping").HandlerFunc(s.HandlePing) + globalMux.Path("/outpost.goauthentik.io/ping").HandlerFunc(sentryutils.SentryNoSample(s.HandlePing)) rootMux.PathPrefix("/").HandlerFunc(s.Handle) return s } diff --git a/internal/utils/sentry/sentry.go b/internal/utils/sentry/sentry.go new file mode 100644 index 000000000..fb3f04d01 --- /dev/null +++ b/internal/utils/sentry/sentry.go @@ -0,0 +1,34 @@ +package sentry + +import ( + "context" + "net/http" + + "github.com/getsentry/sentry-go" +) + +type contextSentryNoSample struct{} + +func SentryNoSample(handler func(rw http.ResponseWriter, r *http.Request)) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), contextSentryNoSample{}, true) + handler(w, r.WithContext(ctx)) + } +} + +func SentryNoSampleMiddleware(h http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), contextSentryNoSample{}, true) + h.ServeHTTP(rw, r.WithContext(ctx)) + }) +} + +func SamplerFunc(defaultRate float64) sentry.TracesSamplerFunc { + return sentry.TracesSamplerFunc(func(ctx sentry.SamplingContext) sentry.Sampled { + data, ok := ctx.Span.Context().Value(contextSentryNoSample{}).(bool) + if data && ok { + return sentry.SampledFalse + } + return sentry.UniformTracesSampler(defaultRate).Sample(ctx) + }) +} diff --git a/internal/web/metrics.go b/internal/web/metrics.go index 8762910bb..b102aab64 100644 --- a/internal/web/metrics.go +++ b/internal/web/metrics.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" "goauthentik.io/internal/config" + "goauthentik.io/internal/utils/sentry" ) var ( @@ -22,6 +23,7 @@ var ( func RunMetricsServer() { m := mux.NewRouter() l := log.WithField("logger", "authentik.router.metrics") + m.Use(sentry.SentryNoSampleMiddleware) m.Path("/metrics").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { promhttp.InstrumentMetricHandler( prometheus.DefaultRegisterer, promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{ @@ -30,7 +32,7 @@ func RunMetricsServer() { ).ServeHTTP(rw, r) // Get upstream metrics - re, err := http.NewRequest("GET", "http://localhost:8000/metrics/", nil) + re, err := http.NewRequest("GET", "http://localhost:8000/-/metrics/", nil) if err != nil { l.WithError(err).Warning("failed to get upstream metrics") return