Every API request logged one bare "info" line with no message: upstream calls log.WithFields(logData).Info(), and the console formatter does not render fields, so status, latency, IP, method and URI all went nowhere. One line of pure noise per request. Give the line its message and demote it to debug. The payload is worth having when diagnosing a slow or failing request, so it is recoverable by setting logger.level back to debug rather than deleted. settings.yml drops from trace to info accordingly. Nothing else in the project logs below info: the many .Debug() calls are gorm SQL echo, which is unaffected by logger level. This patches upstream go-admin middleware, marked as such in a comment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
144 lines
4.0 KiB
Go
144 lines
4.0 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/json"
|
|
"go-admin/app/admin/service/dto"
|
|
"go-admin/common"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-admin-team/go-admin-core/sdk"
|
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
|
"github.com/go-admin-team/go-admin-core/sdk/config"
|
|
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
|
|
|
"go-admin/common/global"
|
|
)
|
|
|
|
// LoggerToFile 日志记录到文件
|
|
func LoggerToFile() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
log := api.GetRequestLogger(c)
|
|
// 开始时间
|
|
startTime := time.Now()
|
|
// 处理请求
|
|
var body string
|
|
switch c.Request.Method {
|
|
case http.MethodPost, http.MethodPut, http.MethodGet, http.MethodDelete:
|
|
bf := bytes.NewBuffer(nil)
|
|
wt := bufio.NewWriter(bf)
|
|
_, err := io.Copy(wt, c.Request.Body)
|
|
if err != nil {
|
|
log.Warnf("copy body error, %s", err.Error())
|
|
err = nil
|
|
}
|
|
rb, _ := ioutil.ReadAll(bf)
|
|
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rb))
|
|
body = string(rb)
|
|
}
|
|
|
|
c.Next()
|
|
url := c.Request.RequestURI
|
|
if strings.Index(url, "logout") > -1 ||
|
|
strings.Index(url, "login") > -1 {
|
|
return
|
|
}
|
|
// 结束时间
|
|
endTime := time.Now()
|
|
if c.Request.Method == http.MethodOptions {
|
|
return
|
|
}
|
|
|
|
rt, bl := c.Get("result")
|
|
var result = ""
|
|
if bl {
|
|
rb, err := json.Marshal(rt)
|
|
if err != nil {
|
|
log.Warnf("json Marshal result error, %s", err.Error())
|
|
} else {
|
|
result = string(rb)
|
|
}
|
|
}
|
|
|
|
st, bl := c.Get("status")
|
|
var statusBus = 0
|
|
if bl {
|
|
statusBus = st.(int)
|
|
}
|
|
|
|
// 请求方式
|
|
reqMethod := c.Request.Method
|
|
// 请求路由
|
|
reqUri := c.Request.RequestURI
|
|
// 状态码
|
|
statusCode := c.Writer.Status()
|
|
// 请求IP
|
|
clientIP := common.GetClientIP(c)
|
|
// 执行时间
|
|
latencyTime := endTime.Sub(startTime)
|
|
// 日志格式
|
|
logData := map[string]interface{}{
|
|
"statusCode": statusCode,
|
|
"latencyTime": latencyTime,
|
|
"clientIP": clientIP,
|
|
"method": reqMethod,
|
|
"uri": reqUri,
|
|
}
|
|
// GoAuto 改动(#48):上游这里是 log.WithFields(logData).Info(),不带任何
|
|
// 消息。控制台格式化器不渲染 fields,于是每个请求打出一行**空的** info——
|
|
// 一行零信息量的噪音。这里补上消息体,并降到 debug 级:
|
|
// settings.yml 的 logger.level 设为 debug 或 trace 时才输出。
|
|
log.WithFields(logData).Debugf("%s %s %d %s %s",
|
|
reqMethod, reqUri, statusCode, latencyTime, clientIP)
|
|
defer func() {
|
|
log.Fields(map[string]interface{}{})
|
|
}()
|
|
if c.Request.Method != "OPTIONS" && config.LoggerConfig.EnabledDB && statusCode != 404 {
|
|
SetDBOperLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, body, result, statusBus)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetDBOperLog 写入操作日志表 fixme 该方法后续即将弃用
|
|
func SetDBOperLog(c *gin.Context, clientIP string, statusCode int, reqUri string, reqMethod string, latencyTime time.Duration, body string, result string, status int) {
|
|
|
|
log := api.GetRequestLogger(c)
|
|
l := make(map[string]interface{})
|
|
l["_fullPath"] = c.FullPath()
|
|
l["operUrl"] = reqUri
|
|
l["operIp"] = clientIP
|
|
l["operLocation"] = "" // pkg.GetLocation(clientIP, gaConfig.ExtConfig.AMap.Key)
|
|
l["operName"] = user.GetUserName(c)
|
|
l["requestMethod"] = reqMethod
|
|
l["operParam"] = body
|
|
l["operTime"] = time.Now()
|
|
l["jsonResult"] = result
|
|
l["latencyTime"] = latencyTime.String()
|
|
l["statusCode"] = statusCode
|
|
l["userAgent"] = c.Request.UserAgent()
|
|
l["createBy"] = user.GetUserId(c)
|
|
l["updateBy"] = user.GetUserId(c)
|
|
if status == http.StatusOK {
|
|
l["status"] = dto.OperaStatusEnabel
|
|
} else {
|
|
l["status"] = dto.OperaStatusDisable
|
|
}
|
|
q := sdk.Runtime.GetMemoryQueue(c.Request.Host)
|
|
message, err := sdk.Runtime.GetStreamMessage("", global.OperateLog, l)
|
|
if err != nil {
|
|
log.Errorf("GetStreamMessage error, %s", err.Error())
|
|
// 日志报错错误,不中断请求
|
|
} else {
|
|
err = q.Append(message)
|
|
if err != nil {
|
|
log.Errorf("Append message error, %s", err.Error())
|
|
}
|
|
}
|
|
}
|