Files
ngzz-mc/internal/crash/crash.go

51 lines
1.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package crash 崩溃兜底:panic 时把堆栈写入崩溃日志(闪退可诊断)。
package crash
import (
"fmt"
"os"
"path/filepath"
"runtime/debug"
"sync"
"time"
)
var (
logMu sync.Mutex
logPath string
)
// SetLogPath 设置崩溃日志路径(main 启动时调用一次)。
func SetLogPath(p string) { logPath = p }
func writeLog(msg string) {
logMu.Lock()
defer logMu.Unlock()
msg = fmt.Sprintf("[%s] %s\n", time.Now().Format("2006-01-02 15:04:05"), msg)
if logPath != "" {
_ = os.MkdirAll(filepath.Dir(logPath), 0o755)
if f, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644); err == nil {
_, _ = f.WriteString(msg)
_ = f.Close()
}
}
_, _ = fmt.Fprint(os.Stderr, msg)
}
// Guard 在 main 顶部 defer Guard();panic 时写崩溃日志后重抛(保留退出行为)。
func Guard(logPath string) {
if r := recover(); r != nil {
writeLog(fmt.Sprintf("崩溃(主线程): %v\n%s", r, debug.Stack()))
panic(r) // 保留原始 panic 行为(退出码非 0)
}
}
// RecoverGo 非主 goroutine 的兜底:panic 写日志后终止进程
// (Go 中任何 goroutine 未恢复的 panic 都会导致整个进程静默退出)。
func RecoverGo(name string) {
if r := recover(); r != nil {
writeLog(fmt.Sprintf("崩溃(goroutine %s): %v\n%s", name, r, debug.Stack()))
os.Exit(2)
}
}