errors包装error对象, 添加调用栈及附加自定义信息, 以便于从日志中快速定位问题. 特点:
- 相比 github.com/pkg/errors github.com/juju/errors 开销小, 只在最早出错的地方会调用runtime.Callers, 只调用一次.
- 对齐调用栈和附加上下文信息, 按[ 文件名:行号 函数名:message ]分行格式化输出, funcName不显示package path, fileName不显示src之前的字符. Goland等IDE可以在控制台上点击错误信息定位源码.
- 精简调用栈输出, 默认忽略标准库和 github.com 下的包的调用栈, 也可以用SetFilterFunc自定义一些filter, 忽略一些固定的框架的调用栈信息.
文章: Go如何优雅地错误处理(Error Handling and Go 1)
doc:
func Errorf(err error, format string, a ...interface{}) error {
//...
}
用于包装上一步New/Errorf返回的error/*Err, 添加错误注释, 如 比"xx function error"更直接的错误说明、调用函数的参数值等
如果参数error类型不为*Err(error常量或自定义error类型或nil), 用于最早出错的地方, 会收集调用栈
如果参数error类型为*Err, 不会收集调用栈.
上层调用方可以通过GetInnerMost得到最里层被包装过的error常量
```go
// 示例代码1 非error常量的情况
// ExampleFunc1 调用func2 func2调用func3
// 在func3使用errors.Errorf时第一个参数传nil收集最完整的调用栈,
// 其他地方用errors.Errorf时第一个参数传上一步返回的error, 最后打log
func func1() {
requestID := "1"
err := func2()
if err != nil {
err = Errorf(err, "[%s] 123", requestID)
log.Print(err)
// log ouuput:
/*
2017/09/02 18:55:35 [errors/example.go:33:func3:unexpected param]
[ errors/example.go:25 func2:i=3]
[ errors/example.go:15 func1:[1] 123]
[ errors/error_test.go:22 TestExample:]
*/
}
return
}
func func2() (err error) {
i := 3
err = func3(i)
if err != nil {
return Errorf(err, "i=%d", i)
}
return
}
func func3(i int) (err error) {
return Errorf(nil, "unexpected param")
}
var (
errSomeUnexpected = errors.New("someUnexpected")
)
// 示例代码2 error常量的情况
// ExampleFunc11 调用func22 func22调用func33
// 在func33使用errors.Errorf包装error常量,收集最完整的调用栈, 最后打log
// 调用func22处可以调GetInnerMost()方法来取到最里层被包装的error常量
func func11() {
requestID := "11"
err := func22()
if err != nil {
err = Errorf(err, "[%s] 123", requestID)
log.Print(err)
// log output:
/*
2017/09/02 18:55:35 [errors/example.go:67:func33:unexpected param err:someUnexpected]
[ errors/example.go:56 func22:i=3]
[ errors/example.go:46 func11:[11] 123]
[ errors/error_test.go:26 TestExample2:]
*/
}
return
}
func func22() (err error) {
i := 3
err = func33(i)
if err != nil {
if err2, ok := err.(*Err); ok && err2.Inner() == errSomeUnexpected {
fmt.Printf("==\n识别到上一步的std error:%s\n==\n", err2.Inner())
}
return Errorf(err, "i=%d", i)
}
return
}
func func33(i int) (err error) {
return Errorf(errSomeUnexpected, "unexpected param")
}