乐趣区

关于golang:Golang-githubcompkgerrors-包使用的正确姿势

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

退出移动版