Files
zap_logger/plugins/gin.go
2025-11-27 10:29:16 +08:00

160 lines
3.7 KiB
Go

package plugins
import (
"encoding/json"
"regexp"
"slices"
"strconv"
"strings"
"time"
"code.mrx.ltd/pkg/zap_logger/log"
"github.com/gin-gonic/gin"
"go.uber.org/zap/zapcore"
)
type LogParam struct {
Time string
Method string
Path string
StatusCode int
ClientIP string
UserAgent string
Latency string
Header string
Errors []string
}
type FormatFunc func(logParam LogParam) string
type Skipper func(c *gin.Context) bool
var defaultConfig = &GinLogConfig{
TimeFormat: "2006-01-02 15:04:05.000",
SkipPaths: nil,
SkipPathRegexps: nil,
DefaultLevel: zapcore.InfoLevel,
Skipper: nil,
FormatFunc: defaultFormatFunc,
HideKeys: []string{"header"},
}
var defaultFormatFunc FormatFunc = func(logParam LogParam) string {
builder := strings.Builder{}
builder.WriteString("[GIN] ")
builder.WriteString("[" + logParam.Time + "]")
builder.WriteString(" ")
builder.WriteString("[" + strconv.Itoa(logParam.StatusCode) + "]")
builder.WriteString(" ")
builder.WriteString("[" + logParam.Latency + "]")
builder.WriteString(" ")
builder.WriteString("[" + logParam.ClientIP + "]")
builder.WriteString(" ")
builder.WriteString("[" + logParam.Method + "]")
builder.WriteString(" ")
builder.WriteString("[" + logParam.Path + "]")
builder.WriteString(" ")
builder.WriteString("[" + logParam.UserAgent + "]")
if len(logParam.Errors) > 0 {
builder.WriteString(" | [Errors] -> ")
for _, err := range logParam.Errors {
builder.WriteString(" [" + err + "]")
}
}
return builder.String()
}
type GinLogConfig struct {
TimeFormat string // custom time format default: 2006-01-02 15:04:05.000
SkipPaths []string // skip path
SkipPathRegexps []*regexp.Regexp
DefaultLevel zapcore.Level
Skipper Skipper
FormatFunc FormatFunc
HideKeys []string // current only use 'header' 'errors'
}
func GinZap() gin.HandlerFunc {
return GinZapWithConfig(defaultConfig)
}
func GinZapWithFormat(formatFunc FormatFunc) gin.HandlerFunc {
conf := defaultConfig
conf.FormatFunc = formatFunc
return GinZapWithConfig(conf)
}
func GinZapWithConfig(conf *GinLogConfig) gin.HandlerFunc {
skipPaths := make(map[string]bool, len(conf.SkipPaths))
for _, path := range conf.SkipPaths {
skipPaths[path] = true
}
if conf.TimeFormat == "" {
conf.TimeFormat = "2006-01-02 15:04:05.000"
}
if conf.FormatFunc == nil {
conf.FormatFunc = defaultFormatFunc
}
return func(c *gin.Context) {
start := time.Now()
path := c.Request.RequestURI
c.Next()
track := true
if _, ok := skipPaths[path]; ok || (conf.Skipper != nil && conf.Skipper(c)) {
track = false
}
if track && len(conf.SkipPathRegexps) > 0 {
for _, reg := range conf.SkipPathRegexps {
if !reg.MatchString(path) {
continue
}
track = false
break
}
}
if track {
latency := time.Since(start)
responseCode := c.Writer.Status()
method := c.Request.Method
clientIP := c.ClientIP()
userAgent := c.Request.UserAgent()
logParam := LogParam{
Time: time.Now().Format(conf.TimeFormat),
Method: method,
Path: path,
StatusCode: responseCode,
ClientIP: clientIP,
UserAgent: userAgent,
Latency: latency.String(),
}
if !slices.Contains(conf.HideKeys, "header") {
headerJson, _ := json.Marshal(c.Request.Header)
logParam.Header = string(headerJson)
}
if !slices.Contains(conf.HideKeys, "error") {
var errs []string
for _, err := range c.Errors.Errors() {
errs = append(errs, err)
}
logParam.Errors = errs
}
if len(c.Errors.Errors()) > 0 {
log.Error(conf.FormatFunc(logParam))
} else {
log.Info(conf.FormatFunc(logParam))
}
}
}
}