From 9063a32fe145eb35b0db4c81031c449f17f72b29 Mon Sep 17 00:00:00 2001 From: Benjamin Pickard Date: Mon, 18 May 2026 16:05:31 -0400 Subject: [PATCH] Add optional pprof endpoint support to multus-daemon Add pprof profiling endpoints to the metrics server, gated behind a new EnablePprof config field. When enabled, standard Go pprof handlers are registered on the metrics port under /debug/pprof/. This also improves the metrics server setup: - Use dedicated http.ServeMux instead of DefaultServeMux - Move mux/handler setup outside the retry loop - Use http.Server with ReadHeaderTimeout for resource safety - Add graceful shutdown on context cancellation Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Benjamin Pickard --- cmd/multus-daemon/main.go | 28 +++++++++++++++++++++++++--- pkg/server/types.go | 3 ++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cmd/multus-daemon/main.go b/cmd/multus-daemon/main.go index b361ca00a..c30bbb2e7 100644 --- a/cmd/multus-daemon/main.go +++ b/cmd/multus-daemon/main.go @@ -22,12 +22,14 @@ import ( "fmt" "io" "net/http" + "net/http/pprof" "os" "os/signal" "os/user" "path/filepath" "sync" "syscall" + "time" utilwait "k8s.io/apimachinery/pkg/util/wait" @@ -155,11 +157,31 @@ func startMultusDaemon(ctx context.Context, daemonConfig *srv.ControllerNetConf, } if daemonConfig.MetricsPort != nil { + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.Handler()) + if daemonConfig.EnablePprof != nil && *daemonConfig.EnablePprof { + mux.HandleFunc("/debug/pprof/", pprof.Index) + mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + logging.Verbosef("pprof endpoints enabled on metrics port %d", *daemonConfig.MetricsPort) + } + metricsSrv := &http.Server{ + Addr: fmt.Sprintf(":%d", *daemonConfig.MetricsPort), + Handler: mux, + ReadHeaderTimeout: 10 * time.Second, + } + logging.Debugf("metrics port: %d", *daemonConfig.MetricsPort) go utilwait.UntilWithContext(ctx, func(_ context.Context) { - http.Handle("/metrics", promhttp.Handler()) - logging.Debugf("metrics port: %d", *daemonConfig.MetricsPort) - logging.Debugf("metrics: %s", http.ListenAndServe(fmt.Sprintf(":%d", *daemonConfig.MetricsPort), nil)) + if err := metricsSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logging.Debugf("metrics server error: %v", err) + } }, 0) + go func() { + <-ctx.Done() + metricsSrv.Shutdown(context.Background()) + }() } l, err := srv.GetListener(api.SocketPath(daemonConfig.SocketDir)) diff --git a/pkg/server/types.go b/pkg/server/types.go index 81d4d6819..4a24905f1 100644 --- a/pkg/server/types.go +++ b/pkg/server/types.go @@ -78,7 +78,8 @@ type ControllerNetConf struct { LogToStderr bool `json:"logToStderr,omitempty"` PerNodeCertificate *PerNodeCertificate `json:"perNodeCertificate,omitempty"` - MetricsPort *int `json:"metricsPort,omitempty"` + MetricsPort *int `json:"metricsPort,omitempty"` + EnablePprof *bool `json:"enablePprof,omitempty"` // Option to point to the path of the unix domain socket through which the // multus client / server communicate.