使用golang开发后端api,使用的是gin框架。上线之后需要用到权限控制,就得先把登录功能加上。 添加登录过程中,引入了gin的sessions间件 : https://github.com/
顺晟科技
2021-06-16 10:27:46
407
本文介绍了在基于杜松子酒框架开发的项目中如何配置并使用活力来接收并记录杜松子酒框架默认的日志和如何配置日志归档。
我们在基于杜松子酒框架开发项目时通常都会选择使用专业的日志库来记录项目中的日志,走语言常用的日志库有zap、logrus等。网上也有很多类似的教程,我之前也翻译过一篇《在Go语言项目中使用Zap日志库》 。
但是我们该如何在日志中记录杜松子酒框架本身输出的那些日志呢?
杜松子酒默认的中间件
首先我们来看一个最简单的杜松子酒项目:
func main() {
r :=杜松子酒。默认()
r.GET('/hello ',func(c *gin .上下文){
c.String('hello liwenzhou.com!')
})
r.运行(
}
接下来我们看一下杜松子酒。默认()的源码:
函数默认值()*引擎{
调试打印警告默认()
发动机:=新()
引擎。使用(记录器()、恢复())
返回引擎
}
也就是我们在使用杜松子酒。默认()的同时是用到了杜松子酒框架内的两个默认中间件记录器()和恢复().
其中记录器()是把杜松子酒框架本身的日志输出到标准输出(我们本地开发调试时在终端输出的那些日志就是它的功劳),而恢复()是在程序出现恐慌的时候恢复现场并写入500响应的。
基于活力的中间件
我们可以模仿记录器()和恢复()的实现,使用我们的日志库来接收杜松子酒框架默认输出的日志。
这里以活力为例,我们实现两个中间件如下:
//GinLogger接收杜松子酒框架默认的日志
func GinLogger(logger *zap .伐木工)杜松子酒HandlerFunc {
返回func(c *gin .上下文){
开始:=时间.现在()
路径:=c.Request.URL.Path
查询:=c.Request.URL.RawQuery
c.下一个()
成本:=时间。自(开始)
伐木工人。信息(路径,
zap .Int('status ',c.Writer.Status()),
zap .字符串('方法方法),
zap .字符串('路径,路径),
zap .字符串('查询',查询)、
zap .字符串(' ip ',c.ClientIP()),
zap .字符串('用户代理,c.Request.UserAgent()),
zap .字符串(“错误”,c.Errors.ByType(gin .ErrorTypePrivate).String()),
zap .持续时间('成本,成本),
)
}
}
//GinRecovery recover掉项目可能出现的恐慌
func GinRecovery(logger *zap .伐木工,栈bool) gin .HandlerFunc {
返回func(c *gin .上下文){
delay func(){
if err :=recover();呃!=零{
//检查断开的连接,因为它不是真正的
//保证紧急堆栈跟踪的条件。
var brokenPipe bool
如果ne,ok :=err .(* .net)操作错误);ok {
如果se,ok :=ne.Err.(*os .SysCallerror);ok {
如果是字符串。包含(字符串ToLower(se .Error()),' break pipe ')| | strings .包含(字符串ToLower(se .错误()),"连接被对等方重置"){
brokenPipe=true
}
}
}
httpRequest,_ :=httputil .转储请求(请求,假)
if brokenPipe {
伐木工人。错误(c.Request.URL.Path,
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
)
//如果连接死了,我们不能给它写状态。
c.错误(错误。(错误))//nolint: errcheck
c.中止()
返回
}
if stack {
伐木工人。错误('[从死机中恢复]',
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
zap .字符串('堆栈,字符串(调试. Stack())),
)
} else {
伐木工人。错误('[从死机中恢复]',
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
)
}
c.AbortWithStatus(http .StatusInternalServerError)
}
}()
c.下一个()
}
}
如果不想自己实现,可以使用开源代码库上有别人封装好的https://github.com/gin-contrib/zap。
这样我们就可以在杜松子酒框架中使用我们上面定义好的两个中间件来代替杜松子酒框架默认的记录器()和恢复()了。
r :=杜松子酒。新()
r.使用(GinLogger()、GinRecovery())
在杜松子酒项目中使用活力
最后我们再加入我们项目中常用的日志切割,完整版的logger.go代码如下:
包记录器
导入(
' gin_zap_demo/config '
"净"
' net/http '
' net/http/http putil '
" os "
"运行时/调试"
"字符串"
时间
github.com/gin-gonic/gin
github。内特芬奇/伐木工'
go.uber.org/zap
go.uber.org/zap/zapcore
)
var lg *zap .记录器
//InitLogger初始化记录器
func IntLogger(CFG * config .LogConfig()错误错误){
write syncer :=GetLogWriter(CFG .文件名,cfg .更大尺寸,cfg .MaxBackups,cfg .MaxAge)
编码器:=getEncoder()
var l=new(zapcore .级别)
err=l。解组文本([]字节(非洲法郎.级别))
如果出错!=零{
返回
}
core :=zapcore .新内核(编码器,写同步程序,l)
lg=zap .新(核心,zap .AddCaller())
zap .ReplaceGlobals(lg) //替换活力包中全局的记录器实例,后续在其他包中只需使用zap .l()调用即可
返回
}
func getEncoder() zapcore .编码器{
encoderConfig :=zap .NewProductionEncoderConfig()
encoderConfig .EncodeTime=zapcore .iso 8601时间编码器
encoderConfig .TimeKey='time '
encoderConfig .EncodeLevel=zapcore .大写水平编码器
encoderConfig .EncodeDuration=zapcore .SecondsDurationEncoder
encoderConfig .EncodeCaller=zapcore .ShortCallerEncoder
返回zapcore .新JSONEncoder(encoderConfig)
}
func getLogWriter(文件名字符串,maxSize,maxBackup,maxAge int) zapcore .WriteSyncer {
伐木工:=伐木工。记录器{
文件名:文件名,
更大尺寸:更大尺寸,
更大备份:更大备份,
更大年龄:更大年龄,
}
返回zapcore .添加同步(伐木工人记录器)
}
//GinLogger接收杜松子酒框架默认的日志
func GinLogger() gin .HandlerFunc {
返回func(c *gin .上下文){
开始:=时间.现在()
路径:=c.Request.URL.Path
查询:=c.Request.URL.RawQuery
c.下一个()
成本:=时间。自(开始)
lg .信息(路径,
zap .Int('status ',c.Writer.Status()),
zap .字符串('方法方法),
zap .字符串('路径,路径),
zap .字符串('查询',查询)、
zap .字符串(' ip ',c.ClientIP()),
zap .字符串('用户代理,c.Request.UserAgent()),
zap .字符串(“错误”,c.Errors.ByType(gin .ErrorTypePrivate).String()),
zap .持续时间('成本,成本),
)
}
}
//GinRecovery recover掉项目可能出现的恐慌,并使用活力记录相关日志
func GinRecovery(堆栈杜松子酒.HandlerFunc {
返回func(c *gin .上下文){
delay func(){
if err :=recover();呃!=零{
//检查断开的连接,因为它不是真正的
//保证紧急堆栈跟踪的条件。
var brokenPipe bool
如果ne,ok :=err .(* .net)操作错误);ok {
如果se,ok :=ne.Err.(*os .SysCallerror);ok {
如果是字符串。包含(字符串ToLower(se .Error()),' break pipe ')| | strings .包含(字符串ToLower(se .错误()),"连接被对等方重置"){
brokenPipe=true
}
}
}
httpRequest,_ :=httputil .转储请求(请求,假)
if brokenPipe {
lg .错误(c.Request.URL.Path,
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
)
//如果连接死了,我们不能给它写状态。
c.错误(错误。(错误))//nolint: errcheck
c.中止()
返回
}
if stack {
lg .错误('[从死机中恢复]',
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
zap .字符串('堆栈,字符串(调试. Stack())),
)
} else {
lg .错误('[从死机中恢复]',
zap .任何('错误,错误),
zap .字符串('请求,字符串(httpRequest)),
)
}
c.AbortWithStatus(http .StatusInternalServerError)
}
}()
c.下一个()
}
}
然后定义日志相关配置:
类型LogConfig结构{
级别字符串" json: "级别
文件名字符串" json: "文件名
MaxSize int `json: ' maxsize ' `
MaxAge int `json: ' max _ age ' '
max BAckUPs int ` js : ' max _ BAckUPs ' `
}
在项目中先从配置文件加载配置信息,再调用伐木工人InitLogger(配置Conf .LogConfig)即可完成记录器实例的初识化。其中,通过使用记录器GinLogger(),Logger .GinRecovery(true))注册我们的中间件来使用活力接收杜松子酒框架自身的日志,在项目中需要的地方通过使用zap .l().Xxx()方法来记录自定义日志信息。
包装总管
导入(
" fmt "
' gin_zap_demo/config '
' gin_zap_demo/logger '
' net/http '
" os "
go.uber.org/zap
github.com/gin-gonic/gin
)
func main() {
//从config.json加载配置
if len(os .Args) 1
返回
}
如果err :=config .初始化(os .args[1]);呃!=零{
恐慌(错误)
}
//初始化记录器
if err :=logger .InitLogger(配置conf .LogConfig);呃!=零{
fmt .Printf('init logger失败,err:%v\n ',错误)
返回
}
杜松子酒SetMode(配置。会议模式)
r :=杜松子酒。默认()
//注册活力相关中间件
r.使用(记录器GinLogger(),Logger .GinRecovery(true))
r.GET('/hello ',func(c *gin .上下文){
//假设你有一些数据需要记录到日志中
var(
名称='q1mi '
年龄=18岁
)
//记录日志并使用zap .Xxx(键,val)记录相关字段
zap .l().调试('这是你好,福克.字符串('用户',名称),zap .Int('age ',age))
c.字符串(http .“StatusOK,”你好李文洲。“com!”)
})
addr :=fmt .Sprintf(':%v),配置。配置端口)
r.运行(地址)
}
28
2021-08
28
2021-08
28
2021-08
28
2021-08
28
2021-08
28
2021-08