Golang 并发下的问题定位及解决方案


Posted in Golang onMarch 16, 2022

问题描述

在使用 gin-swagger 的过程中, 经常会发生因为缺少 jsontag 而导致的异常。 由于 gin-swagger 是并发执行的, 输出的日志本身是错位的。 这就导致无法定义是哪一个结构体缺少 tag 导致的。

Golang 并发下的问题定位及解决方案

一般而言, 这种时候只能一个个点开去检查。

解决方案

思路 : 要是每行日志带当前 goroutine_id 的话, 是不是就可以准确定位到报错的 goroutine 他打印的日志是哪些了呢!

说做就做

实现思路

  • 查看当前日志是怎么打印的

发现 gin-swagger 日志直接调用的 golang 的标准库 log

由于没有对log初始化, 所以默认使用的是 stdout

log.Printf("Picking operation from %s\n", aurora.Blue(funType.FullName()))
  • 如果想要给日志中添加 goroutine_id 的话, 就需要在调用 log.Printf 的时候获取当前 goroutine 的 id , 所以首先要解决的是怎么获取 goroutine_id 的问题。

调研后发现了集中常见的获取 goroutine_id 的方法:

2.1 通过栈信息解析后获取

func GetGID() uint64 {
    b := make([]byte, 64)
    b = b[:runtime.Stack(b, false)]
    b = bytes.TrimPrefix(b, []byte("goroutine "))
    b = b[:bytes.IndexByte(b, ' ')]
    n, _ := strconv.ParseUint(string(b), 10, 64)
    return n
}

2.2 修改 Go 源码获取

# src/runtime/runtime2.go
func Goid() int64 {
    _g_ := getg()
    return _g_.goid
}

2.3 通过 CGO 获取

文件 id.c

#include "runtime.h"
int64 ·Id(void) {
    return g->goid;
}

文件 id.go

package id
func Id() int64

另外还可以通过汇编获取 goroutine_id

由于go的版本不同,goroutine的结构也可能不同, 所以此处我直接调用一个开源实现:

https://github.com/petermattis/goid

  • 修改 gin-swagger main.go 源码, 修改 log Write 的实现

修改前

func main() {
    cmd.Execute()
}

修改后

type Out os.File
func (o Out) Write(b []byte) (int, error) {
    prefix := fmt.Sprintf("gid-%d: ", goid.Get())
    all := make([]byte, len(b)+len(prefix))
    all = []byte(prefix)
    all = append(all, b...)
    f := os.File(o)
    return f.Write(all)
}
func main() {
    var out Out
    out = Out(os.Stdout)
    log.SetOutput(out)
    cmd.Execute()

这样修改后,每次 gin-swagger 调用 log 打印日志都时候, 都会使用我定义的 Write 方法, Write 方法中每次打印前都会先查询出当前的 goroutine_id ,然后作为日志的前缀。

修改后的日志效果

Golang 并发下的问题定位及解决方案

从中可以看到每行日志开头,都已经加上了 goroutine_id。 只要使用 panic goroutineid 做一次 grep , 即可筛选出需要的日志了,极大的方便了定位问题。

Golang 并发下的问题定位及解决方案

cat /tmp/gin-swagger.log | grep 7647

Golang 并发下的问题定位及解决方案

到此这篇关于Golang 并发下的问题定位的文章就介绍到这了,更多相关Golang并发问题内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
go语言-在mac下brew升级golang
Apr 25 Golang
go语言求任意类型切片的长度操作
Apr 26 Golang
Go语言中的UTF-8实现
Apr 26 Golang
goland 清除所有的默认设置操作
Apr 28 Golang
golang 实现菜单树的生成方式
Apr 28 Golang
golang 生成对应的数据表struct定义操作
Apr 28 Golang
golang 比较浮点数的大小方式
May 02 Golang
浅谈golang 中time.After释放的问题
May 05 Golang
解决golang 关于全局变量的坑
May 06 Golang
Go Plugins插件的实现方式
Aug 07 Golang
Golang使用Panic与Recover进行错误捕获
Mar 22 Golang
基于Python实现西西成语接龙小助手
Aug 05 Golang
如何利用golang运用mysql数据库
深入理解go缓存库freecache的使用
Feb 15 #Golang
Go语言读取txt文档的操作方法
Jan 22 #Golang
一文搞懂Golang 时间和日期相关函数
Go语言基础切片的创建及初始化示例详解
Nov 17 #Golang
Go语言基础map用法及示例详解
Nov 17 #Golang
Go语言基础函数基本用法及示例详解
Nov 17 #Golang
You might like
用函数读出数据表内容放入二维数组
2006/10/09 PHP
php 数组元素快速去重
2017/05/05 PHP
ThinkPHP5.1的权限控制怎么写?分享一个AUTH权限控制
2021/03/09 PHP
jquery UI 1.72 之datepicker
2009/12/29 Javascript
基于jQuery的弹出警告对话框美化插件(警告,确认和提示)
2010/06/10 Javascript
js 弹出菜单/窗口效果
2011/10/30 Javascript
AngularJS中取消对HTML片段转义的方法例子
2015/01/04 Javascript
JavaScript中的toDateString()方法使用详解
2015/06/12 Javascript
基于javascript实现listbox左右移动
2016/01/29 Javascript
JS中script标签defer和async属性的区别详解
2016/08/12 Javascript
微信小程序网络请求wx.request详解及实例
2017/05/18 Javascript
MvcPager分页控件 适用于Bootstrap
2017/06/03 Javascript
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
vue.js实现标签页切换效果
2018/06/07 Javascript
Redux实现组合计数器的示例代码
2018/07/04 Javascript
ES6 Promise对象的含义和基本用法分析
2019/06/14 Javascript
vue 源码解析之虚拟Dom-render
2019/08/26 Javascript
转换layUI的数据表格中的日期格式方法
2019/09/19 Javascript
JavaScript实现网页跨年倒计时
2020/12/02 Javascript
python3大文件解压和基本操作
2017/12/15 Python
django mysql数据库及图片上传接口详解
2019/07/18 Python
世界上最大的各式箱包网络零售店:eBag
2016/07/21 全球购物
Canon佳能美国官方商店:购买数码相机、数码单反相机、镜头和打印机
2016/11/15 全球购物
ALDO美国官网:加拿大女鞋品牌
2018/12/28 全球购物
LACOSTE波兰官网:Polo衫、服装和鞋类
2020/09/29 全球购物
《自选商场》教学反思
2014/02/14 职场文书
企业指导教师评语
2014/04/28 职场文书
医疗器械售后服务承诺书
2014/05/21 职场文书
关于读书的演讲稿500字
2014/08/27 职场文书
专题组织生活会发言材料
2014/10/17 职场文书
2014年信息宣传工作总结
2014/12/18 职场文书
六五普法心得体会2016
2016/01/21 职场文书
预备党员入党思想汇报(范文)
2019/08/14 职场文书
HTML中的表单Form实现居中效果
2021/05/25 HTML / CSS
用Python创建简易网站图文教程
2021/06/11 Python
Go gRPC进阶教程gRPC转换HTTP
2022/06/16 Golang