diff --git a/changelog/25391.txt b/changelog/25391.txt new file mode 100644 index 0000000000..522cbe849f --- /dev/null +++ b/changelog/25391.txt @@ -0,0 +1,4 @@ +```release-note:improvement +command/server: Removed environment variable requirement to generate pprof +files using SIGUSR2. Added CPU profile support. +``` diff --git a/command/server.go b/command/server.go index 8aee4c18b8..6b79e40586 100644 --- a/command/server.go +++ b/command/server.go @@ -1760,42 +1760,43 @@ func (c *ServerCommand) Run(args []string) int { // We can only get pprof outputs via the API but sometimes Vault can get // into a state where it cannot process requests so we can get pprof outputs // via SIGUSR2. - if os.Getenv("VAULT_PPROF_WRITE_TO_FILE") != "" { - dir := "" - path := os.Getenv("VAULT_PPROF_FILE_PATH") - if path != "" { - if _, err := os.Stat(path); err != nil { - c.logger.Error("Checking pprof path failed", "error", err) - continue - } - dir = path - } else { - dir, err = os.MkdirTemp("", "vault-pprof") - if err != nil { - c.logger.Error("Could not create temporary directory for pprof", "error", err) - continue - } + pprofPath := filepath.Join(os.TempDir(), "vault-pprof") + err := os.MkdirAll(pprofPath, os.ModePerm) + if err != nil { + c.logger.Error("Could not create temporary directory for pprof", "error", err) + continue + } + + dumps := []string{"goroutine", "heap", "allocs", "threadcreate", "profile"} + for _, dump := range dumps { + pFile, err := os.Create(filepath.Join(pprofPath, dump)) + if err != nil { + c.logger.Error("error creating pprof file", "name", dump, "error", err) + break } - dumps := []string{"goroutine", "heap", "allocs", "threadcreate"} - for _, dump := range dumps { - pFile, err := os.Create(filepath.Join(dir, dump)) - if err != nil { - c.logger.Error("error creating pprof file", "name", dump, "error", err) - break - } - + if dump != "profile" { err = pprof.Lookup(dump).WriteTo(pFile, 0) if err != nil { c.logger.Error("error generating pprof data", "name", dump, "error", err) pFile.Close() break } - pFile.Close() + } else { + // CPU profiles need to run for a duration so we're going to run it + // just for one second to avoid blocking here. + if err := pprof.StartCPUProfile(pFile); err != nil { + c.logger.Error("could not start CPU profile: ", err) + pFile.Close() + break + } + time.Sleep(time.Second * 1) + pprof.StopCPUProfile() } - - c.logger.Info(fmt.Sprintf("Wrote pprof files to: %s", dir)) + pFile.Close() } + + c.logger.Info(fmt.Sprintf("Wrote pprof files to: %s", pprofPath)) } } // Notify systemd that the server is shutting down