123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 |
- 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.ReplaceAll(time.Now().Format(time.RFC3339), ":", "")))
- 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
- }
|