这篇文章比较硬核,会涉及到这几个知识点:协程、协程池、钩子函数、中间件以及异步方法的使用,文章最后会带大家去阅读Async的源码,了解其底层实现。
应用场景
管理后台需要记录登录用户的各种操作日志,便于出现问题时追溯管理员做了哪些操作。
同时我们也需要记录每次的请求日志到log文件中,供开发人员定位问题。
我们需要考虑哪些问题呢?
注意问题
- 首先需要全局添加操作日志的记录,即用户登录后的各种操作都要记录
- 日志记录的操作应该尽量避免对主程序的影响,不能因为记录日志而浪费性能
- 要记录的数据应该定义好规则,统一管理、统一入参。
先说结论
我们会用到以下知识点,来实现上面的场景,解决上面提到的注意问题:
group.Hook()
和HookAfterOutput
在全局添加日志记录的入口- 使用中间件实现字段的统一管理、统一入参
- 使用Go的协程机制提高记录日志的效率,并发执行,存入DB,供管理后台查看使用(在这里我们使用GoFrame的grpool更好的管理协程)
- 使用
g.Log()
的Async()
特性异步保存请求日志到文件,方便我们技术人员查错使用。
实现流程
前言
下面的示例代码基于GoFrame 1.16版本实现,在这里不再赘述项目初始化等基础问题,感兴趣的同学可以查看这篇文章:GoFrame入门实践,里面介绍了GoFrame的特点,以及我按照官方文档学习踩得一些坑。
为了方便大家看懂逻辑,不重要的代码用使用三个竖着的.省略;GoFrame框架在下文简称gf框架。
路由文件
- 我们定义了
ApiLog
的中间件,在业务路由方法之前调用 - 我们定义了
log()
函数,其中应用到了gf框架路由的钩子函数group.Hook
,用于在接口返回业务数据之后记录操作日志。 log()
函数的位置在登录路由之后,业务逻辑路由之前。
package app
func Run() {
s := g.Server()
s.Use(middleware.Cors.CORS)
s.Use(middleware.Logs.ApiLog)
//AKSK换取token
account.Token()
//账号登录
account.Login()
//操作日志
log(s)
admin.Init(s)
.
.
.
s.Run()
}
func log(s *ghttp.Server) {
s.Group("/", func(group *ghttp.RouterGroup) {
group.Hoo