当前位置:网站首页>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
边栏推荐
- Research on multi model architecture of ads computing power chip
- Solution to the problem that the keypad light does not light up when starting up
- UML tourism management system "suggestions collection"
- Apple's self-developed baseband chip failed again, which shows Huawei Hisilicon's technological leadership
- picgo快捷键 绝了这人和我的想法 一模一样
- Go 语言怎么优化重复的 if err != nil 样板代码?
- 【Hot100】19. 删除链表的倒数第 N 个结点
- Zabbix2.2监控之系统及应用日志监控报警
- 揭秘慕思“智商税”:狂砸40亿搞营销,发明专利仅7项
- Tutorial on principles and applications of database system (006) -- compiling and installing MySQL 5.7 (Linux Environment)
猜你喜欢

【Hot100】20. Valid parentheses

程序员职业生涯真的很短吗?

The Department came to a Post-00 test paper king who took out 25K. The veteran said it was really dry, but it had been

What is the digital transformation of manufacturing industry

【Hot100】19. 删除链表的倒数第 N 个结点

Summer Challenge harmonyos canvas realize clock

德国iF多项大奖加冕,这副耳机有多强?音珀GTW 270 Hybrid深度评测
![[IDM] IDM downloader installation](/img/2b/baf8852b422c1c4a18e9c60de864e5.png)
[IDM] IDM downloader installation

分享在大疆DJI(深圳总部)工作的日常和福利

process.env.NODE_ENV
随机推荐
Tutorial on principles and applications of database system (006) -- compiling and installing MySQL 5.7 (Linux Environment)
Go 语言错误处理为什么更推荐使用 pkg/errors 三方库?
Pico,是要拯救还是带偏消费级VR?
[PHP graduation design] design and implementation of textbook management system based on php+mysql+apache (graduation thesis + program source code) -- textbook management system
Seata中1.5.1 是否支持mysql8?
Origin2018安装与使用(整理中)
如何使用phpIPAM来管理IP地址和子网
OJ questions related to complexity (leetcode, C language, complexity, vanishing numbers, rotating array)
[open source data] open source data set for cross modal (MRI, Meg, eye movement) human spatial memory research based on virtual reality scenes
Summer Challenge harmonyos canvas realize clock
实现数字永生还有多久?元宇宙全息真人分身#8i
Go 语言怎么使用对称加密?
从 MLPerf 谈起:如何引领 AI 加速器的下一波浪潮
Vscode find and replace the data of all files in a folder
數據庫系統原理與應用教程(006)—— 編譯安裝 MySQL5.7(Linux 環境)
制造业数字化转型究竟是什么
红队第10篇:coldfusion反序列化过waf改exp拿靶标的艰难过程
Origin2018 installation and use (sorting)
Introduction to RT thread env tool (learning notes)
IM即时通讯开发万人群聊消息投递方案