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

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

func main() {
    go TestGoException()
    time.Sleep(1000)
}

func TestGoException() {     go TestGoException2() }

func TestGoException2() {     panic(“this is a panic”) }


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

更多关于Golang Go语言中 goroutine a 调用 goroutine b,b 里面发生了 panic,能知道是谁调用了 a 导致这次请求的吗?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

15 回复

time.Sleep(1000) 这个值太小了(1000 纳秒), 改成 time.Sleep(time.Second * 1) 试试, panic 后堆栈会打印出来


xxx<br>panic: this is a panic<br><br>goroutine 6 [running]:<br>main.TestGoException2()<br> /Users/aapeli/main.go:15 +0x45<br>created by main.TestGoException<br> /Users/aapeli/main.go:10 +0x25<br>exit status 2<br>

更多关于Golang Go语言中 goroutine a 调用 goroutine b,b 里面发生了 panic,能知道是谁调用了 a 导致这次请求的吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


通过堆栈信息可以获取到最近一次 panic 产生的位置.

  • 记忆中没有
    - 间接的方法是用 context 传递
    - 这是个伪需求

如果在 TestGoException2 函数内可以 recover 的话,是可以通过获取 runtime.Stack 获取调用堆栈信息。比如:
<br>func TestGoException2() {<br> defer func() {<br> if info := recover(); info != nil {<br> fmt.Println(info)<br><br> buff := make([]byte, 1024)<br> runtime.Stack(buff, false)<br><br> fmt.Println(string(buff))<br> }<br> }()<br><br> panic("this is a panic")<br>}<br>



我分别尝试了二位的方法,并不能打印出完整的 stack ,无法知道最开始是 main 调用触发的,还是其他函数触发的


开发期间追踪异步调用链排查问题是最基础的需求
Context 我没试过,对这块不太熟

xxx<br>panic: this is a panic<br><br>goroutine 6 [running]:<br>main.TestGoException2()<br>/Users/aapeli/main.go:15 +0x45 # painic 的位置<br>created by main.TestGoException<br>/Users/aapeli/main.go:10 +0x25. # 这里有告诉你是谁调用的 TestGoException2<br>exit status 2<br>

我期望的是谁调用了 TestGoException ,需要一条完整的异步调用链

g 的原始结构里有个 gopc 字段,是创建这个 g 的父 g 的 pc 位置,试试依次回溯

要不试试 jaeger 之类的 opentracing 吧,成熟的链路追踪产品,有 UI 告诉你相关的调用链路

https://github.com/opentracing/opentracing-go
https://www.jaegertracing.io/
https://github.com/jaegertracing/jaeger

链路追踪产品是给分布式微服务用的,我这里显然不是这个场景,你可以看一下我的 append

f 应该没有办法

runtime.Stack(buff, true)倒是可以打印所有在运行的堆栈。
但在你这个例子中,因为调用 TestGoException 的 goroutine 其实也早已退出了,所以即使调用 runtime.Stack(buff, true)也是打印不出来的。
如果你想实现你想要的追溯,建议自己增加 log 记录或增加上下文信息

在 Go 语言中,当 goroutine a 调用 goroutine b,且 goroutine b 中发生了 panic 时,要追踪到是谁调用了 goroutine a 导致这次请求,通常需要借助一些运行时调试工具和编程约定。

Go 的内建 panic 和 recover 机制主要用于处理运行时错误,但它们本身不提供直接的调用链回溯到 goroutine a 的创建者或更上层调用者的功能。不过,你可以通过以下几种方式获取相关信息:

  1. 使用 debug/trace:启动程序时启用跟踪,可以生成一个跟踪文件,其中包含 goroutine 的创建和生命周期信息。这有助于你分析 goroutine a 是如何被创建的。

  2. 自定义日志:在创建 goroutine a 和调用 goroutine b 的代码中添加详细的日志记录,包括调用者信息(如函数名、行号)。这样,当 goroutine b panic 时,你可以通过日志回溯调用链。

  3. 使用第三方库:有些第三方库(如 go-stacktrace)能提供更详细的堆栈跟踪信息,帮助你在 panic 时获取更全面的调用链。

  4. 通过 runtime/debug:在 panic 发生时,可以使用 runtime/debug.Stack() 打印当前 goroutine 的堆栈信息,虽然这不会直接告诉你 goroutine a 的创建者,但结合日志和代码审查,可以间接推断。

总之,Go 语言本身不提供直接的功能来追踪到 goroutine a 的创建者,但通过上述方法,你可以构建出一个解决方案来分析和记录这类信息。

回到顶部