完善日志和审计链路
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Recovery(logger *zap.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
err := fmt.Errorf("panic: %v", recovered)
|
||||
_ = c.Error(err)
|
||||
logger.Error("http panic recovered",
|
||||
zap.String("request_id", GetRequestID(c)),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", c.Request.URL.Path),
|
||||
zap.String("route", c.FullPath()),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
zap.String("panic", fmt.Sprint(recovered)),
|
||||
zap.ByteString("stack", debug.Stack()),
|
||||
)
|
||||
if !c.Writer.Written() {
|
||||
response.Error(c, http.StatusInternalServerError, "internal_error", "服务暂时不可用")
|
||||
}
|
||||
c.Abort()
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
RequestIDHeader = "X-Request-ID"
|
||||
ContextRequestID = "request_id"
|
||||
)
|
||||
|
||||
func RequestID() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := c.GetHeader(RequestIDHeader)
|
||||
if requestID == "" {
|
||||
requestID = newRequestID()
|
||||
}
|
||||
c.Set(ContextRequestID, requestID)
|
||||
c.Writer.Header().Set(RequestIDHeader, requestID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func GetRequestID(c *gin.Context) string {
|
||||
value, ok := c.Get(ContextRequestID)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
requestID, ok := value.(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return requestID
|
||||
}
|
||||
|
||||
func newRequestID() string {
|
||||
buf := make([]byte, 16)
|
||||
if _, err := rand.Read(buf); err != nil {
|
||||
return ""
|
||||
}
|
||||
return hex.EncodeToString(buf)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -12,12 +13,36 @@ func RequestLogger(logger *zap.Logger) gin.HandlerFunc {
|
||||
start := time.Now()
|
||||
c.Next()
|
||||
|
||||
logger.Info("http request",
|
||||
latency := time.Since(start)
|
||||
fields := []zap.Field{
|
||||
zap.String("request_id", GetRequestID(c)),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", c.Request.URL.Path),
|
||||
zap.String("route", c.FullPath()),
|
||||
zap.Int("status", c.Writer.Status()),
|
||||
zap.Duration("latency", time.Since(start)),
|
||||
zap.Float64("latency_ms", float64(latency.Microseconds())/1000),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
)
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
zap.String("referer", c.GetHeader("Referer")),
|
||||
zap.Int("response_size", c.Writer.Size()),
|
||||
}
|
||||
if userID, ok := c.Get(ContextUserID); ok {
|
||||
fields = append(fields, zap.Any("user_id", userID))
|
||||
}
|
||||
if adminID, ok := c.Get(ContextAdminID); ok {
|
||||
fields = append(fields, zap.Any("admin_id", adminID))
|
||||
}
|
||||
if len(c.Errors) > 0 {
|
||||
fields = append(fields, zap.String("errors", strings.TrimSpace(c.Errors.String())))
|
||||
}
|
||||
|
||||
switch {
|
||||
case c.Writer.Status() >= 500:
|
||||
logger.Error("http request", fields...)
|
||||
case c.Writer.Status() >= 400:
|
||||
logger.Warn("http request", fields...)
|
||||
default:
|
||||
logger.Info("http request", fields...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user