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"` // 经纬度 }