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 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀