-
冉冉说
据我所知,您无法将 panic 的输出重定向到远离标准错误或您的记录器。您能做的最好的事情是将标准错误重定向到您可以在外部或程序内部执行的文件。对于我的rclone程序,我重定向了标准错误以将所有内容捕获到一个选项的文件中,不幸的是,这在跨平台方式中并不是特别容易做到。这是我是如何做到的(请参阅 redirect*.go 文件)对于 linux/unix// Log the panic under unix to the log file//+build unixpackage mainimport ( "log" "os" "syscall")// redirectStderr to the file passed infunc redirectStderr(f *os.File) { err := syscall.Dup2(int(f.Fd()), int(os.Stderr.Fd())) if err != nil { log.Fatalf("Failed to redirect stderr to file: %v", err) }}和窗户// Log the panic under windows to the log file//// Code from minix, via//// http://play.golang.org/p/kLtct7lSUg//+build windowspackage mainimport ( "log" "os" "syscall")var ( kernel32 = syscall.MustLoadDLL("kernel32.dll") procSetStdHandle = kernel32.MustFindProc("SetStdHandle"))func setStdHandle(stdhandle int32, handle syscall.Handle) error { r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0) if r0 == 0 { if e1 != 0 { return error(e1) } return syscall.EINVAL } return nil}// redirectStderr to the file passed infunc redirectStderr(f *os.File) { err := setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(f.Fd())) if err != nil { log.Fatalf("Failed to redirect stderr to file: %v", err) } // SetStdHandle does not affect prior references to stderr os.Stderr = f}
-
慕码人2483693
您可以使用recover()从同一个 goroutine 中恢复恐慌。当调用recover()延迟方法时(请记住,延迟方法仍然会被调用,即使在panic()ing 时),它将返回panic()作为参数传递给最后一次调用的任何内容(或者nil当程序没有发生恐慌时)。defer func() { if x := recover(); x != nil { // recovering from a panic; x contains whatever was passed to panic() log.Printf("run time panic: %v", x) // if you just want to log the panic, panic again panic(x) }}()panic("foo");但是请注意,您无法从不同 goroutine 中触发的恐慌中恢复(感谢 JimB 的提示)。使用单个recover()从任何 goroutine 的恐慌中恢复是不可能的。
-
慕森卡
扩展@nick-craig-wood 的回答:如果您使用的是 Linux,您可以生成一个 logger(1) 实例并将 stderr 重定向到它。这样你就可以在系统日志中获得完整的回溯。这就是gocryptfs所做的:// redirectStdFds redirects stderr and stdout to syslog; stdin to /dev/nullfunc redirectStdFds() { // stderr and stdout pr, pw, err := os.Pipe() if err != nil { tlog.Warn.Printf("redirectStdFds: could not create pipe: %v\n", err) return } tag := fmt.Sprintf("gocryptfs-%d-logger", os.Getpid()) cmd := exec.Command("logger", "-t", tag) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = pr err = cmd.Start() if err != nil { tlog.Warn.Printf("redirectStdFds: could not start logger: %v\n", err) } pr.Close() err = syscall.Dup2(int(pw.Fd()), 1) if err != nil { tlog.Warn.Printf("redirectStdFds: stdout dup error: %v\n", err) } syscall.Dup2(int(pw.Fd()), 2) if err != nil { tlog.Warn.Printf("redirectStdFds: stderr dup error: %v\n", err) } pw.Close() // stdin nullFd, err := os.Open("/dev/null") if err != nil { tlog.Warn.Printf("redirectStdFds: could not open /dev/null: %v\n", err) return } err = syscall.Dup2(int(nullFd.Fd()), 0) if err != nil { tlog.Warn.Printf("redirectStdFds: stdin dup error: %v\n", err) } nullFd.Close()}