diff --git a/changelog/17929.txt b/changelog/17929.txt new file mode 100644 index 000000000..72b639c18 --- /dev/null +++ b/changelog/17929.txt @@ -0,0 +1,4 @@ +```release-note:improvement +core/server: Added an environment variable to write goroutine stacktraces to a +temporary file for SIGUSR2 signals. +``` diff --git a/command/server.go b/command/server.go index d4e960f16..52ecec5d0 100644 --- a/command/server.go +++ b/command/server.go @@ -1760,6 +1760,41 @@ func (c *ServerCommand) Run(args []string) int { case <-c.SigUSR2Ch: logWriter := c.logger.StandardWriter(&hclog.StandardLoggerOptions{}) pprof.Lookup("goroutine").WriteTo(logWriter, 2) + + if os.Getenv("VAULT_STACKTRACE_WRITE_TO_FILE") != "" { + c.logger.Info("Writing stacktrace to file") + + dir := "" + path := os.Getenv("VAULT_STACKTRACE_FILE_PATH") + if path != "" { + if _, err := os.Stat(path); err != nil { + c.logger.Error("Checking stacktrace path failed", "error", err) + continue + } + dir = path + } else { + dir, err = os.MkdirTemp("", "vault-stacktrace") + if err != nil { + c.logger.Error("Could not create temporary directory for stacktrace", "error", err) + continue + } + } + + f, err := os.CreateTemp(dir, "stacktrace") + if err != nil { + c.logger.Error("Could not create stacktrace file", "error", err) + continue + } + + if err := pprof.Lookup("goroutine").WriteTo(f, 2); err != nil { + f.Close() + c.logger.Error("Could not write stacktrace to file", "error", err) + continue + } + + c.logger.Info(fmt.Sprintf("Wrote stacktrace to: %s", f.Name())) + f.Close() + } } } // Notify systemd that the server is shutting down