github.com/rawahars/moby@v24.0.4+incompatible/pkg/stack/stackdump.go (about)

     1  package stack // import "github.com/docker/docker/pkg/stack"
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  const stacksLogNameTemplate = "goroutine-stacks-%s.log"
    15  
    16  // Dump outputs the runtime stack to os.StdErr.
    17  func Dump() {
    18  	_ = dump(os.Stderr)
    19  }
    20  
    21  // DumpToFile appends the runtime stack into a file named "goroutine-stacks-<timestamp>.log"
    22  // in dir and returns the full path to that file. If no directory name is
    23  // provided, it outputs to os.Stderr.
    24  func DumpToFile(dir string) (string, error) {
    25  	var f *os.File
    26  	if dir != "" {
    27  		path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.ReplaceAll(time.Now().Format(time.RFC3339), ":", "")))
    28  		var err error
    29  		f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
    30  		if err != nil {
    31  			return "", errors.Wrap(err, "failed to open file to write the goroutine stacks")
    32  		}
    33  		defer f.Close()
    34  		defer f.Sync()
    35  	} else {
    36  		f = os.Stderr
    37  	}
    38  	return f.Name(), dump(f)
    39  }
    40  
    41  func dump(f *os.File) error {
    42  	var (
    43  		buf       []byte
    44  		stackSize int
    45  	)
    46  	bufferLen := 16384
    47  	for stackSize == len(buf) {
    48  		buf = make([]byte, bufferLen)
    49  		stackSize = runtime.Stack(buf, true)
    50  		bufferLen *= 2
    51  	}
    52  	buf = buf[:stackSize]
    53  	if _, err := f.Write(buf); err != nil {
    54  		return errors.Wrap(err, "failed to write goroutine stacks")
    55  	}
    56  	return nil
    57  }