Capturing panic() in golang

后端 未结 3 567
别跟我提以往
别跟我提以往 2020-12-08 11:04

We have a large-ish golang application that uses the logger (actually, a custom logger), to write output to a log file that is periodically rotated.

However, when an

3条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-08 11:24

    As far as I know, you can't redirect the output from panic away from standard error, or to your logger. The best thing you can do is redirect standard error to a file which you can do externally, or inside your program.

    For my rclone program I redirected standard error to capture everything to a file on an option which is unfortunately isn't particularly easy to do in a cross platform way. Here is how I did it (see the redirect*.go files)

    For 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)
        }
    }
    

    and for windows

    // 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
    }
    

提交回复
热议问题