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-.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.ReplaceAll(time.Now().Format(time.RFC3339), ":", ""))) var err error f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o666) 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 }