当前位置:网站首页>Why is the pkg/errors tripartite library more recommended for go language error handling?
Why is the pkg/errors tripartite library more recommended for go language error handling?
2022-07-01 16:21:00 【frank.】
Hello everyone , I am a frank.
01
Introduce
Go Language project development , We usually need to deal with errors in code logic ,Go Official standard library errors It provides us with some methods , such as New,Unwarp,Is and As.
among , What we use most is New, however , In our reality Go Project under development , Will use some layered design , such as MVC,Clean Architecture etc. .
In projects that use hierarchical design , If we use Go Standard library errors Wrong definition , You will encounter the problem of error coverage .
02
About the standard library errors Error coverage problem
Go Standard library errors Of New Method , Only a simple error message can be defined , In the project code of hierarchical design , You will encounter the problem of error coverage , For example, our sample project code , It uses Clean Architecture Layered design .
Project hierarchical directory :
.
├── app
│ └── main.go
├── domain
│ └── user.go
├── go.mod
├── go.sum
└── user
├── delivery
│ └── http
│ └── user.go
├── repository
│ └── mysql
│ └── user.go
└── usecase
└── user.go
In the example project , So let's use Go Standard library errors Of New Method definition error , The code snippet is as follows :
repository layer :
func (m *mysqlUserRepository) GetUserById(ctx context.Context, user *domain.User) (err error) {
_, err = m.DB.Get(user)
fmt.Printf("mysqlUserRepository || GetUserById() || uid=%v || err=%v\n", user.Id, err)
return
}
usecase layer :
func (u *userUsecase) GetUserById(ctx context.Context, user *domain.User) (err error) {
if user.Id == 0 {
err = errors.New("invalid request parameter")
}
err = u.userRepo.GetUserById(ctx, user)
fmt.Printf("userUsecase || GetUserById() || uid=%v || err=%v\n", user.Id, err)
return
}
delivery layer :
func (u *UserHandler) GetUserById(c echo.Context) error {
idP, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusNotFound, err)
}
id := int64(idP)
ctx := c.Request().Context()
user := &domain.User{
Id: id,
}
err = u.UserUsecase.GetUserById(ctx, user)
if err != nil {
err = errors.New("UserUsecase error")
fmt.Printf("UserHandler || GetUserById() || uid=%v || err=%+v\n", id, err)
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, user)
}
Read the above three pieces of code , We can find out , We have error handling code in each layer , We deliberately use the wrong request parameters , And write the password of the database connection incorrectly , The error that triggered the application .
Output results :
mysqlUserRepository || GetUserById() || uid=1 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=1 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=1 || err=UserUsecase error
Read the output , We can find out ,usecase Layer definition error , The called repository Layer returns error coverage ;delivery Layer definition errors will usecase Error coverage returned by layer .
Because we printed errors on each layer , Check carefully , You can still locate the error , But it's still complicated , Not only do printing errors at each level make the code less elegant , And it can't quickly locate the error .
How to solve this problem ? Use a tripartite Library github.com/pkg/errors Replace Go Standard library errors.
03
Three party Library pkg/errors
Use a tripartite Library pkg/errors It can solve the problem that the error information of call stack overlaps each other in the project of hierarchical design , It can output wrong stack information for us , New error messages can be added to the existing error messages , So as to solve the problem that the output error information lacks context .
So let's revise that Part 02 Example code for , take Go Standard library errors Replace with a third-party library pkg/errors, I believe careful readers have found , Because the names of these two bags are the same , And they all have New Method , So it's convenient to replace , Just replace the imported package .
Sample code :
import (
// "errors"
"fmt"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/weirubo/learn_go/lesson41/domain"
"net/http"
"strconv"
)
Output result after replacement :
mysqlUserRepository || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=0 || err=UserUsecase error
github.com/weirubo/learn_go/lesson41/user/delivery/http.(*UserHandler).GetUserById
/Users/frank/GolandProjects/learn_go/lesson41/user/delivery/http/user.go:36
github.com/labstack/echo/v4.(*Echo).add.func1
/Users/frank/go/pkg/mod/github.com/labstack/echo/[email protected]/echo.go:520
github.com/labstack/echo/v4.(*Echo).ServeHTTP
/Users/frank/go/pkg/mod/github.com/labstack/echo/[email protected]/echo.go:630
net/http.serverHandler.ServeHTTP
/usr/local/go/src/net/http/server.go:2916
net/http.(*conn).serve
/usr/local/go/src/net/http/server.go:1966
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1571
Read the output above , We can find that the error handling package consists of Go Standard library errors Replace with a third-party library pkg/errors after , The output results are not only Go Standard library errors Error messages for , Wrong stack information is also output .
So far, , We just switched the imported package , The error message contains the wrong stack information , however , Our error coverage problem has not been solved , We also need to use third-party libraries pkg/errors Of Wrap Method , Let's change the code again , take New Replace the method with Wrap Method .
delivery layer :
...
if err != nil {
// err = errors.New("UserUsecase error")
err = errors.Wrap(err, "UserUsecase error")
fmt.Printf("UserHandler || GetUserById() || uid=%v || err=%+v\n", id, err)
return c.JSON(http.StatusInternalServerError, err)
}
...
Read the code above , We modify delivery Layer error handling code , take New Replace the method with Wrap Method , It can be based on the existing error information , Attach new error information and wrong stack information .
Output results :
mysqlUserRepository || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserUsecase error
github.com/weirubo/learn_go/lesson41/user/delivery/http.(*UserHandler).GetUserById
/Users/frank/GolandProjects/learn_go/lesson41/user/delivery/http/user.go:37
github.com/labstack/echo/v4.(*Echo).add.func1
/Users/frank/go/pkg/mod/github.com/labstack/echo/[email protected]/echo.go:520
github.com/labstack/echo/v4.(*Echo).ServeHTTP
/Users/frank/go/pkg/mod/github.com/labstack/echo/[email protected]/echo.go:630
net/http.serverHandler.ServeHTTP
/usr/local/go/src/net/http/server.go:2916
net/http.(*conn).serve
/usr/local/go/src/net/http/server.go:1966
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1571
Read the above output , We can find it in delivery Error message defined by layer , No more override calls usecase The error message returned by the layer method , Both are output normally .
It should be noted that , Output error information and stack information at the same time , Placeholders need to use %+v, Don't output stack information at every layer , This will repeatedly print stack information , Usually, if the stack information is printed on the lower layer , Don't print stack information on the upper layer .
Besides , Three party Library pkg/errors The other two methods WithMessage and WithStack It's also more commonly used , They are based on the existing error messages , Attach new error information and wrong stack information , We are in the actual project development , You can choose to use the appropriate method as needed .
04
summary
In this article, we talked about using Go Standard library errors Limitations and deficiencies of error handling , In order to solve its shortcomings , We introduced the use of third-party libraries pkg/errors Replace Go Standard library errors, And third-party library pkg/errors How to use several common methods of .
About the third-party library pkg/errors More ways , Interested readers can read the document to learn how to use .
Reference material :
- https://pkg.go.dev/github.com/pkg/[email protected]
- https://pkg.go.dev/errors
- https://dave.cheney.net/2016/06/12/stack-traces-and-the-errors-package
- https://morioh.com/p/777d15fe7828
边栏推荐
- Problems encountered in IM instant messaging development to maintain heartbeat
- 【Hot100】19. 删除链表的倒数第 N 个结点
- StoneDB 为国产数据库添砖加瓦,基于 MySQL 的一体化实时 HTAP 数据库正式开源!
- 2022 Moonriver global hacker song winning project list
- Preliminary study on golang crawler framework
- Five years after graduation, I became a test development engineer with an annual salary of 30w+
- Smart Party Building: faith through time and space | 7.1 dedication
- China's intelligent transportation construction from the perspective of "one hour life circle" in Dawan District
- Use Tencent cloud to build a map bed service
- Zabbix2.2 monitoring system and application log monitoring alarm
猜你喜欢

毕业后5年,我成为了年薪30w+的测试开发工程师

2022 Moonriver global hacker song winning project list
![[nodemon] app crashed - waiting for file changes before starting...解决方法](/img/ee/9830afd86e092851a2a906cb994949.png)
[nodemon] app crashed - waiting for file changes before starting...解决方法

Sqlserver query: when a.id is the same as b.id, and the A.P corresponding to a.id cannot be found in the B.P corresponding to b.id, the a.id and A.P will be displayed

圈铁发音,动感与无噪强强出彩,魔浪HIFIair蓝牙耳机测评

Zhou Shaojian, rare

OJ questions related to complexity (leetcode, C language, complexity, vanishing numbers, rotating array)

【SQL语句】请问这边为什么select出了两个上海,查询出了不同的count我想让他变成一个上海,count只显示一个总和

超视频时代,什么样的技术会成为底座?

德国iF多项大奖加冕,这副耳机有多强?音珀GTW 270 Hybrid深度评测
随机推荐
部门来了个拿25k出来的00后测试卷王,老油条表示真干不过,已被...
虚拟串口模拟器和串口调试助手使用教程「建议收藏」
Comment win11 définit - il les permissions de l'utilisateur? Win11 comment définir les permissions de l'utilisateur
ABAP call restful API
[nodemon] app crashed - waiting for file changes before starting...解决方法
Which MySQL functions are currently supported by tablestore in table storage?
UML旅游管理系统「建议收藏」
ThinkPHP kernel work order system source code commercial open source version multi user + multi customer service + SMS + email notification
There will be a gap bug when the search box and button are zoomed
Is the programmer's career really short?
Malaysia's Star: Sun Yuchen is still adhering to the dream of digital economy in WTO MC12
红队第8篇:盲猜包体对上传漏洞的艰难利用过程
Zabbix2.2 monitoring system and application log monitoring alarm
數據庫系統原理與應用教程(006)—— 編譯安裝 MySQL5.7(Linux 環境)
There is a difference between u-standard contract and currency standard contract. Will u-standard contract explode
Does 1.5.1 in Seata support mysql8?
How to write good code - Defensive Programming Guide
Microservice tracking SQL (support Gorm query tracking under isto control)
Go 语言错误处理为什么更推荐使用 pkg/errors 三方库?
近半年内连获5家“巨头”投资,这家智能驾驶“黑马”受资本追捧