errors包常用方法

func Unwrap(err error) error                 // 获得err包含下一层错误
func Is(err, target error) bool // 判断err是否包含target
func As(err error, target interface{}) bool // 判断err是否为target类型

自定义错误信息

errors.New("这是自定义错误")

# 使用fmt进行错误包装
fmt.Errorf("error: %w", err)

errors.Is()

作用:判断被包装过的error是否包含指定错误

var BaseErr = errors.New("base error")

func main() {
err1 := fmt.Errorf("wrap base: %w", BaseErr)
err2 := fmt.Errorf("wrap err1: %w", err1)
println(err2 == BaseErr) if !errors.Is(err2, BaseErr) { // err2错误 是否在BaseErr错误树中
panic("err2 is not BaseErr")
}
println("err2 is BaseErr")
} //输出:
//false
//err2 is BaseErr

errors.As()

作用:判断被包装过的error是否为指定类型

具体说明:提取指定类型的错误,判断包装的 error 链中,某一个 error 的类型是否与 target 相同,并提取第一个符合目标类型的错误的值,将其赋值给 target

type TypicalErr struct {
e string
} func (t TypicalErr) Error() string {
return t.e
} func main() {
err := TypicalErr{"typical error"}
err1 := fmt.Errorf("wrap err: %w", err)
err2 := fmt.Errorf("wrap err1: %w", err1)
var e TypicalErr
if !errors.As(err2, &e) {
panic("TypicalErr is not on the chain of err2")
}
println("TypicalErr is on the chain of err2")
println(err == e)
}
//输出:
//TypicalErr is on the chain of err2
//true

errors的最佳实践:

遵循以下建议,我们可以更好地处理 error :

  • 1、一个 error,应该只被处理一次
  • 2、让 error 包含更多的信息
  • 3、原始 error,应保证完整性,不被破坏
  • 4、error 需要被日志记录

为了确保 error 处理的有效性,对于某一层来说,应该保证每个错误只被处理一次,要么打印 error 信息,要么将其传递给上一层,而不是每一层都独立打印 error 信息。

同时,在传递错误给上一层时,应该附带有用的额外信息,并确保不破坏原始错误的完整性,以保证错误的可追溯性。最后,通过记录错误日志可以帮助我们进行问题排查。

我们可以借助第三方库 github.com/pkg/errors 来完成我们的需求。

github.com/pkg/errors 提供了很多实用的函数,例如:

  • Wrap(err error, message string) error:该函数基于原始错误 err,返回一个带有堆栈跟踪信息和附加信息 message 的新 error
  • Wrapf(err error, format string, args ...interface{}) error: 和上面的函数功能是一样的,只不过可以对附加信息进行格式化封装
  • WithMessage(err error, message string) error:该函数基于原始错误 err,返回一个附加信息 message 的新 error
  • WithMessagef(err error, format string, args ...interface{}) error: 和上面的函数功能是一样的,只不过可以对附加信息进行格式化封装
  • Cause(err error) error:该函数用于提取 err 中的原始 error,它会递归地检查 error,直到找到最底层的原始 error,如果存在的话
// controller / middleware
res, err := service.GetById(ctx, id)
if err != nil {
log.Errorf(ctx, "service.GetById failed, original error: %T %v", errors.Cause(err), errors.Cause(err))
log.Errorf(ctx, "stack trace: \n%+v\n", err)
······
}
······ // service
article, err := dao.GetById(ctx, id)
if err != nil {
return errors.WithMessage(err, "dao.GetById failed")
}
······ // dao
······
if err != nil {
return errors.Wrapf(err, "GetById failed, id=%s, error=%v", id, err)
}
······

当在 Dao 层遇到原始错误 Original Error 后,使用 errors.Wrap() 对错误进行封装。这个封装操作可以在保留根因(Origin error)的同时,提供堆栈信息,并添加额外的上下文信息,然后将封装后的错误传递给上一层处理。

service 层接收到 error 之后,使用 errors.WithMessage() 函数,将额外的信息附加到错误上,并继续将错误向上层传递,直至到达 controller 层。在 controller 层,我们可以打印出根因的类型、信息以及堆栈信息,以便更好地进行问题排查。

 
 

golang之errors包的更多相关文章

  1. Golang学习 - errors 包

    ------------------------------------------------------------ Go 语言使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 e ...

  2. 关于golang的time包总结

    目录 前言 time包详解 总结 前言 各种编程语言都少不了与时间有关的操作,因为很多判断都是基于时间,因此正确和方便的使用时间库就很重要额. golang提供了import "time&q ...

  3. Golang爬虫示例包系列教程(一):pedaily.com投资界爬虫

    Golang爬虫示例包 文件结构 自己用Golang原生包封装了一个爬虫库,源码见go get -u -v github.com/hunterhug/go_tool/spider ---- data ...

  4. 一键解决 go get golang.org/x 包失败

    问题描述 当我们使用 go get.go install.go mod 等命令时,会自动下载相应的包或依赖包.但由于众所周知的原因,类似于 golang.org/x/... 的包会出现下载失败的情况. ...

  5. 19-03【golang】strings包

    golang的strings包提供了字符串操作的一系列函数.下面做个简单介绍 函数 用法 备注 Compare(a,b sring) 比较两个字符串   Contains(s, substr stri ...

  6. 关于golang.org/x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...

  7. Golang Gin 项目包依赖管理 godep 使用

    Golang Gin 项目包依赖管理 godep 使用 标签(空格分隔): Go 在按照github.com/tools/godep文档go get完包以后,调整项目结构为$GOPATH/src/$P ...

  8. golang 关于golang.org/x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...

  9. Golang的json包

    encoding/json encoding/json是官方提供的标准json, 实现RFC 7159中定义的JSON编码和解码.使用的时候需要预定义struct,原理是通过reflection和in ...

  10. Golang官方log包详解

    Golang官方log包详解 以下全是代码, 详解在注释中, 请从头到尾看 // Copyright 2009 The Go Authors. All rights reserved. // Use ...

随机推荐

  1. 【VMware VCF】VCF 5.2:配置管理域 vSAN 延伸集群。

    VMware vSAN 解决方案中,根据集群的配置类型分为 vSAN 标准集群.vSAN 延伸集群以及双主机集群(延伸集群特例).我们最常见的使用方式应该是 vSAN 标准集群,也就是 vSAN HC ...

  2. 知识点考古:php5的面向对象学习笔记

    闲来无事翻看以前收藏的资料,考古到保存的这篇文章对php的OOP的整理还很系统.原链接已经打不开(http://www.cublog.cn/u/17686/showart.php?id=146562) ...

  3. Identity – Custom Entity

    扩展属性 Custom Entity 指的是我们想对 Identity 的几个 Entity 做修改. 比如 User 要多一些 property, 或者 Id 用 int 而不是默认的 GUID. ...

  4. 构建数据大屏,塑造IT运维可视化核心竞争力

    随着大数据.云计算等新兴技术的发展与运用,在金融.交通.教育.政府等行业的信息化在飞速发展.与此同时,各行业的IT建设与维护管理成本也在与日俱增,大量的运维工作下产生庞大的运维数据,如何进行运维数据可 ...

  5. SpringBoot 实现文件上传

    参考:Java springboot进阶教程 文件上传功能实现 后端代码编写 常见错误分析与解决 在 Service 业务层接口中增加一个上传文件的方法 因为文件并不是上传至数据库中,所以不需要编写 ...

  6. Nuxt.js 应用中的 app:suspense:resolve 钩子详解

    title: Nuxt.js 应用中的 app:suspense:resolve 钩子详解 date: 2024/10/6 updated: 2024/10/6 author: cmdragon ex ...

  7. string的find()与npos

    在 C++ 中,std::string::find() 是一个用于在字符串中查找子字符串或字符的成员函数.查找成功时返回匹配的索引位置,查找失败时返回 std::string::npos,表示未找到. ...

  8. Android 12 关机重启流程

    1. 关机流程 Android上层触发关机的入口很多,但最终几乎都是调用ShutdownThread.shutdown来实现.如下是一些常见的调用关机的点: StatusBarManagerServi ...

  9. 在实例化对象的时候new关键字具体做了哪些操作?

    a 创建了一个空对象 {}b 通过原型链把空对象和构造函数连接起来__proto__ = prototype c 构造函数的this指向新对象,并执行函数体 d 判断构造函数的返回值,返回对象就使用该 ...

  10. 理解 keep-alive

    keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 : 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 act ...