pkg errors包是如何输出错误信息及堆栈信息的

pkg errors包是如何输出错误信息及堆栈信息的

Content #

github.com/pkg/errors 是怎么实现输出错误信息和堆栈信息的呢?

它利用了 fmt 包的一个特性。fmt 包在打印 error 之前会判断当前打印的对象是否实现了 Formatter 接口,这个 formatter 接口只有一个 format 方法。如果要输出的对象实现了这个 Formatter 接口,则调用对象的 Format 方法来打印信息:

type Formatter interface {
    Format(f State, c rune)
}

而 github.com/pkg/errors 中提供的各种初始化 error 方法(包括 errors.New)封装了一个 fundamental 结构,这个结构就是实现了 Formatter 接口:

// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
        msg string
        *stack
}

这个 fundamental 结构中带着 error 的信息和堆栈信息。并且实现了 Format 方法。在 Format 方法中,判断调用 fmt.Printf 函数的第一个参数,如果是 +v,则打印错误内容和堆栈信息,如果是 v 或者 s,则打印错误内容,如果是 q,则打印转义后的信息:

func (f *fundamental) Format(s fmt.State, verb rune){
        switch verb {
        case 'v':
                if s.Flag('+') {
                        io.WriteString(s, f.msg)
                        f.stack.Format(s, verb)
                        return
                }
                fallthrough
        case 's':
                io.WriteString(s, f.msg)
        case 'q':
                fmt.Fprintf(s, "%q", f.msg)
        }
}

所以说,我们在实际的工作项目中,我建议你尽量使用 pkg/errors 而不是官方 error 库,这样我们能在错误出现的时候获取更多的错误信息,更快地定位问题。

Viewpoint #

From #

大咖助阵|叶剑峰:Go语言中常用的那些代码优化点