go使用errors.Wrapf()代替log.Error()方法示例

 更新时间:2023年08月31日 11:02:46   作者:好文收藏  
这篇文章主要为大家介绍了go使用errors.Wrapf()代替log.Error()的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

介绍不同语言的错误处理机制:

Error handling patterns

Musings about error handling mechanisms in programming languages

项目中 main调func1,func1调取func2...

这样就会出现很多的 if err != nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要逐级定位, 确定错误抛出的点

希望只有一条, 能清晰看到整个堆栈调用信息

使用log.xxxx方法

package main
import (
    "fmt"
    "log"
    "strconv"
    "time"
)
func init() {
    log.SetFlags(log.Lshortfile | log.LstdFlags)
}
func main() {
    str := "123a"
    rs, err := func1(str)
    if err != nil {
        log.Printf("err is (%+v)\n", err)
        return
    }
    fmt.Println("最终结果为:", rs)
}
func func1(str string) (int, error) {
    b, err := func2()
    if err != nil {
        log.Printf("There is func11111,  func2 err(%+v)\n", err)
    }
    if b == false {
        strInt, err := strconv.Atoi(str)
        if err != nil {
            log.Printf("There is func11111, err(%+v)\n", err)
        }
        return strInt, err
    }
    return 0, nil
}
func func2() (bool, error) {
    now := time.Now().Unix()
    endTimeStr := "2021-08-06 20:00:0000"
    endtime, err := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
    if err != nil {
        log.Printf("There is func22222, err(%+v)\n", err)
        return false, err
    }
    if endtime.Unix() > now {
        return true, nil
    }
    return false, nil
}

执行结果:

2021/06/07 21:52:56 vs.go:56: There is func22222, err(parsing time "2021-08-06 20:00:0000": extra text: "00")
2021/06/07 21:52:56 vs.go:33: There is func11111,  func2 err(parsing time "2021-08-06 20:00:0000": extra text: "00")
2021/06/07 21:52:56 vs.go:40: There is func11111, err(strconv.Atoi: parsing "123a": invalid syntax)
2021/06/07 21:52:56 vs.go:20: err is (strconv.Atoi: parsing "123a": invalid syntax)

使用errors.Wrapf方法

package main
import (
    "fmt"
    "github.com/pkg/errors"
    "strconv"
    "time"
)
func main() {
    str := "123a"
    rs, err := func1(str)
    if err != nil {
        fmt.Printf("err: %+v\n", err)
        //fmt.Println("err:", lastErr) //必须%+v才会打印完整堆栈信息,否则只打印错误信息
        return
    }
    fmt.Println("最终结果为:", rs)
}
func func1(str string) (int, error) {
    b, err := func2()
    if err != nil {
        err = errors.Wrapf(err, "There is func11111, func2 err, b is(%b) \n", b)
    }
    if b == false {
        var strInt int
        strInt, err = strconv.Atoi(str)
        if err != nil {
            err = errors.Wrapf(err, "There is func11111,str is(%s)\n", str)
        }
        return strInt, err
    }
    return 0, nil
}
func func2() (bool, error) {
    now := time.Now().Unix()
    endTimeStr := "2021-08-06 20:00:0000"
    endtime, err := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
    if err != nil {
        err = errors.Wrapf(err, "There is func22222,endTimeStr is(%s)\n", endTimeStr)
        return false, err
    }
    if endtime.Unix() > now {
        return true, nil
    }
    return false, nil
}

执行:

err: strconv.Atoi: parsing "123a": invalid syntax
There is func11111,str is(123a)
main.func1
        /Users/fliter/go/src/shuang/llog/1.go:39
main.main
        /Users/fliter/go/src/shuang/llog/1.go:13
runtime.main
        /usr/local/Cellar/go/1.16.3/libexec/src/runtime/proc.go:225
runtime.goexit
        /usr/local/Cellar/go/1.16.3/libexec/src/runtime/asm_amd64.s:1371

注意赋值这步, 必不可少!

有一个问题, 即对于f1调f2,f2调f3这种, 如果f3发生error, 可以逐级将error抛出.
但如果一个方法里有两个error, 则第二条会覆盖掉第一条,如上 err = errors.Wrapf(err, "There is func11111, func2 err, b is(%b) \n", b)这一条就被覆盖了

// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
    if err == nil {
        return nil
    }
    err = &withMessage{
        cause: err,
        msg:   fmt.Sprintf(format, args...),
    }
    return &withStack{
        err,
        callers(),
    }
}
func callers() *stack {
    const depth = 32
    var pcs [depth]uintptr
    n := runtime.Callers(3, pcs[:])
    var st stack = pcs[0:n]
    return &st
}
// Callers fills the slice pc with the return program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
//
// To translate these PCs into symbolic information such as function
// names and line numbers, use CallersFrames. CallersFrames accounts
// for inlined functions and adjusts the return program counters into
// call program counters. Iterating over the returned slice of PCs
// directly is discouraged, as is using FuncForPC on any of the
// returned PCs, since these cannot account for inlining or return
// program counter adjustment.
func Callers(skip int, pc []uintptr) int {
    // runtime.callers uses pc.array==nil as a signal
    // to print a stack trace. Pick off 0-length pc here
    // so that we don't let a nil pc slice get to it.
    if len(pc) == 0 {
        return 0
    }
    return callers(skip, pc)
}
func callers(skip int, pcbuf []uintptr) int {
    sp := getcallersp()
    pc := getcallerpc()
    gp := getg()
    var n int
    systemstack(func() {
        n = gentraceback(pc, sp, 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
    })
    return n
}

参考:

golang 打印error的堆栈信息

Go错误处理最佳实践

以上就是go使用errors.Wrapf()代替log.Error()方法示例的详细内容,更多关于go errors.Wrapf log.Error的资料请关注脚本之家其它相关文章!

相关文章

  • 使用Go语言编写一个NTP服务器的流程步骤

    使用Go语言编写一个NTP服务器的流程步骤

    NTP服务器【Network Time Protocol(NTP)】是用来使计算机时间同步化的一种协议,为了确保封闭局域网内多个服务器的时间同步,我们计划部署一个网络时间同步服务器(NTP服务器),本文给大家介绍了使用Go语言编写一个NTP服务器的流程步骤,需要的朋友可以参考下
    2024-11-11
  • golang 设置web请求状态码操作

    golang 设置web请求状态码操作

    这篇文章主要介绍了golang 设置web请求状态码操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang sync.Cond同步机制运用及实现

    golang sync.Cond同步机制运用及实现

    在 Go 里有专门为同步通信而生的 channel,所以较少看到 sync.Cond 的使用,不过它也是并发控制手段里的一种,今天我们就来认识下它的相关实现,加深对同步机制的运用
    2023-09-09
  • golang中值类型/指针类型的变量区别总结

    golang中值类型/指针类型的变量区别总结

    golang的值类型和指针类型receiver一直是大家比较混淆的地方,下面这篇文章主要给大家总结介绍了关于golang中值类型/指针类型的变量区别的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
    2017-12-12
  • golang类型转换之interface转字符串string简单示例

    golang类型转换之interface转字符串string简单示例

    在我们使用Golang进行开发过程中,总是绕不开对字符或字符串的处理,这篇文章主要给大家介绍了关于golang类型转换之interface转字符串string的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Golang特殊init函数的实现实例

    Golang特殊init函数的实现实例

    本文介绍了Go语言中特殊函数init()的作用,如变量初始化、包初始化顺序以及与main函数的关系,具有一定的参考价值,感兴趣的可以了解一下
    2025-11-11
  • Go语言中Redis缓存与本地内存缓存实战

    Go语言中Redis缓存与本地内存缓存实战

    在现代高并发系统中,缓存技术是提升性能和降低数据库压力的关键手段,本文将为大家介绍一下Redis缓存与本地内存缓存的具体应用,需要的可以了解下
    2025-03-03
  • 深入解析Go语言中for循环的写法

    深入解析Go语言中for循环的写法

    这篇文章主要介绍了Go语言中for循环的写法,是Golang入门学习中的基础知识,需要的朋友可以参考下
    2015-10-10
  • 浅谈Go语言多态的实现与interface使用

    浅谈Go语言多态的实现与interface使用

    如果大家系统的学过C++、Java等语言以及面向对象的话,相信应该对多态不会陌生。多态是面向对象范畴当中经常使用并且非常好用的一个功能,它主要是用在强类型语言当中,像是Python这样的弱类型语言,变量的类型可以随意变化,也没有任何限制,其实区别不是很大
    2021-06-06
  • 十个Go map面试常考问题合集

    十个Go map面试常考问题合集

    go面试中,map相关知识点问的比较多,这篇文章主要为大家整理归纳了10个常考的问题,文中的示例代码讲解详细,希望对大家有一定的帮助
    2023-07-07

最新评论