127 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package middleware ...
 | 
						|
//
 | 
						|
// Description : middleware ...
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 2022-07-14 10:53
 | 
						|
package middleware
 | 
						|
 | 
						|
import (
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"git.zhangdeman.cn/zhangdeman/gin/request/parse_body"
 | 
						|
	"git.zhangdeman.cn/zhangdeman/gin/util"
 | 
						|
 | 
						|
	"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 填充默认配置
 | 
						|
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
 | 
						|
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
 | 
						|
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 记录请求日志
 | 
						|
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)
 | 
						|
		// 记录请求日志
 | 
						|
		data := map[string]any{
 | 
						|
			handleConfig.StartRequestTimeField: startRequestTime,                      // 开始请求时间
 | 
						|
			"request_header":                   getLogRequestHeader(ctx, cfg),         // 请求header
 | 
						|
			"request_query":                    request.WrapperHandle.ParseQuery(ctx), // 获取请求query
 | 
						|
			"request_body":                     map[string]any{},                      // 请求body
 | 
						|
		}
 | 
						|
		data["request_body"], _ = parse_body.ExecuteForMap(ctx)
 | 
						|
		logData := logger.NewLogData(util.GinCtxToContext(ctx), consts.LogTypeRequest, "", data)
 | 
						|
		cfg.Logger.Info("接口请求日志记录", logData.ToFieldList()...)
 | 
						|
		ctx.Next()
 | 
						|
		// 结束时间
 | 
						|
		finishRequestTime := request.WrapperHandle.GetCtxIntData(ctx, handleConfig.FinishRequestTimeField, 0)
 | 
						|
		ctx.Set(handleConfig.FinishRequestTimeField, finishRequestTime)
 | 
						|
		// 记录相应日志
 | 
						|
		logResponseData := logger.NewLogData(util.GinCtxToContext(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("接口响应日志记录", logResponseData.ToFieldList()...)
 | 
						|
		} else {
 | 
						|
			cfg.Logger.Error("接口响应日志记录", logResponseData.ToFieldList()...)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// AccessConfig 访问记录的配置
 | 
						|
type AccessConfig struct {
 | 
						|
	Logger             *zap.Logger                 // 日志实例
 | 
						|
	RequestHeaderList  []string                    // 要记录哪些header , 不传全部记录
 | 
						|
	ResponseHeaderList []string                    // 要记录哪些响应header, 不传全部记录
 | 
						|
	IsRecordLog        func(ctx *gin.Context) bool // 验证当前请求是否记录日志
 | 
						|
}
 | 
						|
 | 
						|
// defaultIsRecordLog 默认仅记录 json api 日志
 | 
						|
func defaultIsRecordLog(ctx *gin.Context) bool {
 | 
						|
	return strings.Contains(ctx.Writer.Header().Get(consts.HeaderKeyContentType.String()), "application/json")
 | 
						|
}
 |