mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: mount pprof and metrics to /api/v2/debug for admins (#20353)
Adds the following debug routes for people with the `debug_info:read`
permission:
- `/api/v2/debug/pprof` for `net/http/pprof`
- `/`
- `/cmdline`
- `/profile`
- `/symbol`
- `/trace`
- `/*`
- `/api/v2/debug/metrics` for Prometheus metrics
This commit is contained in:
Generated
+132
@@ -954,6 +954,138 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/metrics": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug metrics",
|
||||
"operationId": "debug-metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug pprof index",
|
||||
"operationId": "debug-pprof-index",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/cmdline": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug pprof cmdline",
|
||||
"operationId": "debug-pprof-cmdline",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/profile": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug pprof profile",
|
||||
"operationId": "debug-pprof-profile",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/symbol": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug pprof symbol",
|
||||
"operationId": "debug-pprof-symbol",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/trace": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Debug"
|
||||
],
|
||||
"summary": "Debug pprof trace",
|
||||
"operationId": "debug-pprof-trace",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/tailnet": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
||||
Generated
+120
@@ -840,6 +840,126 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/metrics": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug metrics",
|
||||
"operationId": "debug-metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug pprof index",
|
||||
"operationId": "debug-pprof-index",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/cmdline": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug pprof cmdline",
|
||||
"operationId": "debug-pprof-cmdline",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/profile": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug pprof profile",
|
||||
"operationId": "debug-pprof-profile",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/symbol": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug pprof symbol",
|
||||
"operationId": "debug-pprof-symbol",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/pprof/trace": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Debug"],
|
||||
"summary": "Debug pprof trace",
|
||||
"operationId": "debug-pprof-trace",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/debug/tailnet": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
||||
+39
-1
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
httppprof "net/http/pprof"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
httpSwagger "github.com/swaggo/http-swagger/v2"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -1512,7 +1514,8 @@ func New(options *Options) *API {
|
||||
r.Route("/debug", func(r chi.Router) {
|
||||
r.Use(
|
||||
apiKeyMiddleware,
|
||||
// Ensure only owners can access debug endpoints.
|
||||
// Ensure only users with the debug_info:read (e.g. only owners)
|
||||
// can view debug endpoints.
|
||||
func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if !api.Authorize(r, policy.ActionRead, rbac.ResourceDebugInfo) {
|
||||
@@ -1545,6 +1548,41 @@ func New(options *Options) *API {
|
||||
})
|
||||
}
|
||||
r.Method("GET", "/expvar", expvar.Handler()) // contains DERP metrics as well as cmdline and memstats
|
||||
|
||||
r.Route("/pprof", func(r chi.Router) {
|
||||
r.Use(func(next http.Handler) http.Handler {
|
||||
// Some of the pprof handlers strip the `/debug/pprof`
|
||||
// prefix, so we need to strip our additional prefix as
|
||||
// well.
|
||||
return http.StripPrefix("/api/v2", next)
|
||||
})
|
||||
|
||||
// Serve the index HTML page.
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Redirect to include a trailing slash, otherwise links on
|
||||
// the generated HTML page will be broken.
|
||||
if !strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(w, r, "/api/v2/debug/pprof/", http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
httppprof.Index(w, r)
|
||||
})
|
||||
|
||||
// Handle any out of the box pprof handlers that don't get
|
||||
// dealt with by the default index handler. See httppprof.init.
|
||||
r.Get("/cmdline", httppprof.Cmdline)
|
||||
r.Get("/profile", httppprof.Profile)
|
||||
r.Get("/symbol", httppprof.Symbol)
|
||||
r.Get("/trace", httppprof.Trace)
|
||||
|
||||
// Index will handle any standard and custom runtime/pprof
|
||||
// profiles.
|
||||
r.Get("/*", httppprof.Index)
|
||||
})
|
||||
|
||||
r.Get("/metrics", promhttp.InstrumentMetricHandler(
|
||||
options.PrometheusRegistry, promhttp.HandlerFor(options.PrometheusRegistry, promhttp.HandlerOpts{}),
|
||||
).ServeHTTP)
|
||||
})
|
||||
// Manage OAuth2 applications that can use Coder as an OAuth2 provider.
|
||||
r.Route("/oauth2-provider", func(r chi.Router) {
|
||||
|
||||
@@ -160,8 +160,9 @@ func VerifySwaggerDefinitions(t *testing.T, router chi.Router, swaggerComments [
|
||||
t.Run(method+" "+route, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// This route is for compatibility purposes and is not documented.
|
||||
if route == "/workspaceagents/me/metadata" {
|
||||
// Wildcard routes break the swaggo parser, so we do not document
|
||||
// them.
|
||||
if strings.HasSuffix(route, "/*") {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -325,3 +325,57 @@ func loadDismissedHealthchecks(ctx context.Context, db database.Store, logger sl
|
||||
}
|
||||
return dismissedHealthchecks
|
||||
}
|
||||
|
||||
// @Summary Debug pprof index
|
||||
// @ID debug-pprof-index
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/pprof [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugPprofIndex(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
// @Summary Debug pprof cmdline
|
||||
// @ID debug-pprof-cmdline
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/pprof/cmdline [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugPprofCmdline(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
// @Summary Debug pprof profile
|
||||
// @ID debug-pprof-profile
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/pprof/profile [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugPprofProfile(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
// @Summary Debug pprof symbol
|
||||
// @ID debug-pprof-symbol
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/pprof/symbol [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugPprofSymbol(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
// @Summary Debug pprof trace
|
||||
// @ID debug-pprof-trace
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/pprof/trace [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugPprofTrace(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
// @Summary Debug metrics
|
||||
// @ID debug-metrics
|
||||
// @Security CoderSessionToken
|
||||
// @Success 200
|
||||
// @Tags Debug
|
||||
// @Router /debug/metrics [get]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func _debugMetrics(http.ResponseWriter, *http.Request) {} //nolint:unused
|
||||
|
||||
Reference in New Issue
Block a user