当前位置:网站首页>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
边栏推荐
- Zabbix2.2 monitoring system and application log monitoring alarm
- Vscode find and replace the data of all files in a folder
- Task. Run(), Task. Factory. Analysis of behavior inconsistency between startnew() and new task()
- 分享在大疆DJI(深圳总部)工作的日常和福利
- How does win11 set user permissions? Win11 method of setting user permissions
- [daily question] 1175 Prime permutation
- 制造业数字化转型究竟是什么
- 表格存储中tablestore 目前支持mysql哪些函数呢?
- Microservice tracking SQL (support Gorm query tracking under isto control)
- Endeavouros mobile hard disk installation
猜你喜欢

Nuxt. JS data prefetching

【LeetCode】43. String multiplication

Is the programmer's career really short?

Zhou Shaojian, rare

复杂度相关OJ题(LeetCode、C语言、复杂度、消失的数字、旋转数组)

How to write good code - Defensive Programming Guide

电脑照片尺寸如何调整成自己想要的

Embedded development: five revision control best practices

投稿开奖丨轻量应用服务器征文活动(5月)奖励公布

EndeavourOS移动硬盘安装
随机推荐
OJ questions related to complexity (leetcode, C language, complexity, vanishing numbers, rotating array)
Comprehensively view the value of enterprise digital transformation
Golang爬虫框架初探
Is the programmer's career really short?
How long will it take to achieve digital immortality? Metacosmic holographic human avatar 8i
2023 spring recruitment Internship - personal interview process and face-to-face experience sharing
Zabbix2.2监控之系统及应用日志监控报警
Apple's self-developed baseband chip failed again, which shows Huawei Hisilicon's technological leadership
SQLServer查询: a.id与b.id相同时,a.id对应的a.p在b.id对应的b.p里找不到的话,就显示出这个a.id和a.p
In the era of super video, what kind of technology will become the base?
Zhou Shaojian, rare
picgo快捷键 绝了这人和我的想法 一模一样
PostgreSQL 存储结构浅析
process.env.NODE_ENV
laravel的模型删除后动作
红队第10篇:coldfusion反序列化过waf改exp拿靶标的艰难过程
[nodemon] app crashed - waiting for file changes before starting...解决方法
Go 语言源码级调试器 Delve
动作捕捉系统用于苹果采摘机器人
揭秘慕思“智商税”:狂砸40亿搞营销,发明专利仅7项