vault/helper/trace/debug_trace.go
Bruno Oliveira de Souza a2c467cc22
VAULT-31409: trace postUnseal function (#28895)
* initial implementation of unseal trace

* close file if we fail to start the trace

didn't bother to check the error from traceFile.Close()

* use reloadable config instead of env var

* license

* remove leftover

* allow setting custom dir and remove new package

* bring back StartDebugTrace

after talking to Kuba it sounds like it's a good idea to try to move stuff out of core, so even if there's no immediate need for a generic debug trace function it's still fair to add it

* track postUnseal instead of unsealInternal

also some usability improvements from manual testing

* address PR comments

* address security review

there were concerns about using the /tmp directory because of permissions, or having a default dir at all, so now it's required to set a dir in order to generate the traces.

* add unit tests to StartDebugTrace

* move back to default dir

* document new parameters

* add tiny integration test

* avoid column in trace filename

sounds like it might be forbidden in Windows and possibly cause problems in some MacOS applications.

* address PR feedback

* add go doc to test

CI was complaining about missing comments on the new test function. It feels a bit silly to require this of tests but whatever XD

* fix tests
2024-11-26 15:04:34 -03:00

64 lines
1.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package trace
import (
"fmt"
"os"
"path/filepath"
"runtime/trace"
"time"
)
func StartDebugTrace(dir string, filePrefix string) (file string, stop func() error, err error) {
dirMustExist := true
if dir == "" {
dirMustExist = false // if a dir is provided it must exist, otherwise we'll create a default one
dir = filepath.Join(os.TempDir(), "vault-traces")
}
d, err := os.Stat(dir)
if err != nil && !os.IsNotExist(err) {
return "", nil, fmt.Errorf("failed to stat trace directory %q: %s", dir, err)
}
if os.IsNotExist(err) && dirMustExist {
return "", nil, fmt.Errorf("trace directory %q does not exist", dir)
}
if !os.IsNotExist(err) && !d.IsDir() {
return "", nil, fmt.Errorf("trace directory %q is not a directory", dir)
}
if os.IsNotExist(err) {
if err := os.Mkdir(dir, 0o700); err != nil {
return "", nil, fmt.Errorf("failed to create trace directory %q: %s", dir, err)
}
}
// would prefer a more human readable time reference in the file name but the column
// character can cause problems in filenames
fileName := fmt.Sprintf("%s-%d.trace", filePrefix, time.Now().Unix())
traceFile, err := filepath.Abs(filepath.Join(dir, fileName))
if err != nil {
return "", nil, fmt.Errorf("failed to get absolute path for trace file: %s", err)
}
f, err := os.Create(traceFile)
if err != nil {
return "", nil, fmt.Errorf("failed to create trace file %q: %s", traceFile, err)
}
if err := trace.Start(f); err != nil {
f.Close()
return "", nil, fmt.Errorf("failed to start trace: %s", err)
}
stop = func() error {
trace.Stop()
return f.Close()
}
return f.Name(), stop, nil
}