golang捕获panic

golang当中panic的时候如果启动的goroutine比较多,刷的信息满屏都是,在终端工具上因为刷的信息太多,找不到前边的信息,因此很有必要程序自己捕获panic,并且将错误信息输出到文件当中,以便定位排查问题。

以下是一段捕获panic的代码

package main

import (
    "fmt"
    "os"
    "runtime/debug"
    "time"
)

func PanicHandler() {
    exeName := os.Args[0] //获取程序名称

    now := time.Now()  //获取当前时间
    pid := os.Getpid() //获取进程ID

    time_str := now.Format("20060102150405")                          //设定时间格式
    fname := fmt.Sprintf("%s-%d-%s-dump.log", exeName, pid, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
    fmt.Println("dump to file ", fname)

    f, err := os.Create(fname)
    if err != nil {
        return
    }
    defer f.Close()

    if err := recover(); err != nil {
        f.WriteString(fmt.Sprintf("%v\r\n", err)) //输出panic信息
        f.WriteString("========\r\n")
    }

    f.WriteString(string(debug.Stack())) //输出堆栈信息
}

以下是测试程序,这里我们测试除数为0的异常

package main

import (
    "fmt"
    //"sync"
)

func test_panic() {
    n := 0
    i := 5 / n
    fmt.Println(i)
}

func main() {
    defer PanicHandler()
    test_panic()

    /*
        var wg sync.WaitGroup

        wg.Add(1)
        go func() {
            defer PanicHandler()
            test_panic()
            wg.Done()
        }()

        wg.Wait()
    */
}

捕获的错误信息如下:

runtime error: integer divide by zero
========
F:/MyProject/Go/src/panictest/panicHandler.go:31 (0x4017c2)
    PanicHandler: f.WriteString(string(debug.Stack())) //输出堆栈信息
c:/go/src/runtime/asm_amd64.s:437 (0x4543e5)
    call32: CALLFN(·call32, 32)
c:/go/src/runtime/panic.go:423 (0x4291f7)
    gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
c:/go/src/runtime/panic.go:24 (0x427740)
    panicdivide: panic(divideError)
c:/go/src/runtime/signal_windows.go:166 (0x43a31f)
    sigpanic: panicdivide()
F:/MyProject/Go/src/panictest/main.go:10 (0x401073)
    test_panic: i := 5 / n
F:/MyProject/Go/src/panictest/main.go:16 (0x40119c)
    main: test_panic()
c:/go/src/runtime/proc.go:111 (0x42b78e)
    main: main_main()
c:/go/src/runtime/asm_amd64.s:1721 (0x456821)
    goexit: BYTE    $0x90  // NOP

至此获取错误并且存储的功能已经实现。

最后注意,如果是启动的多goroutine,需要在每个goroutine执行函数的时候,写上defer PanicHandler() 否则的话是捕获不到其他goroutine当中的painc信息的。

你可能感兴趣的:(golang)