-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*unix: kill -USR1 <gocq_pid> windows: echo dumpstack >\\.\pipe\go-cqhttp-<pid> stackdump将直接以<exec_name>.<pid>.stacks.<timestamp>.log 的文件名保存在当前工作目录下
- Loading branch information
Showing
6 changed files
with
181 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package global | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"sync" | ||
"time" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
var ( | ||
mainStopCh chan struct{} | ||
mainOnce sync.Once | ||
|
||
dumpMutex sync.Mutex | ||
) | ||
|
||
func dumpStack() { | ||
dumpMutex.Lock() | ||
defer dumpMutex.Unlock() | ||
|
||
log.Info("开始 dump 当前 goroutine stack 信息") | ||
|
||
buf := make([]byte, 1024) | ||
for { | ||
n := runtime.Stack(buf, true) | ||
if n < len(buf) { | ||
buf = buf[:n] | ||
break | ||
} | ||
buf = make([]byte, 2*len(buf)) | ||
} | ||
|
||
fileName := fmt.Sprintf("%s.%d.stacks.%d.log", filepath.Base(os.Args[0]), os.Getpid(), time.Now().Unix()) | ||
fd, err := os.Create(fileName) | ||
if err != nil { | ||
log.Errorf("保存 stackdump 到文件时出现错误: %v", err) | ||
log.Warnf("无法保存 stackdump. 将直接打印\n %s", buf) | ||
return | ||
} | ||
defer fd.Close() | ||
_, err = fd.Write(buf) | ||
if err != nil { | ||
log.Errorf("写入 stackdump 失败: %v", err) | ||
log.Warnf("无法保存 stackdump. 将直接打印\n %s", buf) | ||
return | ||
} | ||
log.Infof("stackdump 已保存至 %s", fileName) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
//+build !windows | ||
|
||
package global | ||
|
||
import ( | ||
"os" | ||
"os/signal" | ||
"sync" | ||
"syscall" | ||
) | ||
|
||
func SetupMainSignalHandler() <-chan struct{} { | ||
mainOnce.Do(func() { | ||
mc := make(chan os.Signal, 2) | ||
closeOnce := sync.Once{} | ||
signal.Notify(mc, os.Interrupt, syscall.SIGTERM, syscall.SIGUSR1) | ||
go func() { | ||
for { | ||
s := <-mc | ||
switch s { | ||
case os.Interrupt, syscall.SIGTERM: | ||
closeOnce.Do(func() { | ||
close(mc) | ||
}) | ||
case syscall.SIGUSR1: | ||
dumpStack() | ||
} | ||
} | ||
}() | ||
|
||
mainStopCh = make(chan struct{}) | ||
}) | ||
return mainStopCh | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//+build windows | ||
|
||
package global | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/signal" | ||
"sync" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/Microsoft/go-winio" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
var ( | ||
validTasks = []string{ | ||
"dumpstack", | ||
} | ||
) | ||
|
||
func SetupMainSignalHandler() <-chan struct{} { | ||
mainOnce.Do(func() { | ||
// for stack trace collecting on windows | ||
pipeName := fmt.Sprintf(`\\.\pipe\go-cqhttp-%d`, os.Getpid()) | ||
pipe, err := winio.ListenPipe(pipeName, &winio.PipeConfig{}) | ||
if err != nil { | ||
log.Error("创建 named pipe 失败. 将无法使用 dumpstack 功能") | ||
} else { | ||
maxTaskLen := 0 | ||
for i := range validTasks { | ||
if l := len(validTasks[i]); l > maxTaskLen { | ||
maxTaskLen = l | ||
} | ||
} | ||
go func() { | ||
for { | ||
c, err := pipe.Accept() | ||
if err != nil { | ||
log.Errorf("accept named pipe 失败: %v", err) | ||
continue | ||
} | ||
go func() { | ||
defer c.Close() | ||
_ = c.SetReadDeadline(time.Now().Add(5 * time.Second)) | ||
buf := make([]byte, maxTaskLen) | ||
n, err := c.Read(buf) | ||
if err != nil { | ||
log.Errorf("读取 named pipe 失败: %v", err) | ||
return | ||
} | ||
cmd := string(buf[:n]) | ||
switch cmd { | ||
case "dumpstack": | ||
dumpStack() | ||
default: | ||
log.Warnf("named pipe 读取到未知指令: %q", cmd) | ||
} | ||
}() | ||
} | ||
}() | ||
} | ||
|
||
mc := make(chan os.Signal, 2) | ||
closeOnce := sync.Once{} | ||
signal.Notify(mc, os.Interrupt, syscall.SIGTERM) | ||
go func() { | ||
for { | ||
s := <-mc | ||
switch s { | ||
case os.Interrupt, syscall.SIGTERM: | ||
closeOnce.Do(func() { | ||
close(mc) | ||
if pipe != nil { | ||
_ = pipe.Close() | ||
} | ||
}) | ||
} | ||
} | ||
}() | ||
|
||
mainStopCh = make(chan struct{}) | ||
}) | ||
return mainStopCh | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters