package main
import (
"fmt"
"runtime"
"sync"
)
// 定义一个结构体来记录panic的详细信息
type PanicInfo struct {
FuncName string
Args []interface{}
Stack string
}
// 用于记录panic信息的全局变量
var panicInfos []PanicInfo
var mu sync.Mutex
// 捕获panic并记录信息的函数
func recoverAndLog() {
if r := recover(); r != nil {
var buf [4096]byte
n := runtime.Stack(buf[:], false)
stack := string(buf[:n])
// 这里假设能获取到函数名和参数,实际情况可能需要更复杂逻辑
funcName := "unknown"
args := []interface{}{}
panicInfo := PanicInfo{
FuncName: funcName,
Args: args,
Stack: stack,
}
mu.Lock()
panicInfos = append(panicInfos, panicInfo)
mu.Unlock()
}
}
// 模拟可能发生panic的goroutine
func worker(id int, wg *sync.WaitGroup) {
defer func() {
recoverAndLog()
wg.Done()
}()
if id == 3 { // 假设id为3时发生panic
panic("模拟panic")
}
fmt.Printf("Goroutine %d is running\n", id)
}
func main() {
var wg sync.WaitGroup
numGoroutines := 5
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
// 打印记录的panic信息
mu.Lock()
for _, info := range panicInfos {
fmt.Printf("Function: %s\n", info.FuncName)
fmt.Printf("Args: %v\n", info.Args)
fmt.Printf("Stack: %s\n", info.Stack)
}
mu.Unlock()
}
关键部分注释
- PanicInfo结构体:用于存储发生panic的goroutine的函数名、传入参数和函数调用栈信息。
- recoverAndLog函数:使用
recover
捕获panic,获取调用栈信息,并将相关信息记录到panicInfos
中。
- worker函数:模拟可能发生panic的goroutine,使用
defer
调用recoverAndLog
来捕获panic,确保即使发生panic也能正确结束该goroutine,不影响其他goroutine。
- main函数:启动多个goroutine,并等待它们完成。最后打印记录的panic信息。
sync.Mutex
用于保证对panicInfos
的并发安全访问。