Now optionally enabling thye pprof endpoint with the --pprof flag.

This commit is contained in:
Erik Brakkee 2024-08-14 20:41:49 +02:00
parent eb145b2374
commit 2916184661
5 changed files with 97 additions and 34 deletions

View File

@ -14,7 +14,21 @@ go install honnef.co/go/tools/cmd/staticcheck@v0.5.0
# Profiling # Profiling
``` ```
go tool pprof -http 8081 http://localhost:8000/debug/pprof/profile?seconds=30 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 # 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
``` ```

View File

@ -52,7 +52,8 @@ func printHelp(msg string) {
"--ccntext <contextpath>: by default all content is served at /. Use this option to specify\n" + "--ccntext <contextpath>: 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" + " a different context path. For instance to host converge at a base\n" +
" URL of https://example.com/converge/, specify /converge/ (with\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) fmt.Fprintln(os.Stderr, helpText)
os.Exit(1) os.Exit(1)
} }
@ -69,6 +70,7 @@ func main() {
downloaddir := "." downloaddir := "."
staticdir := "../static" staticdir := "../static"
contextpath := "/" contextpath := "/"
pprof := false
args := os.Args[1:] args := os.Args[1:]
for len(args) > 0 && strings.HasPrefix(args[0], "-") { for len(args) > 0 && strings.HasPrefix(args[0], "-") {
@ -91,6 +93,8 @@ func main() {
} }
contextpath = args[1] contextpath = args[1]
args = args[1:] args = args[1:]
case "--pprof":
pprof = true
default: default:
printHelp("Unknown option " + args[0]) printHelp("Unknown option " + args[0])
} }
@ -102,16 +106,59 @@ func main() {
printHelp("") 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() notifications := NewStateNotifier()
websessions := matchmaker.NewWebSessions(notifications.webNotificationChannel) websessions := matchmaker.NewWebSessions(notifications.webNotificationChannel)
// monitoring // monitoring
mux := http.NewServeMux() prometheusMux := http.NewServeMux()
setupPrometheus(mux, notifications.prometheusNotificationChannel) setupPrometheus(prometheusMux, notifications.prometheusNotificationChannel)
go func() { go func() {
log.Fatal(http.ListenAndServe(":8001", mux)) log.Fatal(http.ListenAndServe(":8001", prometheusMux))
}() }()
admin := matchmaker.NewMatchMaker(notifications) 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 // For agents connecting
registrationService := websocketutil.WebSocketService{ registrationService := websocketutil.WebSocketService{
Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) { Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) {
@ -159,28 +206,5 @@ func main() {
}, },
Text: true, Text: true,
} }
return registrationService, clientService, sessionService
// 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))
} }

View File

@ -5,13 +5,14 @@ import "net/http"
// dealing with the context path in a simple way // dealing with the context path in a simple way
type HttpContext struct { type HttpContext struct {
mux *http.ServeMux
path string path string
} }
func (context HttpContext) Handle(pattern string, handler http.Handler) { 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)) { 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)
} }

23
cmd/converge/pprof.go Normal file
View File

@ -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"))
}

View File

@ -24,4 +24,5 @@ spec:
name: http name: http
- containerPort: 8001 - containerPort: 8001
name: prometheus name: prometheus
args:
- --pprof