package main
import (
"log"
"github.com/pkg/errors"
)
func myError() error {
return errors.New("failing unconditionally")
}
func myError1() error {
return errors.Errorf("annotate with additional debug info: %+v", myError())
}
func myError2() error {
return errors.Errorf("extra debug info: %+v", myError1())
}
func main() {
if err := myError2(); err != nil {
log.Printf("%+v", err)
}
}
我用
errors.New
创建错误并使用errors.Errorf
添加额外信息。它能够记录和打印堆栈跟踪和行号,符合我的需求。但是,问题在于
log.Printf("%+v", err)
的输出冗长而重复。2009/11/10 23:00:00 extra debug info: annotate with additional debug info: failing unconditionally
main.myError
/tmp/sandbox3329712514/prog.go:10
main.myError1
/tmp/sandbox3329712514/prog.go:14
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
main.myError1
/tmp/sandbox3329712514/prog.go:14
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
根据我的理解,
errors
包在每次注释错误时都会将额外的堆栈跟踪复制附加到错误中,如下面的代码片段所示。// repetitive (thrice) error stack
main.myError
/tmp/sandbox3329712514/prog.go:10
main.myError1
/tmp/sandbox3329712514/prog.go:14
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
main.myError1
/tmp/sandbox3329712514/prog.go:14
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
我的期望输出是:
// Desired output
2009/11/10 23:00:00 extra debug info: annotate with additional debug info: failing unconditionally
main.myError
/tmp/sandbox3329712514/prog.go:10
main.myError1
/tmp/sandbox3329712514/prog.go:14
main.myError2
/tmp/sandbox3329712514/prog.go:18
main.main
/tmp/sandbox3329712514/prog.go:22
runtime.main
/usr/local/go-faketime/src/runtime/proc.go:250
runtime.goexit
/usr/local/go-faketime/src/runtime/asm_amd64.s:1571
实现这一目标的方法之一是只使用
errors
包来发出错误,然后在调用堆栈中使用fmt.Errorf
和%+v
添加附加信息(例如https://go.dev/play/p/OrWe6KUIL_m)。但是,这种方法容易出错,在大型代码库中强制每个开发人员都使用这种模式很困难。开发人员必须记住使用errors
包来发出错误,并使用%+v
%s
正确打印出堆栈跟踪。
我想知道这是否是期望的行为(冗长重复)。是否有可能始终使用errors
包来注释沿着调用堆栈的错误,而不必担心附加重复的堆栈跟踪副本(例如,errors
自动知道错误已经有了堆栈跟踪)?