gin/middleware/access_log.go

125 lines
4.0 KiB
Go

// 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
}