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-...