service/library/middleware/logger.go

136 lines
3.3 KiB
Go

package middleware
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"service/library/logger"
"strings"
"time"
)
var defaultLogFormatter = func(param gin.LogFormatterParams) string {
if param.Latency > time.Minute {
// Truncate in a golang < 1.8 safe way
param.Latency = param.Latency - param.Latency%time.Second
}
return fmt.Sprintf("|%3d|%13v|%15s|%-7s %#v\t%s",
param.StatusCode,
param.Latency,
param.ClientIP,
param.Method,
param.Path,
param.ErrorMessage,
)
}
type bodyLogWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (w bodyLogWriter) Write(b []byte) (int, error) {
w.body.Write(b)
return w.ResponseWriter.Write(b)
}
func LoggerMiddleware(conf gin.LoggerConfig) gin.HandlerFunc {
formatter := conf.Formatter
if formatter == nil {
formatter = defaultLogFormatter
}
return func(c *gin.Context) {
// Start timer
start := time.Now()
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
//body writer
blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = blw
// Process request
c.Next()
notlogged := conf.SkipPaths
var skip map[string]struct{}
if length := len(notlogged); length > 0 {
skip = make(map[string]struct{}, length)
for _, path := range notlogged {
skip[path] = struct{}{}
}
}
// Log only when path is not being skipped
if _, ok := skip[path]; !ok {
param := gin.LogFormatterParams{
Request: c.Request,
Keys: c.Keys,
}
// Stop timer
param.TimeStamp = time.Now()
param.Latency = param.TimeStamp.Sub(start)
param.ClientIP = c.ClientIP()
param.Method = c.Request.Method
param.StatusCode = c.Writer.Status()
param.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
param.BodySize = c.Writer.Size()
if raw != "" {
path = path + "?" + raw
}
param.Path = path
var bodyBytes []byte
body, ok := c.Get(gin.BodyBytesKey)
if ok {
bodyBytes = body.([]byte)
}
if _, ok := NoLogRoutesMap[param.Path]; !ok {
logger.Info("%s params: %s", formatter(param), string(bodyBytes))
}
if strings.Contains(param.Path, "is_there_a_new_version_available") {
logger.Info("%s response: %s", formatter(param), blw.body.String())
}
bReq := BaseRequest{}
_ = json.Unmarshal(bodyBytes, &bReq)
if bReq.Mid == 161 {
logger.Info("%s xresponse: %s", formatter(param), blw.body.String())
}
//logger.WithCtx(c.Request.Context()).Info("%s params: %s", formatter(param), bodyStr)
//if accessConf.LogResponseEnabled {
// logger.WithCtx(c.Request.Context()).Info("%s response: %s", formatter(param), blw.body.String())
//}
}
}
}
var NoLogRoutesMap = map[string]bool{
"/healthcheck": true,
}
type BaseRequest struct {
Mid int64 `json:"b_mid"` // 用户id
Did string `json:"b_did"` // 设备id
Version string `json:"b_ver"` // 版本
OsVersion string `json:"b_osver"` // 系统版本
DevType int32 `json:"b_dt"` // 设备类型
Channel string `json:"b_ch"` // 渠道
Model string `json:"b_model"` // 机型
NetType string `json:"b_nt"` // 网络类型
Timestamp int64 `json:"b_ts"` // 时间戳,毫秒
Token string `json:"b_token"` // 令牌
Location struct {
Lat float64 `json:"b_lat"`
Lon float64 `json:"b_lon"`
} `json:"b_loc"` // 经纬度
}