dongzhong2018 2016-08-30 14:04
浏览 39
已采纳

从导入包中堆栈跟踪go例程?

How to obtain the stack trace of the last (ideally of all) go routine (the app has multiple go routines) which panicked and recovered and logged only a not much descriptive error message? I don't know which routine recovered. Also, please keep in mind that I will not alter the code of any imported package. This panic happened in some of the imported packages which creates multiple go routines so I need a way to grab the stack trace of the last recovered routine in order to find where it panic.

  • 写回答

1条回答 默认 最新

  • duandun2136 2016-08-30 14:30
    关注

    The short answer is: Not possible but there are exceptions.

    Golang has a few stack control methods and types.

    You can control the stack levels with runtime/debug/SetTraceback

    func SetTraceback(level string)

    SetTraceback sets the amount of detail printed by the runtime inthe traceback it prints before exiting due to an unrecovered panic or an internal runtime error. The level argument takes the same values as the GOTRACEBACK environment variable. For example, SetTraceback("all") ensure that the program prints all goroutines when it crashes.
    See the package runtime documentation for details. If SetTraceback is called with a level lower than that of the environment variable, the call is ignored.

    You can also print the stack strace with runtime/debug/Stack

    func Stack() []byte

    Stack returns a formatted stack trace of the goroutine that calls it. It calls runtime.Stack with a large enough buffer to capture the entire trace.

    Also you need to understand how the Built-in funct recover works.

    The recover built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function (but not any function called by it) stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil, recover returns nil. Thus the return value from recover reports whether the goroutine is panicking.

    func recover() interface{}

    Working Example

    This example assumes that the package does not call recover (detailed in another section).

    Golang Playground Link

    package main
    
    import (
        "log"
        "errors"
        "runtime/debug"
        "time"
    )
    
    func f2() {
        panic(errors.New("oops")) // line 11
    }
    
    func f1() {
        f2() // line 15
    }
    
    func main() {
        defer func() {
            if e := recover(); e != nil {
                log.Printf("%s: %s", e, debug.Stack()) // line 20
            }
        }()
    
        go f1() // line 25
    
        time.Sleep(time.Second * 1)
    }
    

    If package calls recover

    If the code is recovering from the panic you need to use a debugger or remove the recover to understand what is going on as seen on the example below which demonstrate that recovered panics can not be "recovered" again.

    Golang Playground Link

    package main
    
    import (
        "log"
        "errors"
        "runtime/debug"
        "time"
    )
    
    func f2() {
        panic(errors.New("oops")) // line 11
    }
    
    func f1() {
        defer func() {
            if e := recover(); e != nil {
                log.Printf("internal %s: %s", e, debug.Stack()) // line 20
            }
        }()
        f2() // line 15
    }
    
    func main() {
        defer func() {
            if e := recover(); e != nil {
                log.Printf("external %s: %s", e, debug.Stack()) // line 20
            } else {
                log.Println("Nothing to print")
            }
        }()
    
        go f1() // line 25
    
        time.Sleep(time.Second * 1)
    }
    

    Lesser then two evils

    Debug with Delve Or temporaly edit the package so it logs the full message (once understood you can revert the changes).

    Also if you find the problem let the package author know so it can be fixed.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。