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 相关文章推荐
解决Golang中goroutine执行速度的问题
May 02 Golang
使用golang编写一个并发工作队列
May 08 Golang
关于golang高并发的实现与注意事项说明
May 08 Golang
go语言基础 seek光标位置os包的使用
May 09 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
go select编译期的优化处理逻辑使用场景分析
Jun 28 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
Go语言读取txt文档的操作方法
Jan 22 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
Golang Elasticsearches 批量修改查询及发送MQ
Apr 19 Golang
Go语言编译原理之变量捕获
Aug 05 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
PHP新手上路(十三)
2006/10/09 PHP
一个显示某段时间内每个月的方法 返回由这些月份组成的数组
2012/05/16 PHP
apache+codeigniter 通过.htcaccess做动态二级域名解析
2012/07/01 PHP
thinkPHP分组后模板无法加载问题解决方法
2016/07/12 PHP
PHP CURL post数据报错 failed creating formpost data
2016/10/16 PHP
php执行多个存储过程的方法【基于thinkPHP】
2016/11/08 PHP
LBS blog sql注射漏洞[All version]-官方已有补丁
2007/08/26 Javascript
13个绚丽的Jquery 界面设计网站推荐
2010/09/28 Javascript
JS修改地址栏参数实例代码
2016/06/14 Javascript
Node.js利用js-xlsx处理Excel文件的方法详解
2017/07/05 Javascript
VUE2实现事件驱动弹窗示例
2017/10/21 Javascript
Vue-cli 使用json server在本地模拟请求数据的示例代码
2017/11/02 Javascript
Vue 按键修饰符处理事件的方法
2018/05/04 Javascript
JavaScript实现一个简易的计算器实例代码
2018/05/10 Javascript
微信小程序自定义tab实现多层tab嵌套功能
2018/06/15 Javascript
详解微信小程序-扫一扫 wx.scanCode() 扫码大变身
2019/04/30 Javascript
vue中使用GraphQL的实例代码
2019/11/04 Javascript
Nuxt配置Element-UI按需引入的操作方法
2020/07/06 Javascript
[03:49]DOTA2英雄基础教程 光之守卫
2014/01/14 DOTA
详解设计模式中的工厂方法模式在Python程序中的运用
2016/03/02 Python
Django使用httpresponse返回用户头像实例代码
2018/01/26 Python
selenium+python 去除启动的黑色cmd窗口方法
2018/05/22 Python
Django框架安装方法图文详解
2019/11/04 Python
python文字转语音的实例代码分析
2019/11/12 Python
基于Keras 循环训练模型跑数据时内存泄漏的解决方式
2020/06/11 Python
解决tensorflow读取本地MNITS_data失败的原因
2020/06/22 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
在数据文件自动增长时,自动增长是否会阻塞对文件的更新
2014/05/01 面试题
女大学生个人求职信
2013/12/09 职场文书
七一建党日演讲稿
2014/09/05 职场文书
试用期员工工作自我评价
2014/09/10 职场文书
音乐会主持人开场白
2015/05/28 职场文书
Python使用sql语句对mysql数据库多条件模糊查询的思路详解
2021/04/12 Python
python 机器学习的标准化、归一化、正则化、离散化和白化
2021/04/16 Python
Java并发编程之详解CyclicBarrier线程同步
2021/06/23 Java/Android
Python中基础数据类型 set集合知识点总结
2021/08/02 Python