doumen6532
2015-10-09 09:07
浏览 548
已采纳

如何获取指向Golang中实际错误原因的堆栈跟踪?

Let's say I have some code like this:

value, err := some3rdpartylib.DoSomething()
if err != nil {
    panic(err)
}

In case err != nil I will get something like this:

panic: some error explanation here

goroutine 1 [running]:
main.main()
    /tmp/blabla/main.go:6 +0x80

This stack trace is completely legit but sometimes these error messages may not clarify what happened and so I'd like to dig deeper into the source code of the 3rd party library to investigate what exactly causes this error to be returned. However when my code panics like this, there is no way to get the actual place that returned this error.

A little bit more clarification: as I'm coming from JVM world where exceptions are thrown I can completely trace what exactly line of code thrown the exception and thus can easily find the place and see what gone wrong. Go stack trace ends exactly where my code panics and thus not too useful in my case.

I've created a playground here and ideally I'd like to be able to trace the error to the place it was actually returned from, not panic. (e.g. to line 17, return "", errors.New("some error explanation here"))

Is this even possible?

图片转代码服务由CSDN问答提供 功能建议

假设我有一些这样的代码:

  value  ,err:= some3rdpartylib.DoSomething()
if err!= nil {
 panic(err)
} 
   
 
 

如果 err!= nil 我会得到这样的东西:

  panic:这里有些错误的解释
 
goroutine 1 [运行中]:
main.main()
 /  tmp / blabla / main.go:6 + 0x80 
   
 
 

此堆栈跟踪完全合法,但有时这些错误消息可能无法阐明发生了什么,因此我想 深入研究第三方库的源代码,以调查究竟是什么原因导致返回此错误。 但是,当我的代码如此恐慌时,无法获得返回此错误的实际位置。

需要更多说明:因为我来自JVM世界,其中存在异常 我可以完全跟踪抛出异常的确切代码行,从而可以轻松找到位置并查看出了什么问题。 Go堆栈跟踪恰好在我的代码恐慌的地方结束,因此在我的情况下不太有用。

我创建了一个游乐场此处,理想情况下,我希望能够将错误跟踪到实际返回错误的位置,而不必担心。 (例如,到第17行,返回“”,errors.New(“此处有一些错误说明”)

这是否可能? \ n

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

5条回答 默认 最新

  • dqd54099 2015-10-09 10:18
    已采纳

    Shortly: this is not possible. Since errors are values, they are not treated in any special way. Due to this, when function (normally) returns, stack is no more available (ie. another function call may overwrite memory used by returning-error function' stack).

    There is a tool called trace which was introduced with go1.5, but for now, there is no comprehensive tutorial available neither any of those I found says that this kind of feature will be included.

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • dongpuchao1680 2017-09-05 14:57

    Take a look at: https://github.com/efimovalex/stackerr

    Is this the thing you are looking for?

    package main
    
    import "github.com/efimovalex/stackerr"
    import "fmt"
    
    func f1() *stackerr.Err {
        err := stackerr.Error("message")
        return err.Stack()
    }
    
    func f2() *stackerr.Err {
        err := f1()
        return err.Stack()
    }
    
    type t1 struct{}
    
    func (t *t1) f3() *stackerr.Err {
        err := f2()
        return err.Stack()
    }
    
    func main() {
        ts := t1{}
        err := ts.f3()
    
        err.Log()
    }
    

    Result:

    2017/08/31 12:13:47 Error Stacktrace:
    -> github.com/efimovalex/stackerr/example/main.go:25 (main.main)
    -> github.com/efimovalex/stackerr/example/main.go:19 (main.(*t1).f3)
    -> github.com/efimovalex/stackerr/example/main.go:12 (main.f2)
    -> github.com/efimovalex/stackerr/example/main.go:7 (main.f1)
    
    评论
    解决 无用
    打赏 举报
  • dongwen750492 2017-12-13 00:33

    As others have pointed out tracing errors in go isn't trivial. There are projects like jujo/errors, that allow you to wrap errors and then trace these errors back. For that to work tough, you must use them consistently throughout your project and that won't help you with errors in 3rd party libraries or with errors that get handled and never get returned.

    Because this is such a common issue and I really got annoyed with this. I wrote a small debug utility that will add debug code to go files that logs every returned error (value that implements error) and the function in which it was returned to STDOUT (if you need more advanced logging just hack the logger in the project it's really simple).

    Installation

    go get github.com/gellweiler/errgotrace
    go install github.com/gellweiler/errgotrace
    

    Usage

    To debug all files in the current directory:

    $ find . -name '*.go' -print0 | xargs -0 errgotrace -w
    

    To remove the added debug code from the go files:

    $ find . -name '*.go' -print0 | xargs -0 errgotrace -w -r
    

    Then just simply compile & run your code or your test cases.

    Sample Output

    [...]
    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
    [...]
    

    As you can see from this output, it's really easy to tell in which function the error originally occurred. Once you know that, you can use a debugger to get more context.

    评论
    解决 无用
    打赏 举报
  • dongyashun2559 2018-02-27 09:22

    I think that there is an easier way to achieve this. You can try wrapping errors using the golang "default" error package:

    You need to define the interface to be implemented by your error :

    type stackTracer interface {
        StackTrace() errors.StackTrace
    }
    

    Then use it when wrapping/treating an error :

    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
    
    评论
    解决 无用
    打赏 举报
  • dongrunying7537 2019-02-12 15:32

    Take a look at https://github.com/ztrue/tracerr

    I created this package in order to have both stack trace and source fragments to be able to debug faster and log errors with much more details.

    Here is a code example:

    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)
    }
    

    And here is the output: golang error stack trace

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题