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项目中使用init()
Apr 12 Golang
Golang 实现超大文件读取的两种方法
Apr 27 Golang
go语言中fallthrough的用法说明
May 06 Golang
go mod 安装依赖 unkown revision问题的解决方案
May 06 Golang
go语言中http超时引发的事故解决
Jun 02 Golang
修改并编译golang源码的操作步骤
Jul 25 Golang
go使用Gin框架利用阿里云实现短信验证码功能
Aug 04 Golang
golang为什么要统一错误处理
Apr 03 Golang
Go归并排序算法的实现方法
Apr 06 Golang
Golang获取List列表元素的四种方式
Apr 20 Golang
Golang 并发编程 SingleFlight模式
Apr 26 Golang
Golang入门之计时器
May 04 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
require(),include(),require_once()和include_once()区别
2008/03/27 PHP
CI框架(CodeIgniter)实现的数据库增删改查操作总结
2018/05/23 PHP
CI框架附属类用法分析
2018/12/26 PHP
PHP设计模式之PHP迭代器模式讲解
2019/03/22 PHP
PHP实现单例模式建立数据库连接的方法分析
2020/02/11 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
2021/03/09 PHP
JavaScript Array扩展实现代码
2009/10/14 Javascript
getElementByIdx_x js自定义getElementById函数
2012/01/24 Javascript
jQuery实现购物车数字加减效果
2015/03/14 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
2016/10/11 Javascript
jQuery+ajax的资源回收处理机制分析
2017/01/07 Javascript
javascript编程实现栈的方法详解【经典数据结构】
2017/04/11 Javascript
jQuery实现简单的回到顶部totop功能示例
2017/10/16 jQuery
jQuery中的for循环var与let的区别
2018/04/21 jQuery
详解Angular如何正确的操作DOM
2018/07/06 Javascript
javascript实现放大镜功能
2020/12/09 Javascript
python网络编程学习笔记(四):域名系统
2014/06/09 Python
Python采集腾讯新闻实例
2014/07/10 Python
在ironpython中利用装饰器执行SQL操作的例子
2015/05/02 Python
PyQt实现界面翻转切换效果
2018/04/20 Python
如何优雅地处理Django中的favicon.ico图标详解
2018/07/05 Python
完美解决Python matplotlib绘图时汉字显示不正常的问题
2019/01/29 Python
pymongo中聚合查询的使用方法
2019/03/22 Python
Python Tkinter 简单登录界面的实现
2019/06/14 Python
Django调用支付宝接口代码实例详解
2020/04/04 Python
python读取hdfs并返回dataframe教程
2020/06/05 Python
Python基于wordcloud及jieba实现中国地图词云图
2020/06/09 Python
python动态规划算法实例详解
2020/11/22 Python
python爬虫爬取某网站视频的示例代码
2021/02/20 Python
Andrew Marc官网:设计师外套的领先制造商
2019/10/30 全球购物
几个数据库方面的面试题
2016/07/01 面试题
网络编程中设计并发服务器,使用多进程与多线程,请问有什么区别?
2016/03/27 面试题
大学生就业推荐信范文
2013/11/29 职场文书
城市轨道交通工程职业规划书范文
2014/01/18 职场文书
表扬稿范文
2015/01/17 职场文书
python语言中pandas字符串分割str.split()函数
2022/08/05 Python