package logger import ( "bytes" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "io/ioutil" "net/http" "time" ) // LoggerToFile 日志记录到文件 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 //请求参数 request := getRequestBody(ctx) // 请求IP clientIP := ctx.ClientIP() // 处理请求 ctx.Next() // 结束时间 endTime := time.Now() // 执行时间 latencyTime := endTime.Sub(startTime) // 状态码 statusCode := ctx.Writer.Status() // 响应 response := blw.body.String() if len(response) > 256 { response = "..." } //日志格式 Logger.WithFields(logrus.Fields{ "status_code": statusCode, "latency_time": latencyTime, "client_ip": clientIP, "req_method": reqMethod, "request": request, "response": response, "req_uri": reqUri, }).Info() } } func getRequestBody(ctx *gin.Context) interface{} { 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) }