moby/pkg/stack/stackdump.go
Sebastiaan van Stijn ea5c94cdb9
pkg/signal: move signal.DumpStacks() to a separate package
It is not directly related to signal-handling, so can well live
in its own package.

Also added a variant that doesn't take a directory to write files
to, for easier consumption / better match to how it's used.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-07-15 18:09:43 +02:00

57 lines
1.3 KiB
Go

package stack // import "github.com/docker/docker/pkg/stack"
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/pkg/errors"
)
const stacksLogNameTemplate = "goroutine-stacks-%s.log"
// Dump outputs the runtime stack to os.StdErr.
func Dump() {
_ = dump(os.Stderr)
}
// DumpToFile appends the runtime stack into a file named "goroutine-stacks-<timestamp>.log"
// in dir and returns the full path to that file. If no directory name is
// provided, it outputs to os.Stderr.
func DumpToFile(dir string) (string, error) {
var f *os.File
if dir != "" {
path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1)))
var err error
f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return "", errors.Wrap(err, "failed to open file to write the goroutine stacks")
}
defer f.Close()
defer f.Sync()
} else {
f = os.Stderr
}
return f.Name(), dump(f)
}
func dump(f *os.File) error {
var (
buf []byte
stackSize int
)
bufferLen := 16384
for stackSize == len(buf) {
buf = make([]byte, bufferLen)
stackSize = runtime.Stack(buf, true)
bufferLen *= 2
}
buf = buf[:stackSize]
if _, err := f.Write(buf); err != nil {
return errors.Wrap(err, "failed to write goroutine stacks")
}
return nil
}