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.

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

报告相同问题?

悬赏问题

  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启