工作中遇到的gin和gorm的两个问题记录

2019年3月31日 338点热度 0人点赞 0条评论

图片

Gin 中间件没有使用next会是什么反应?

周末老王提了一个问题,如果Gin中间件里面如果我忘记写context.Next了会有什么结果呢?

我第一个反应是直接不会执行后面的handler了呗。我印象中gin的middleware也是个handler,然后维护一个handler链条,使用next进行调用传递。

事实证明我错了,如果某个middleware里面忘记写c.Next(), 那么它还是会进行后续调用的。只是不会再回到这个middleware中了。

这块代码又加深了一些理解:

1func (c *Context) Next() {
2    c.index++
3    for s := int8(len(c.handlers)); c.index < s; c.index++ {
4        c.handlers[c.index](c)
5    }
6}

每个请求进来的时候,都已经创建了c.handlers数组,当第一个Next函数启动的时候,会进入到这里的for循环,在这个循环中,默认就是会调用所有的handler的。所以这里就回答了之前的问题,如果没有写next的话,就顺势进入到下一个排序的handler。

如果调用了Next的话呢,实际上就不会调度for循环里面的c.index++了,就进入了第一行的c.index++,并且调用下一个handler,由下一个handler里面的next进入第一行的c.index++。

这个设计确实有点反直觉。

但是看了这个帖子 https://github.com/gin-gonic/gin/issues/287 也就释然了,在设计上,c.Next其实不是必要的,它存在的必要性就是为了能执行Next函数后面的代码而已。所以我们把c.Next放在中间件的最后其实和不写它是一样一样的...

如何给Gorm 每个sql请求日志增加一个上下文的traceId

我的需求是一个请求用一个traceId进行串下来,不管是sql日志,还是请求日志。

这个想了老久了,最后结论:做不到。

原因是啥?gorm是启动的时候就创建连接,然后每个请求进来的时候,去连接池获取连接,进行请求。它的实体在启动的时候就创建好了。但是,在具体记录日志的时候,它的logger接口里面没有带上context,导致上下文丢失。

关键的代码在jinzhu/gorm/logger.go

 1type LogWriter interface {
2    Println(v ...interface{})
3}
4// Logger default logger
5type Logger struct {
6    LogWriter
7}
8
9// Print format & print log
10func (logger Logger) Print(values ...interface{}) {
11    logger.Println(LogFormatter(values...)...)
12}

这里的LogWriter并没有使用上下文。我们即使定义自己的logger实现了LogWriter,也无处往这个Writer里面塞traceId.

这个可能也只是由于gorm创建的时候还没有到go1.7。貌似又很多人也发现这个问题,希望gorm加上context: https://github.com/jinzhu/gorm/issues/1231 。但是至少,到现在为止现在还未加上去。

后来脑洞了一下,可能还有一种做法,https://github.com/huandu/go-tls 。把context存储在goroutine作用域存储里面,然后创建一个自定义的Logger,在Print的时候,去这个goroutine作用域存储里面获取context。

但是这个“创建goroutine作用域存储”本身就是golang官网不提倡的。这就是和获取goroutine唯一id一样的做法,tls也是使用了依赖具体golang版本实现的获取goroutine结构字段的方法,换句话说,一旦golang在某个版本修改了goroutine的内部结构,可能go-tls就失效了。

当然还有另外一种办法,就是你自己在每次sql请求之后自己使用logger记录一下sql请求和结果。不过过于丑陋了。

最终作罢。。。

图片

图片

Hi,我是轩脉刃,一个名不见经传码农,体制内的小愤青,躁动的骚年,2019年想坚持写一些学习/工作/思考笔记,谓之倒逼学习。欢迎关注个人公众号:轩脉刃的刀光剑影。


MORE | 更多原创文章


 gin框架使用注意事项

② 测试用例是开发人员最后一块遮羞布

③ mariaDB vs mysql的区别

④ 一次composer错误使用引发的思考

⑤ colly源码学习

⑥ 使用chan的时候选择对象还是指针

36040工作中遇到的gin和gorm的两个问题记录

这个人很懒,什么都没留下

文章评论