Git Product home page Git Product logo

go-errx's Introduction

errx - 更精准的定位和跟踪错误

GoDoc Go codecov License GoVersion Go Report Card

功能:

  • 封装引起错误的错误。
  • 为错误追加方法调用栈信息。
  • 业务预定义异常 BizError
  • 用于处理 recover() 结果的 PreserveRecover 方法。

安装:

go get -u github.com/cmstar/go-errx@latest

调用栈和错误链

Go 程序通常小而精,更多的用于中间件和系统编程,但有时仍会被用在上层的复杂业务里,和 Java 、 .net 同台,此时 Go 的错误处理模式就变得捉襟见肘起来。也许这就不是 Go 的设计意图,但真实的编码场景里,我们免不了碰到这样的情况。

Go 的 error 只是“不太特殊”的值而已(Errors are values),它太过于普通以至于不能像 Java/.net 的 Exception 一样携带足够多的信息。

在复杂的上层业务中,快速定位错误的位置显得极为重要,有时可以用运行性能换工作效率。


Wrap 方法

errx.Wrap 为错误添加更多的细节,返回一个 StackfulError 接口的实现,它包含方法:

  • Cause:记录引起错误的错误,类似 Java 的 Throwable.getCause() 或 .net 的 Exception.InnerException
  • Stack:记录创建错误(即调用 Wrap 方法)时的方法调用栈,类似 Java 的 Exception.printStackTrace() 或 .net 的 Exception.StackTrace
  • Error:即标准库的 error.Error() ,但它包含了 CauseStack 格式化后的信息。输出格式见下文《Describe 方法》。
  • ErrorWithoutStack:只包含错误的描述,不包含 Stack 的信息。

调用栈信息使用标准库的 runtime.CallersFrames 方法获取,有一定的性能开销。

BizError

在业务交互中,我们可能需要根据错误的类别进行不同的处理,原始的 error 等同于一个字符串,难以判断和分类。 errx 包定义了 BizError ,以便对错误进行分类。它是一个特殊的 error ,可通过 errx.NewBizError 方法创建。

BizError 提供:

  • 为每个错误添加一个整数型的错误码 Code ,以便更精准的对错误进行分类和定位,特别是在日志搜索时。通常0表示没有错误,其余值表示有错误,值由具体业务指定。
  • 包含调用栈信息 Stack
  • 包含 Cause ,即引起此错误的错误。

BizError.Error() 返回值格式为: (Code) Message ,不包含 CauseStack

BizError 的使用样例可参考 GoDoc 示例

go-webapi 框架使用 BizError 区分需要返回的业务错误和其他内部错误。

方法

Describe 方法

errx.Describeerrx.Wrap 添加的信息抽取出来,形成一段完整的错误描述,它包含各层级错误的信息及调用栈。

格式为:

最外层错误描述
--- 最外层错误的调用栈信息
=== 第1层内部错误的描述
--- 第1层内部错误的调用栈信息
=== 第2层内部错误的描述
--- 第2层内部错误的调用栈信息
...(逐层展示)
=== 最内层错误的描述
--- 最内层错误的描述的调用栈信息

实际示例可参考 GoDoc 示例


总体而言,就是让 Go 的 error 更像 Java/.net 的 Exception

当一个 errorWrap 之后返回给其调用者,调用者再次使用 Wrap 并返回给更上层的调用者, error 就形成了一个链条。

PreserveRecover 方法

我们可能需要利用应对 panic ,并将相关的错误信息保留下来,代码如下:

func do() (err error) {
    defer func() {
        r := recover()
        if r == nil {
            return
        }

        // 留存错误,丢失了调用栈信息。
        err = fmt.Errorf("do: %v", r)
    }()

    somethingThatMayPanic()
    return nil
}

利用 PreserveRecover 方法,这段代码可以简化成这样,当 recover() 的结果不是 nil 时,它会被 Wrap() 在一个错误里:

func do() (err error) {
    defer func() {
        // 留存错误,并保留调用栈信息。若 recover() 结果为 nil ,则 err 也是 nil 。
        err = errx.PreserveRecover("do", recover())
    }()

    somethingThatMayPanic()
    return nil
}

Run/RunE 方法

用于执行一个可能会 panic 的方法,自动添加 defer 过程,并通过 PreserveRecover 方法捕获错误。

func do() {
    err := errx.Run(func() {
        panic("oops!")
    })
    fmt.Println(err)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.