假设我有一些像这样的代码:
value, err := some3rdpartylib.DoSomething()
if err != nil {
panic(err)
}
Run Code Online (Sandbox Code Playgroud)
万一err != nil我会得到这样的东西:
panic: some error explanation here
goroutine 1 [running]:
main.main()
/tmp/blabla/main.go:6 +0x80
Run Code Online (Sandbox Code Playgroud)
这个堆栈跟踪是完全合法的,但有时这些错误消息可能无法澄清发生了什么,所以我想深入研究第三方库的源代码,以调查究竟是什么原因导致返回此错误.但是,当我的代码像这样恐慌时,无法获得返回此错误的实际位置.
稍微澄清一点:因为我来自JVM世界,抛出异常,我可以完全跟踪抛出异常的确切代码行,从而可以轻松找到该位置,看看出了什么问题.Go堆栈跟踪正好在我的代码恐慌的地方结束,因此在我的情况下不太有用.
我在这里创建了一个游乐场,理想情况下我希望能够将错误追踪到它实际返回的地方,而不是恐慌.(例如到第17行return "", errors.New("some error explanation here"))
这甚至可能吗?
我认为有一种更简单的方法可以实现这一目标。您可以尝试包装错误使用golang“默认”的错误包:
您需要定义要由您实现的接口error:
type stackTracer interface {
StackTrace() errors.StackTrace
}
Run Code Online (Sandbox Code Playgroud)
然后在包装/处理错误时使用它:
err, ok := errors.(stackTracer) // ok is false if errors doesn't implement stackTracer
stack := err.StackTrace()
fmt.Println(stack) // here you'll have your stack trace
Run Code Online (Sandbox Code Playgroud)
正如其他人指出的那样,跟踪 go 中的错误并不是微不足道的。有一些项目,如juju/errgo,允许您包装错误,然后追溯这些错误。为了使其工作顺利,您必须在整个项目中一致地使用它们,这不会帮助您解决第 3 方库中的错误或已处理但永远不会返回的错误。
因为这是一个很常见的问题,而且我真的对此很恼火,所以我编写了一个小型调试实用程序,它将添加调试代码到 go 文件中,记录每个返回的错误(实现的值error)以及返回到 STDOUT 的函数(如果您需要更高级的日志记录,只需破解项目中的记录器即可,这非常简单)。
安装
go get github.com/gellweiler/errgotrace
Run Code Online (Sandbox Code Playgroud)
用法
调试当前目录中的所有文件:
$ find . -name '*.go' -print0 | xargs -0 errgotrace -w
Run Code Online (Sandbox Code Playgroud)
要从 go 文件中删除添加的调试代码:
$ find . -name '*.go' -print0 | xargs -0 errgotrace -w -r
Run Code Online (Sandbox Code Playgroud)
然后只需编译并运行您的代码或测试用例即可。
样本输出
[...]
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectKey: EOF token found
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectItem: EOF token found
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectKey: EOF token found
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectItem: EOF token found
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectKey: At 3:4: nested object expected: LBRACE got: ASSIGN
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectItem: At 3:4: nested object expected: LBRACE got: ASSIGN
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.objectList: At 3:4: nested object expected: LBRACE got: ASSIGN
2017/12/13 00:54:39 [ERRGOTRACE] parser.*Parser.Parse: At 2:31: literal not terminated
2017/12/13 00:54:39 [ERRGOTRACE] parser.Parse: At 2:31: literal not terminated
2017/12/13 00:54:39 [ERRGOTRACE] hcl.parse: At 2:31: literal not terminated
2017/12/13 00:54:39 [ERRGOTRACE] hcl.ParseBytes: At 2:31: literal not terminated
2017/12/13 00:54:39 [ERRGOTRACE] formula.parse: parsing failed
[...]
Run Code Online (Sandbox Code Playgroud)
正如您从这个输出中看到的,很容易判断错误最初发生在哪个函数中。一旦了解了这一点,您就可以使用调试器来获取更多上下文。
小智 5
看看https://github.com/ztrue/tracerr
我创建这个包是为了拥有堆栈跟踪和源代码片段,以便能够更快地调试并记录更多详细信息的错误。
这是一个代码示例:
package main
import (
"io/ioutil"
"github.com/ztrue/tracerr"
)
func main() {
if err := read(); err != nil {
tracerr.PrintSourceColor(err)
}
}
func read() error {
return readNonExistent()
}
func readNonExistent() error {
_, err := ioutil.ReadFile("/tmp/non_existent_file")
// Add stack trace to existing error, no matter if it's nil.
return tracerr.Wrap(err)
}
Run Code Online (Sandbox Code Playgroud)
package main
import (
"errors"
"fmt"
)
func main() {
value, err := DoSomething()
if err != nil {
panic(err)
}
fmt.Println(value)
}
func DoSomething() (string, error) {
return "", errors.New("some error explanation here")
}
Run Code Online (Sandbox Code Playgroud)
问题是标准包errors没有在发生时附加堆栈跟踪。您可以使用github.com/pkg/errors来执行此操作:
package main
import (
"github.com/pkg/errors"
"fmt"
)
func main() {
value, err := DoSomething()
if err != nil {
fmt.Printf("%+v", err)
}
fmt.Println(value)
}
func DoSomething() (string, error) {
return "", errors.New("some error explanation here")
}
Run Code Online (Sandbox Code Playgroud)
$ go run stacktrace.go
some error explanation here
main.DoSomething
/Users/quanta/go/src/github.com/quantonganh/errors/stacktrace.go:18
main.main
/Users/quanta/go/src/github.com/quantonganh/errors/stacktrace.go:10
runtime.main
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/proc.go:204
runtime.goexit
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/asm_amd64.s:1374
Run Code Online (Sandbox Code Playgroud)
更多详细信息:https://dave.cheney.net/2016/06/12/stack-traces-and-the-errors-package