// Package middleware ... // // Description : middleware ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2022-07-14 10:53 package middleware import ( "git.zhangdeman.cn/zhangdeman/wrapper" "strings" "git.zhangdeman.cn/zhangdeman/gin/define" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // Access 记录请求日志 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:55 2022/7/14 func Access(cfg *AccessConfig) gin.HandlerFunc { // 未传入配置或者未传入日志实例 if nil == cfg || nil == cfg.Logger { return func(ctx *gin.Context) { ctx.Next() } } if nil == cfg.IsRecordLog { cfg.IsRecordLog = defaultIsRecordLog } if nil == cfg.ExtraFieldList { cfg.ExtraFieldList = make([]string, 0) } cfg.ExtraFieldList = append(cfg.ExtraFieldList, define.RecordRequestDataField, define.RecordResponseDataField) return func(ctx *gin.Context) { ctx.Next() if !cfg.IsRecordLog(ctx) { // 不记录日志 return } startRequestTime := wrapper.OwnTime(ctx.GetTime(define.StartRequestTimeField)) logDataList := []zap.Field{ // 开始请求时间 zap.Any(define.StartRequestTimeField, startRequestTime.FormatUnixMilli()), } // 结束时间 finishRequestTime := wrapper.OwnTime(ctx.GetTime(define.FinishRequestTimeField)) logDataList = append( logDataList, zap.Any(define.FinishRequestTimeField, startRequestTime.FormatUnixMilli()), zap.Int64("pkg_gin_request_cost", finishRequestTime.UnixMilli()-startRequestTime.UnixMilli()), ) // 请求header if len(cfg.RequestHeaderList) == 0 { // 全部记录 zap.Any("pkg_gin_request_header", ctx.Request.Header) } else { headerTable := make(map[string][]string, 0) for _, key := range cfg.RequestHeaderList { headerTable[key] = ctx.Request.Header.Values(key) } zap.Any("pkg_gin_request_header", headerTable) } // 响应header if len(cfg.ResponseHeaderList) == 0 { // 全部记录 zap.Any("pkg_gin_response_header", ctx.Writer.Header()) } else { headerTable := make(map[string][]string, 0) for _, key := range cfg.ResponseHeaderList { headerTable[key] = ctx.Writer.Header().Values(key) } zap.Any("pkg_gin_response_header", headerTable) } // 扩展数据 for _, field := range cfg.ExtraFieldList { val, _ := ctx.Get(field) logDataList = append(logDataList, zap.Any(field, val)) } cfg.Logger.Info("请求日志记录", logDataList...) if nil != cfg.FinishHook { // hook 不为nil, 自动触发 cfg.FinishHook( ctx, []byte(ctx.GetString(define.RecordRequestDataField)), []byte(ctx.GetString(define.RecordResponseDataField)), finishRequestTime.UnixMilli()-startRequestTime.UnixMilli(), ) } } } // AccessConfig 访问记录的配置 // // Author : go_developer@163.com<白茶清欢> // // Date : 11:26 2022/7/14 type AccessConfig struct { Logger *zap.Logger // 日志实例 RequestHeaderList []string // 要记录哪些header , 不传全部记录 ResponseHeaderList []string // 要记录哪些响应header, 不传全部记录 IsRecordLog func(ctx *gin.Context) bool // 验证当前请求是否记录日志 ExtraFieldList []string // 记录的扩展字段列表,请将相关数据使用 ctx.Set 写入上下文中, 日志会自动记录 FinishHook func(ctx *gin.Context, requestData []byte, responseData []byte, cost int64) // 请求处理完成之后, 触发的hook函数 } // defaultIsRecordLog 默认仅记录 json api 日志 // // Author : go_developer@163.com<白茶清欢> // // Date : 11:31 2022/7/14 func defaultIsRecordLog(ctx *gin.Context) bool { if strings.Contains(ctx.Writer.Header().Get("Content-type"), "application/json") { return true } return false }