程序里面用了若干 go 子线程(盲猜问题在子线程但是无法定位),有些错误会直接 os.exit ,每个函数方法都写了 panic 捕获写日志,程序退出时不会返回 panic 。
大神们有什么好的办法定位错误处吗?
生产环境问题出了几个月还是找不到问题,有时运行半天,有时运行几天,退出的时候 cpu 和内存都没有大量占用

b os.exit

试试 sentry ?

找找有没有不安全指针

attach processes 或者直接远程上去 debug ?

我最近也遇到了类似的 Bug ,服务器崩溃了,但是 Sentry 无法收集到崩溃,但是退出还是有日志的。

我遇到的情况是这样的:一个第三方库出了些问题,在 map 里面野指针了。而 Map 在 Go Runtime 里面的实现是 ASM 实现的,然后 Link 到 Runtime 里面。如果 ASM 内部发生了野指针相关的问题,直接会被系统走了 unix signal 退出,导致无法被 recover handle 。

我看日志说 os.Exit() 会把程序立即退出,这个真的是你需要的函数吗?

设置环境变量 GOTRACEBACK=crash 运行 Go 程序,core dump 后用 GDB 查,参见: pkg.go.dev/runtime

不是自己主动写的 os.exit 而是一些莫名的错误导致的

就是找起来很麻烦 代码行一多逻辑一复杂简直不可能

你是如何找到错误地方的?

1.lint 错误全部要修改过来
2.race 运行检测
3.付费请人

错误只会产生 err ,Exit 自己主动调用才会被执行

map 并发读写导致的程序崩溃。这种崩溃通过 panic 无法捕捉,检查下全局 map 是否有并发读写的情况吧。

看看日志库,有没有接管退出方法,导致退出前没有 flush 日志。
如果短时间可以浮现,服务器上 nohup strace 启动服务看退出前的行为。

先跑一遍 golangci-lint 吧。

这个会有堆栈信息的

  1. strace
    可以有这个 api 的调用关系
  2. gdb
    有堆栈

    log 文件呀,我 go 的 binary 的启动是套了一层 supervisor 的,在 supervisor 对应的 err 里面是有崩溃 stack trace 的

在 Goroutines 里面写 defer func(){}

像楼上说的,多打日志。我之前也是有这种类似的情况,多打日志就好了,极限一点每个模块都用不同的日志文件记录,方便定位

我只是在每个子线程里面的 defer 捕获 panic ,但是出错的地方根本没有返回 panic ,感觉是直接 os
.exit 了

打了日志啊,根本没有信息

supervisor 是啥 属于 go 的范围吗?还是 linux 层面的?

跑了没问题

貌似直接崩溃有好些可能性,比如指针错误,并发写入公共变量,还有第三方库可能是 os.exit

本质上就是 stderr 啊...

什么神仙第三方库会 os.Exit() ?

提示一点……panic 日志是不会打在你指定的文件里的,总是输出到 stderr

所以如果你没对 stderr 进行重定向的话,应该是看不到日志的。

目前看起来是猜测已经够多了只差验证了,我提供一个验证的思路:利用 BPF 技术追踪下 os.Exit 和 panic 调用,能够定位到底是因为哪一种方式导致程序退出的。