V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
lightjiao
V2EX  ›  Go 编程语言

Golang 里 goroutine a 调用 goroutine b, b 里面发生了 panic,能知道是谁调用了 a 导致这次请求的吗?

  •  
  •   lightjiao ·
    lightjiao · 339 天前 via iPhone · 1609 次点击
    这是一个创建于 339 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如如下代码,开发时如何知道这个 panic 是由于 main 函数调用触发的

    func main() {
        go TestGoException()
        time.Sleep(1000)
    }
    
    func TestGoException() {
        go TestGoException2()
    }
    
    func TestGoException2() {
        panic("this is a panic")
    }
    
    第 1 条附言  ·  339 天前
    ```
    func main() {
        randomizer := rand.New(rand.NewSource(1000))
        go DelayPanic(randomizer.Int())
        go DelayPanic(randomizer.Int())
        time.Sleep(time.Second * 2)
    }
    func DelayPanic(n int) {
        time.Sleep(time.Millisecond * time.Duration(n))
        go TestGoException()
    }

    func TestGoException() {
        go TestGoException2()
    }

    func TestGoException2() {
        // 原始的需求是希望这个函数里的 log 或者 panic ,能知道是 main 函数里的哪一行导致的调用
        panic("this is a panic")
    }
    ```
    14 条回复    2023-05-15 18:28:39 +08:00
    aapeli
        1
    aapeli  
       339 天前
    time.Sleep(1000) 这个值太小了(1000 纳秒), 改成 time.Sleep(time.Second * 1) 试试, panic 后堆栈会打印出来


    ```xxx
    panic: this is a panic

    goroutine 6 [running]:
    main.TestGoException2()
    /Users/aapeli/main.go:15 +0x45
    created by main.TestGoException
    /Users/aapeli/main.go:10 +0x25
    exit status 2
    ```
    aapeli
        2
    aapeli  
       339 天前
    通过堆栈信息可以获取到最近一次 panic 产生的位置.
    GopherDaily
        3
    GopherDaily  
       339 天前
    - 记忆中没有
    - 间接的方法是用 context 传递
    - 这是个伪需求
    AnroZ
        5
    AnroZ  
       339 天前
    如果在 TestGoException2 函数内可以 recover 的话,是可以通过获取 runtime.Stack 获取调用堆栈信息。比如:
    ```
    func TestGoException2() {
    defer func() {
    if info := recover(); info != nil {
    fmt.Println(info)

    buff := make([]byte, 1024)
    runtime.Stack(buff, false)

    fmt.Println(string(buff))
    }
    }()

    panic("this is a panic")
    }
    ```
    lightjiao
        6
    lightjiao  
    OP
       339 天前 via iPhone   ❤️ 1
    @aapeli
    @AnroZ
    我分别尝试了二位的方法,并不能打印出完整的 stack ,无法知道最开始是 main 调用触发的,还是其他函数触发的
    lightjiao
        7
    lightjiao  
    OP
       339 天前 via iPhone
    @GopherDaily
    开发期间追踪异步调用链排查问题是最基础的需求
    Context 我没试过,对这块不太熟
    aapeli
        8
    aapeli  
       339 天前
    ```xxx
    panic: this is a panic

    goroutine 6 [running]:
    main.TestGoException2()
    /Users/aapeli/main.go:15 +0x45 # painic 的位置
    created by main.TestGoException
    /Users/aapeli/main.go:10 +0x25. # 这里有告诉你是谁调用的 TestGoException2
    exit status 2
    ```
    lightjiao
        9
    lightjiao  
    OP
       339 天前 via iPhone
    @aapeli 我期望的是谁调用了 TestGoException ,需要一条完整的异步调用链
    docxs
        10
    docxs  
       339 天前 via iPhone   ❤️ 1
    g 的原始结构里有个 gopc 字段,是创建这个 g 的父 g 的 pc 位置,试试依次回溯
    aapeli
        11
    aapeli  
       339 天前
    要不试试 jaeger 之类的 opentracing 吧,成熟的链路追踪产品,有 UI 告诉你相关的调用链路

    https://github.com/opentracing/opentracing-go
    https://www.jaegertracing.io/
    https://github.com/jaegertracing/jaeger
    lightjiao
        12
    lightjiao  
    OP
       339 天前 via iPhone
    @aapeli 链路追踪产品是给分布式微服务用的,我这里显然不是这个场景,你可以看一下我的 append
    hzzhzzdogee
        13
    hzzhzzdogee  
       339 天前
    f 应该没有办法
    AnroZ
        14
    AnroZ  
       339 天前   ❤️ 1
    @lightjiao runtime.Stack(buff, true)倒是可以打印所有在运行的堆栈。
    但在你这个例子中,因为调用 TestGoException 的 goroutine 其实也早已退出了,所以即使调用 runtime.Stack(buff, true)也是打印不出来的。
    如果你想实现你想要的追溯,建议自己增加 log 记录或增加上下文信息
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3203 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:08 · PVG 21:08 · LAX 06:08 · JFK 09:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.