From 2916184661f99dc5f163b2c4b7828e0d82672822 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Wed, 14 Aug 2024 20:41:49 +0200 Subject: [PATCH] Now optionally enabling thye pprof endpoint with the --pprof flag. --- README.md | 20 ++++++++-- cmd/converge/converge.go | 80 ++++++++++++++++++++++++------------- cmd/converge/httpcontext.go | 5 ++- cmd/converge/pprof.go | 23 +++++++++++ kubernetes/deployment.yaml | 3 +- 5 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 cmd/converge/pprof.go diff --git a/README.md b/README.md index e30b619..105f104 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,21 @@ go install honnef.co/go/tools/cmd/staticcheck@v0.5.0 # Profiling ``` -go tool pprof -http 8081 http://localhost:8000/debug/pprof/profile?seconds=30 -go tool pprof -http 8081 http://localhost:8000/debug/pprof/heap -go tool pprof -http 8081 http://localhost:8000/debug/pprof/goroutine +go tool pprof -http :8081 http://localhost:8000/debug/pprof/profile?seconds=30 + +# sample for allocations +go tool pprof -http :8081 http://localhost:8000/debug/pprof/heap?seconds=10 +# show all memory +go tool pprof -http :8081 --alloc_space http://localhost:8000/debug/pprof/heap + +# sample_index values +# cpu: CPU time spent in each function +#alloc_objects: Number of allocated heap objects +#alloc_space: Amount of allocated heap memory +#inuse_objects: Number of heap objects in use at the time of profile collection +#inuse_space: Amount of heap memory in use at the time of profile collection +go tool pprof -http :8081 --sample_index=alloc_objects http://localhost:8000/debug/pprof/heap + + +go tool pprof -http :8081 http://localhost:8000/debug/pprof/goroutine ``` diff --git a/cmd/converge/converge.go b/cmd/converge/converge.go index bdc541b..aed35f4 100644 --- a/cmd/converge/converge.go +++ b/cmd/converge/converge.go @@ -52,7 +52,8 @@ func printHelp(msg string) { "--ccntext : by default all content is served at /. Use this option to specify\n" + " a different context path. For instance to host converge at a base\n" + " URL of https://example.com/converge/, specify /converge/ (with\n" + - " trailing slash. " + " trailing slash. \n" + + "--pprof: Enable the pprof endpoint at /debug/pprof" fmt.Fprintln(os.Stderr, helpText) os.Exit(1) } @@ -69,6 +70,7 @@ func main() { downloaddir := "." staticdir := "../static" contextpath := "/" + pprof := false args := os.Args[1:] for len(args) > 0 && strings.HasPrefix(args[0], "-") { @@ -91,6 +93,8 @@ func main() { } contextpath = args[1] args = args[1:] + case "--pprof": + pprof = true default: printHelp("Unknown option " + args[0]) } @@ -102,16 +106,59 @@ func main() { printHelp("") } + // Initializing the ocre system. + // Setup of websession handling for pushing notifications to the client + // Prometheus + // And the MatchMaker. The MatchMakers sends state notifications to websessions + // and prometheus. notifications := NewStateNotifier() websessions := matchmaker.NewWebSessions(notifications.webNotificationChannel) // monitoring - mux := http.NewServeMux() - setupPrometheus(mux, notifications.prometheusNotificationChannel) + prometheusMux := http.NewServeMux() + setupPrometheus(prometheusMux, notifications.prometheusNotificationChannel) go func() { - log.Fatal(http.ListenAndServe(":8001", mux)) + log.Fatal(http.ListenAndServe(":8001", prometheusMux)) }() admin := matchmaker.NewMatchMaker(notifications) + registrationService, clientService, sessionService := setupWebSockets(admin, websessions) + + context := HttpContext{mux: http.NewServeMux(), path: contextpath} + + if pprof { + registerPprof(context.mux, "/debug/pprof") + } + setupWebUI(context, registrationService, clientService, sessionService, staticdir, downloaddir) + // Catch all for the web UI + context.mux.HandleFunc("/", catchAllHandler(contextpath)) + + // Start HTTP server + fmt.Println("Rendez-vous server listening on :8000") + log.Fatal(http.ListenAndServe(":8000", context.mux)) +} + +func setupWebUI(context HttpContext, registrationService websocketutil.WebSocketService, clientService websocketutil.WebSocketService, sessionService websocketutil.WebSocketService, staticdir string, downloaddir string) HttpContext { + // The web UI + + context.HandleFunc("agent/", registrationService.Handle) + context.HandleFunc("client/", clientService.Handle) + context.HandleFunc("ws/sessions", sessionService.Handle) + + // create filehandler with templating for html files. + context.Handle("docs/", http.StripPrefix("docs/", http.HandlerFunc(pageHandler))) + context.Handle("static/", http.StripPrefix("static/", + http.FileServer(http.Dir(staticdir)))) + context.Handle("downloads/", http.StripPrefix("downloads/", + http.FileServer(http.Dir(downloaddir)))) + // create usage generator + context.HandleFunc("usage", generateCLIExammple) + + return context +} + +func setupWebSockets(admin *matchmaker.MatchMaker, websessions *matchmaker.WebSessions) (websocketutil.WebSocketService, websocketutil.WebSocketService, websocketutil.WebSocketService) { + // websocket endpoints + // For agents connecting registrationService := websocketutil.WebSocketService{ Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) { @@ -159,28 +206,5 @@ func main() { }, Text: true, } - - // websocket endpoints - - context := HttpContext{path: contextpath} - - context.HandleFunc("agent/", registrationService.Handle) - context.HandleFunc("client/", clientService.Handle) - context.HandleFunc("ws/sessions", sessionService.Handle) - - // create filehandler with templating for html files. - context.Handle("docs/", http.StripPrefix("docs/", http.HandlerFunc(pageHandler))) - context.Handle("static/", http.StripPrefix("static/", - http.FileServer(http.Dir(staticdir)))) - context.Handle("downloads/", http.StripPrefix("downloads/", - http.FileServer(http.Dir(downloaddir)))) - - // create usage generator - context.HandleFunc("usage", generateCLIExammple) - - http.HandleFunc("/", catchAllHandler(contextpath)) - - // Start HTTP server - fmt.Println("Rendez-vous server listening on :8000") - log.Fatal(http.ListenAndServe(":8000", nil)) + return registrationService, clientService, sessionService } diff --git a/cmd/converge/httpcontext.go b/cmd/converge/httpcontext.go index 04a81e7..e5e1181 100644 --- a/cmd/converge/httpcontext.go +++ b/cmd/converge/httpcontext.go @@ -5,13 +5,14 @@ import "net/http" // dealing with the context path in a simple way type HttpContext struct { + mux *http.ServeMux path string } func (context HttpContext) Handle(pattern string, handler http.Handler) { - http.Handle(context.path+pattern, http.StripPrefix(context.path, handler)) + context.mux.Handle(context.path+pattern, http.StripPrefix(context.path, handler)) } func (context HttpContext) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { - http.HandleFunc(context.path+pattern, handler) + context.mux.HandleFunc(context.path+pattern, handler) } diff --git a/cmd/converge/pprof.go b/cmd/converge/pprof.go new file mode 100644 index 0000000..9ae45c9 --- /dev/null +++ b/cmd/converge/pprof.go @@ -0,0 +1,23 @@ +package main + +import ( + "net/http" + "net/http/pprof" +) + +func registerPprof(mux *http.ServeMux, contextPath string) { + mux.HandleFunc(contextPath+"/", pprof.Index) + mux.HandleFunc(contextPath+"/cmdline", pprof.Cmdline) + mux.HandleFunc(contextPath+"/profile", pprof.Profile) + mux.HandleFunc(contextPath+"/symbol", pprof.Symbol) + mux.HandleFunc(contextPath+"/trace", pprof.Trace) + + // Add the allocs handler + mux.Handle("/debug/pprof/allocs", pprof.Handler("allocs")) + + // Optional: Add other pprof handlers + mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine")) + mux.Handle("/debug/pprof/heap", pprof.Handler("heap")) + mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate")) + mux.Handle("/debug/pprof/block", pprof.Handler("block")) +} diff --git a/kubernetes/deployment.yaml b/kubernetes/deployment.yaml index e1b2539..7f0a39e 100644 --- a/kubernetes/deployment.yaml +++ b/kubernetes/deployment.yaml @@ -24,4 +24,5 @@ spec: name: http - containerPort: 8001 name: prometheus - + args: + - --pprof