浏览代码

Merge pull request #27951 from LK4D4/dump_always_to_file

daemon: always dump stack to file
Vincent Demeester 8 年之前
父节点
当前提交
19b5b4aada
共有 3 个文件被更改,包括 33 次插入33 次删除
  1. 10 3
      daemon/debugtrap_unix.go
  2. 6 1
      daemon/debugtrap_windows.go
  3. 17 29
      pkg/signal/trap.go

+ 10 - 3
daemon/debugtrap_unix.go

@@ -7,15 +7,22 @@ import (
 	"os/signal"
 	"os/signal"
 	"syscall"
 	"syscall"
 
 
-	psignal "github.com/docker/docker/pkg/signal"
+	stackdump "github.com/docker/docker/pkg/signal"
+
+	"github.com/Sirupsen/logrus"
 )
 )
 
 
-func setupDumpStackTrap(_ string) {
+func setupDumpStackTrap(root string) {
 	c := make(chan os.Signal, 1)
 	c := make(chan os.Signal, 1)
 	signal.Notify(c, syscall.SIGUSR1)
 	signal.Notify(c, syscall.SIGUSR1)
 	go func() {
 	go func() {
 		for range c {
 		for range c {
-			psignal.DumpStacks("")
+			path, err := stackdump.DumpStacks(root)
+			if err != nil {
+				logrus.WithError(err).Error("failed to write goroutines dump")
+				continue
+			}
+			logrus.Infof("goroutine stacks written to %s", path)
 		}
 		}
 	}()
 	}()
 }
 }

+ 6 - 1
daemon/debugtrap_windows.go

@@ -35,7 +35,12 @@ func setupDumpStackTrap(root string) {
 		logrus.Debugf("Stackdump - waiting signal at %s", ev)
 		logrus.Debugf("Stackdump - waiting signal at %s", ev)
 		for {
 		for {
 			syscall.WaitForSingleObject(h, syscall.INFINITE)
 			syscall.WaitForSingleObject(h, syscall.INFINITE)
-			signal.DumpStacks(root)
+			path, err := signal.DumpStacks(root)
+			if err != nil {
+				logrus.WithError(err).Error("failed to write goroutines dump")
+				continue
+			}
+			logrus.Infof("goroutine stacks written to %s", path)
 		}
 		}
 	}()
 	}()
 }
 }

+ 17 - 29
pkg/signal/trap.go

@@ -1,6 +1,7 @@
 package signal
 package signal
 
 
 import (
 import (
+	"fmt"
 	"os"
 	"os"
 	gosignal "os/signal"
 	gosignal "os/signal"
 	"path/filepath"
 	"path/filepath"
@@ -10,6 +11,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	"github.com/pkg/errors"
 )
 )
 
 
 // Trap sets up a simplified signal "trap", appropriate for common
 // Trap sets up a simplified signal "trap", appropriate for common
@@ -64,8 +66,11 @@ func Trap(cleanup func()) {
 	}()
 	}()
 }
 }
 
 
-// DumpStacks dumps the runtime stack.
-func DumpStacks(root string) {
+const stacksLogNameTemplate = "goroutine-stacks-%s.log"
+
+// DumpStacks appends the runtime stack into file in dir and returns full path
+// to that file.
+func DumpStacks(dir string) (string, error) {
 	var (
 	var (
 		buf       []byte
 		buf       []byte
 		stackSize int
 		stackSize int
@@ -77,32 +82,15 @@ func DumpStacks(root string) {
 		bufferLen *= 2
 		bufferLen *= 2
 	}
 	}
 	buf = buf[:stackSize]
 	buf = buf[:stackSize]
-	// Note that if the daemon is started with a less-verbose log-level than "info" (the default), the goroutine
-	// traces won't show up in the log.
-	if root == "" {
-		logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
-	} else {
-		// Dumps the stacks to a file in the root directory of the daemon
-		// On Windows, this overcomes two issues - one being that if the stack is too big, it doesn't
-		// get written to the event log when the Windows daemon is running as a service.
-		// Second, using logrus, the tabs and new-lines end up getting written as literal
-		// \t and \n's, meaning you need to use something like notepad++ to convert the
-		// output into something readable using 'type' from a command line or notepad/notepad++ etc.
-		path := filepath.Join(root, "goroutine-stacks.log")
-		f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
-		if err != nil {
-			logrus.Warnf("Could not open %s to write the goroutine stacks: %v", path, err)
-			return
-		}
-		defer f.Close()
-		f.WriteString("=== BEGIN goroutine stack dump ===\n")
-		f.WriteString(time.Now().String() + "\n")
-		if _, err := f.Write(buf); err != nil {
-			logrus.Warnf("Could not write goroutine stacks to %s: %v", path, err)
-			return
-		}
-		f.WriteString("=== END goroutine stack dump ===\n")
-		f.Sync()
-		logrus.Infof("goroutine stacks written to %s", path)
+	path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, time.Now().Format(time.RFC3339)))
+	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()
+	if _, err := f.Write(buf); err != nil {
+		return "", errors.Wrap(err, "failed to write goroutine stacks")
 	}
 	}
+	f.Sync()
+	return path, nil
 }
 }