使用github.com/pkg/errors包快速定位错误

package main

import (
    "bufio"
    "fmt"
    "os"
    "path/filepath"
    "time"

    "github.com/pkg/errors"
)

func func1(num int64) (result int64, err error) {
    defer func() {
       rec := recover()
       if rec != nil {
          err, _ = rec.(error)
          err = errors.WithStack(err) // 附加调用堆栈信息
       }
    }()

    // num的值为0时会报panic,然后被defer-recover捕获错误
    result = 1024 / num

    return
}

func func2(num int64) (result int64, err error) {
    result, err = func1(num)

    // 由于发生了错误,附加调用堆栈信息然后返回即可
    if err != nil {
       err = errors.WithStack(err) // 附加调用堆栈信息
       return
    }

    return
}

func WriteErrorLog(err error) {
    curPath, _ := filepath.Abs(".")   // 当前目录硬盘路径,结尾不带“/”
    logPath := curPath + "/log"       // 错误日志文件保存目录
    logFile := logPath + "/error.log" // 错误日志文件硬盘路径

    // 创建日志文件保存目录(若目录存在则忽略)
    _ = os.MkdirAll(logPath, 0755)

    // 打开日志文件(不存在则创建|只写模式|尾部追加)
    file, _ := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

    // 关闭日志文件
    defer func(file *os.File) {
       _ = file.Close()
    }(file)

    // 获取当前时间
    location, _ := time.LoadLocation("Asia/Shanghai")
    now := time.Now().In(location).Format("2006/01/02 15:04:05.999999")

    // 写入文件
    writer := bufio.NewWriter(file)
    _, _ = writer.WriteString(fmt.Sprintf("[error] %+v %+v\n\n", now, err))
    _ = writer.Flush()
}

func main() {
    result, err := func2(0)
    if err != nil {
       // 这里会打印一大段调用堆栈信息(具体可看最后)
       info := fmt.Sprintf("%+v", err)
       fmt.Println(info)

       // 将错误信息写入日志文件(也可以写入数据库)
       WriteErrorLog(err)
    } else {
       fmt.Printf("result = %+v \n", result)
    }
}

// ========== 调用堆栈信息·开始 ========== //

// runtime error: integer divide by zero
// main.func1.func1
//        D:/go/demo/cmd/main.go:17
// runtime.gopanic
//        C:/Program Files (x86)/go/src/runtime/panic.go:890
// runtime.panicdivide
//        C:/Program Files (x86)/go/src/runtime/panic.go:239
// main.func1
//        D:/go/demo/cmd/main.go:22
// main.func2
//        D:/go/demo/cmd/main.go:28
// main.main
//        D:/go/demo/cmd/main.go:66
// runtime.main
//        C:/Program Files (x86)/go/src/runtime/proc.go:250
// runtime.goexit
//        C:/Program Files (x86)/go/src/runtime/asm_amd64.s:1598
// main.func2
//        D:/go/demo/cmd/main.go:32
// main.main
//        D:/go/demo/cmd/main.go:66
// runtime.main
//        C:/Program Files (x86)/go/src/runtime/proc.go:250
// runtime.goexit
//        C:/Program Files (x86)/go/src/runtime/asm_amd64.s:1598

// ========== 调用堆栈信息·结束 ========== //

// ========== 总结 ========== //
// 1、使用github.com/pkg/errors包可以获取错误的调用堆栈信息,利用这些信息可以很快定位错误方便debug// 2、只需在最底层(即错误最初产生的地方)使用errors.WithStack(err)加入堆栈信息即可,不需要每一层都使用errors.WithStack(err)//    如果有需要可以在中间层使用errors.WithMessage()来添加有意义的上下文信息,但不需要每次都添加堆栈信息,否则会造成堆栈信息冗余。

Copyright © 2025 码农人生. All Rights Reserved