我们有一个大型golang应用程序,它使用记录器(实际上是一个自定义记录器)将输出写入定期轮换的日志文件.
但是,当应用程序崩溃或panic()时,这些消息会转到标准错误.
有没有办法覆盖恐慌功能来使用我们的记录器?
Nic*_*ood 12
据我所知,您不能将输出从恐慌中重新定向到标准错误或记录器.您可以做的最好的事情是将标准错误重定向到您可以在外部或程序内部执行的文件.
对于我的rclone程序,我重定向标准错误以将所有内容捕获到选项上的文件,遗憾的是,这种方式在跨平台方式下并不是特别容易.我是这样做的(参见重定向*.go文件)
对于linux/unix
// Log the panic under unix to the log file
//+build unix
package main
import (
"log"
"os"
"syscall"
)
// redirectStderr to the file passed in
func 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)
}
}
Run Code Online (Sandbox Code Playgroud)
和窗户
// Log the panic under windows to the log file
//
// Code from minix, via
//
// http://play.golang.org/p/kLtct7lSUg
//+build windows
package main
import (
"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 in
func 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
}
Run Code Online (Sandbox Code Playgroud)
您可以使用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");
Run Code Online (Sandbox Code Playgroud)
但请注意,您无法从在不同goroutine中触发的恐慌中恢复(感谢JimB提示).使用单个recover()从任何goroutine中恢复恐慌是不可能的.