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:垃圾回收GC触发条件详解
Apr 24 Golang
golang在GRPC中设置client的超时时间
Apr 27 Golang
go语言中json数据的读取和写出操作
Apr 28 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
golang switch语句的灵活写法介绍
May 06 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Go语言基础函数基本用法及示例详解
Nov 17 Golang
golang用type-switch判断interface的实际存储类型
Apr 14 Golang
Golang 链表的学习和使用
Apr 19 Golang
详解Go语言中配置文件使用与日志配置
Jun 01 Golang
Go gRPC进阶教程gRPC转换HTTP
Jun 16 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微信刮刮卡 附微信接口
2016/07/22 PHP
一实用的实现table排序的Javascript类库
2007/09/12 Javascript
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
ASP.NET中使用后端代码注册脚本 生成JQUERY-EASYUI的界面错位的解决方法
2010/06/12 Javascript
jquery选择器的选择使用及性能介绍
2013/01/16 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
JS是按值传递还是按引用传递
2015/01/30 Javascript
JavaScript中原型和原型链详解
2015/02/11 Javascript
浅谈jQuery中replace()方法
2015/05/13 Javascript
javascript实现动态改变层大小的方法
2015/05/14 Javascript
详解JS对象封装的常用方式
2016/12/30 Javascript
深入理解Webpack 中路径的配置
2017/06/17 Javascript
javascript数组定义的几种方法
2017/10/06 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
2019/04/10 Javascript
ES6知识点整理之函数数组参数的默认值及其解构应用示例
2019/04/17 Javascript
JS前端知识点 运算符优先级,URL编码与解码,String,Math,arguments操作整理总结
2019/06/27 Javascript
javascript 高级语法之继承的基本使用方法示例
2019/11/11 Javascript
微信小程序分享小程序码的生成(带参数)以及参数的获取
2020/03/25 Javascript
在Vue中使用mockjs代码实例
2020/11/25 Vue.js
通过实例解析js可枚举属性与不可枚举属性
2020/12/02 Javascript
理解Python垃圾回收机制
2016/02/12 Python
Python学习之Django的管理界面代码示例
2018/02/10 Python
python实现傅里叶级数展开的实现
2018/07/21 Python
在ubuntu16.04中将python3设置为默认的命令写法
2018/10/31 Python
利用python实现汉字转拼音的2种方法
2019/08/12 Python
3行Python代码实现图像照片抠图和换底色的方法
2019/10/10 Python
python 实现矩阵填充0的例子
2019/11/29 Python
Python中的流程控制详解
2021/02/18 Python
解释一下ruby中的特殊方法与特殊类
2013/02/26 面试题
出纳岗位职责模板
2013/11/27 职场文书
销售人员自我评价
2014/02/01 职场文书
小学生国旗下演讲稿
2014/04/25 职场文书
教育实践活动对照检查材料
2014/09/23 职场文书
2015年简历自我评价范文
2015/03/11 职场文书
新郎父母婚礼答谢词
2015/09/29 职场文书
mysql查看表结构的三种方法总结
2022/07/07 MySQL