19 | 错误处理(下):如何设计错误包?
孔令飞
该思维导图由 AI 生成,仅供参考
你好,我是孔令飞。
在 Go 项目开发中,错误是我们必须要处理的一个事项。除了我们上一讲学习过的错误码,处理错误也离不开错误包。
业界有很多优秀的、开源的错误包可供选择,例如 Go 标准库自带的errors包、github.com/pkg/errors包。但是这些包目前还不支持业务错误码,很难满足生产级应用的需求。所以,在实际开发中,我们有必要开发出适合自己错误码设计的错误包。当然,我们也没必要自己从 0 开发,可以基于一些优秀的包来进行二次封装。
这一讲里,我们就来一起看看,如何设计一个错误包来适配上一讲我们设计的错误码,以及一个错误码的具体实现。
错误包需要具有哪些功能?
要想设计一个优秀的错误包,我们首先得知道一个优秀的错误包需要具备哪些功能。在我看来,至少需要有下面这六个功能:
执行上面的代码:
这时我们想定位问题,但不知道具体是哪行代码报的错误,只能靠猜,还不一定能猜到。为了解决这个问题,我们可以加一些 Debug 信息,来协助我们定位问题。这样做在测试环境是没问题的,但是在线上环境,一方面修改、发布都比较麻烦,另一方面问题可能比较难重现。这时候我们会想,要是能打印错误的堆栈就好了。例如:
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了在Go项目开发中错误处理的重要性以及错误包的设计原则和功能。作者首先介绍了优秀的错误包需要具备的功能,包括支持错误堆栈、不同的打印格式、Wrap/Unwrap功能、Is方法、As函数以及两种错误创建方式。强调了错误堆栈的重要性,并提到了一些优秀的错误包,如`github.com/pkg/errors`包,并基于该包进行了二次封装,以支持错误码。文章还介绍了`github.com/marmotedu/errors`包的功能和性能测试结果,以及如何在实际生产环境中使用JSON格式打印日志。此外,还详细介绍了一个错误码的具体实现,包括通用错误码的定义、Coder结构体的实现以及错误码的注册和文档生成。总的来说,本文内容丰富,涵盖了错误包的设计原则、功能实现和性能对比,对于Go语言开发者来说具有很高的参考价值。读者可以从中了解如何设计一个优秀的错误包,以及错误包需要具备的功能,对于Go项目开发中的错误处理具有一定的指导意义。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 语言项目开发实战》,新⼈⾸单¥68
《Go 语言项目开发实战》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(32)
- 最新
- 精选
- yandongxiao总结: 1. 为什么业务要开发自己的错误包?因为开源的error包中,没有业务错误码,不方便使用。 2. 如何区分内部错误和外部错误? 1. 将错误分为两部分,是一个非常好的设计,通过 error code 联系在一起 2. 将 error code, response code, external error message 注册到一张大表上 3. github.com/marmotedu/errors 包提供的 WitheCode 和 Wrap 方法,构建错误链(嵌套关系) 4. 通过 format 的各种形式,控制 error 的输出信息 3. 如何自动生成全局的错误码文档,方便排查问题和联调? 使用 codegen 工具。 4. 如何打印错误?只在错误最原始位置打印错误。
作者回复: 总结的很全,很到位!
2021-11-2710 - pedro以推荐老师的项目给组里其它小伙伴,一起学习沉淀打磨为自己的实用标准,多谢老师
作者回复: 感谢pedro支持
2021-07-088 - 漂泊的小飘感觉需要看着源码再学一遍。。。
作者回复: 老哥,加油!
2021-07-285 - 树建文中提到withCode实现了format方法,但是看了errors.go中只查看withMessage实现了format
作者回复: 就是 withMessage
2022-05-05归属地:广东33 - 吹口哨yuwithCode 没有实现 Format() 方法呀?
作者回复: withMessage,我改下文章
2022-07-13归属地:广东2 - .看完了git中withCode错误的实现逻辑对于 WitCode需要分开cause和err 两个errors,很是迷惑。起初看完代码在猜想cause这个应该是为了递归打印,实现上个章节的”科学设计错误包“内容“ 错误码100101, 10: 服务。01: 某个服务下的某个模块。01: 模块下的错误码序号,每个模块可以注册 100 个错误。” 的功能,但是看了函数IsCode的逻辑,彻底懵逼了,code只对比了第一层的code就return,显然不是为了实现上一章节的内容,所以多个cause errors感觉是一个特别累赘的设计。 另外WithCode和WithStack 的入参都是error 接口。 如果一个error起初是go原生库的error, 先withCode再WithMessgge, 在执行err. Error() 会丢失打印不出完整的错误栈。这块是原本iam的就是业务设计就是如此吗?WithMessgge会直接决定了err. Error() 值,不管前面被With了多少次?
作者回复: 是的
2022-06-11归属地:广东2 - 你赖东东不错嘛记录错误方式二:在err发生处打印了log,却依旧把err上抛,而最外层又对err进行了一次处理,这样可能导致日志里写了两份重复的err信息。望解惑!
作者回复: 这个地方可以根据需要选择是否在上层直接返回err,还是再添加一些信息。 一般情况下直接返回err即可。但可能也有些业务逻辑需要在上层追加一些额外的信息,来帮助排障。
2021-07-1632 - Geek_25f93f要写这么一个codegen工具应该要废很多时间
作者回复: 一劳永逸
2022-07-09归属地:广东1 - Geek_c2089dfunc New(message string) error { return &fundamental{ msg: message, stack: callers(), } } 老师,想问一下errors/code.go 的包里面的callers()函数,哪里来的
作者回复: 相同目录下,stack.go文件中
2022-04-191 - 莫林老师能介绍一下如何适配gprc 的 status 响应吗?
作者回复: 内容有点多,后面考虑出个加餐。
2021-12-071
收起评论