Golang 的 error 不会像 Java 那样打印 stackTrack 信息。回溯 err 十分不不便。
之前见过比拟蠢的的做法是层层 log,写起来贼吃力。
大家应该都晓得能够通过 github.com/pkg/errors
这个包来解决 err,WithStack(err)
函数能够打印 stack。
留神,应用 log.Errorf("%+v", err)
才会打印 stackTrack,应用 %v %s
不行。
然而如果屡次应用 WithStack(err)
,会将 stack 打印多遍,err 信息可能十分长。像这样:
err_test.go:35: err: normal error
github.com/win5do/golang-microservice-demo/pkg/lib/errx.errMulti
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:29
github.com/win5do/golang-microservice-demo/pkg/lib/errx.TestOriginWithStack
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:35
testing.tRunner
/usr/local/Cellar/go/1.15.5/libexec/src/testing/testing.go:1123
runtime.goexit
/usr/local/Cellar/go/1.15.5/libexec/src/runtime/asm_amd64.s:1374
github.com/win5do/golang-microservice-demo/pkg/lib/errx.errMulti
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:30
github.com/win5do/golang-microservice-demo/pkg/lib/errx.TestOriginWithStack
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:35
testing.tRunner
/usr/local/Cellar/go/1.15.5/libexec/src/testing/testing.go:1123
runtime.goexit
/usr/local/Cellar/go/1.15.5/libexec/src/runtime/asm_amd64.s:1374
github.com/win5do/golang-microservice-demo/pkg/lib/errx.errMulti
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:31
github.com/win5do/golang-microservice-demo/pkg/lib/errx.TestOriginWithStack
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:35
testing.tRunner
/usr/local/Cellar/go/1.15.5/libexec/src/testing/testing.go:1123
runtime.goexit
/usr/local/Cellar/go/1.15.5/libexec/src/runtime/asm_amd64.s:1374
能够看到这个 stack 信息反复了三次。能够人肉去 check 上层有没有应用 WithStack(err)
,如果上层用了下层就不必。但这样会减少心智累赘,容易出错。
咱们能够在调用是应用一个 wrap 函数,判断一下是否曾经执行 WithStack(err)
。
然而 github.com/pkg/errors
自定义的 error 类型 withStack
是公有类型,如何去判断是否曾经执行 WithStack(err)
呢?
好在 StackTrace
不是公有类型,所以咱们能够应用 interface 的一个小技巧,本人定义一个 interface,如果领有 StackTrace()
办法则不再执行 WithStack(err)
。像这样:
type stackTracer interface {StackTrace() errors2.StackTrace
}
func WithStackOnce(err error) error {
if !stackFlag {return err}
_, ok := err.(stackTracer)
if ok {return err}
return errors2.WithStack(err)
}
有人可能要问 StackTrace
也是公有类型咋办?那就 fork 而后间接改源码吧。
当初应用这个 wrap 函数打印进去的 stackTrace 就不会反复和简短。像这样:
err_test.go:21: err: normal error
github.com/win5do/golang-microservice-demo/pkg/lib/errx.WithStackOnce
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err.go:27
github.com/win5do/golang-microservice-demo/pkg/lib/errx.errOnce
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:13
github.com/win5do/golang-microservice-demo/pkg/lib/errx.TestWithStackOnce
/Users/wufeng/code/codebase/self/gorm-demo/pkg/lib/errx/err_test.go:19
testing.tRunner
/usr/local/Cellar/go/1.15.5/libexec/src/testing/testing.go:1123
runtime.goexit
/usr/local/Cellar/go/1.15.5/libexec/src/runtime/asm_amd64.s:1374
残缺代码参考:https://github.com/win5do/go-…