// Package middleware ... // // Description : middleware ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2022-07-14 10:53 package middleware import ( "strings" "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/gin/request" "go.uber.org/zap" "git.zhangdeman.cn/zhangdeman/gin/define" "git.zhangdeman.cn/zhangdeman/logger" "github.com/gin-gonic/gin" ) // fillCfg 填充默认配置 // // Author : go_developer@163.com<白茶清欢> // // Date : 15:37 2023/12/29 func fillCfg(cfg *AccessConfig) { if nil == cfg { return } if nil == cfg.IsRecordLog { cfg.IsRecordLog = defaultIsRecordLog } if nil == cfg.RequestHeaderList { cfg.RequestHeaderList = make([]string, 0) } if nil == cfg.ResponseHeaderList { cfg.ResponseHeaderList = make([]string, 0) } } // getLogRequestHeader 获取记录的请求header // // Author : go_developer@163.com<白茶清欢> // // Date : 15:59 2023/12/29 func getLogRequestHeader(ctx *gin.Context, cfg *AccessConfig) map[string][]string { // 请求header headerTable := make(map[string][]string) if len(cfg.RequestHeaderList) == 0 { // 全部记录 for headerKey := range ctx.Request.Header { cfg.RequestHeaderList = append(cfg.RequestHeaderList, headerKey) } } for _, key := range cfg.RequestHeaderList { headerTable[key] = ctx.Request.Header.Values(key) } return headerTable } // getLogResponseHeader 记录相应header // // Author : go_developer@163.com<白茶清欢> // // Date : 16:01 2023/12/29 func getLogResponseHeader(ctx *gin.Context, cfg *AccessConfig) map[string][]string { // 响应header responseHeaderTable := make(map[string][]string) if len(cfg.ResponseHeaderList) == 0 { // 全部记录 for headerKey := range ctx.Writer.Header() { cfg.ResponseHeaderList = append(cfg.ResponseHeaderList, headerKey) } zap.Any("pkg_gin_response_header", ctx.Writer.Header()) } for _, key := range cfg.ResponseHeaderList { responseHeaderTable[key] = ctx.Writer.Header().Values(key) } return responseHeaderTable } // LogRequest 记录请求日志 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:55 2022/7/14 func LogRequest(cfg *AccessConfig) gin.HandlerFunc { fillCfg(cfg) handleConfig := define.GetHttpHandleConfig() return func(ctx *gin.Context) { // 未传入配置或者未传入日志实例 if nil == cfg || nil == cfg.Logger || (nil != cfg.IsRecordLog && !cfg.IsRecordLog(ctx)) { ctx.Next() return } startRequestTime := request.WrapperHandle.GetCtxIntData(ctx, handleConfig.StartRequestTimeField, 0) // 记录请求日志 logData := logger.NewLogData(ctx, consts.LogTypeRequest, "", map[string]any{ handleConfig.StartRequestTimeField: startRequestTime, // 开始请求时间 "request_header": getLogRequestHeader(ctx, cfg), // 请求header "request_query": request.WrapperHandle.ParseQuery(ctx), // 获取请求query "request_body": request.WrapperHandle.ParseBody(ctx), // 请求body }) cfg.Logger.Info("接口请求日志记录", logger.ZapLogDataList(logData)...) ctx.Next() // 结束时间 finishRequestTime := request.WrapperHandle.GetCtxIntData(ctx, handleConfig.FinishRequestTimeField, 0) ctx.Set(handleConfig.FinishRequestTimeField, finishRequestTime) // 记录相应日志 logResponseData := logger.NewLogData(ctx, consts.LogTypeOutput, "", map[string]any{ handleConfig.FinishRequestTimeField: finishRequestTime, // 完成请求时间 "request_cost": finishRequestTime - startRequestTime, // 请求耗时 "response_body": request.WrapperHandle.GetResponseBody(ctx, handleConfig.ResponseDataField, map[string]any{}), // 响应body "response_header": getLogResponseHeader(ctx, cfg), // 响应header }) if ctx.GetBool(define.GetHttpHandleConfig().RequestIsSuccessField) { cfg.Logger.Info("接口响应日志记录", logger.ZapLogDataList(logResponseData)...) } else { cfg.Logger.Error("接口响应日志记录", logger.ZapLogDataList(logResponseData)...) } } } // 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 // 验证当前请求是否记录日志 } // 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 }