package logger import ( "bytes" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "io/ioutil" "net/http" "strings" "time" ) // LogToFile 日志记录到文件 func LogToFile() gin.HandlerFunc { return func(ctx *gin.Context) { // 初始化bodyLogWriter blw := &bodyLogWriter{ body: bytes.NewBufferString(""), ResponseWriter: ctx.Writer, } ctx.Writer = blw // 开始时间 startTime := time.Now() // 请求方式 reqMethod := ctx.Request.Method // 请求路由 reqUri := ctx.Request.RequestURI //如果是查询日志,则跳出,不记录日志 if strings.Contains(reqUri, "/api/blade-log/usual") { ctx.Next() return } //请求参数 request := getRequestBody(ctx) if v, ok := request.(string); ok && len(v) > 2560 { request = "none" } // 请求IP clientIP := ctx.ClientIP() // 处理请求 ctx.Next() // 结束时间 endTime := time.Now() // 执行时间 latencyTime := endTime.Sub(startTime) // 状态码 statusCode := ctx.Writer.Status() // 响应 response := blw.body.String() if len(response) > 2560 { response = "none" } //日志格式 Logger.WithFields(logrus.Fields{ "status_code": statusCode, "latency_time": latencyTime, "client_ip": clientIP, "req_method": reqMethod, "request": request, "response": response, "req_uri": reqUri, "t": time.Now().UnixMilli(), //用于es中按时间排序 }).Info() } } func getRequestBody(ctx *gin.Context) interface{} { if strings.Contains(ctx.ContentType(), "multipart/form-data") { return "multipart" } switch ctx.Request.Method { case http.MethodGet: fallthrough case http.MethodDelete: return ctx.Request.URL.Query() case http.MethodPost: fallthrough case http.MethodPut: fallthrough case http.MethodPatch: var bodyBytes []byte bodyBytes, err := ioutil.ReadAll(ctx.Request.Body) if err != nil { return nil } ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) return string(bodyBytes) } return nil } // bodyLogWriter 定义一个存储响应内容的结构体 type bodyLogWriter struct { gin.ResponseWriter body *bytes.Buffer } // Write 读取响应数据 func (w bodyLogWriter) Write(b []byte) (int, error) { w.body.Write(b) return w.ResponseWriter.Write(b) }