优化结构
This commit is contained in:
@@ -2,10 +2,14 @@ package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -67,14 +71,26 @@ func AccessLog(runtime *conf.Runtime, logger *slog.Logger, version string) gin.H
|
||||
if config != nil && config.Zap != nil && config.Zap.AccessLogMaxBytes > 0 {
|
||||
logLimit = int(config.Zap.AccessLogMaxBytes)
|
||||
}
|
||||
paymentCallback := isPaymentCallbackPath(c.Request.URL.Path)
|
||||
paymentConfigWrite := isPaymentIntegrationConfigWrite(c.Request.Method, c.Request.URL.Path)
|
||||
requestText := ""
|
||||
if multipart {
|
||||
if paymentCallback {
|
||||
requestText = paymentCallbackSummary(requestBody, c.GetHeader("Content-Type"))
|
||||
} else if paymentConfigWrite {
|
||||
requestText = paymentConfigSummary(requestBody)
|
||||
} else if multipart {
|
||||
requestText = "[文件]"
|
||||
} else {
|
||||
requestText = redactJSON(requestBody, c.GetHeader("Content-Type"), logLimit)
|
||||
}
|
||||
c.Set(ctxReqBodyKey, requestText)
|
||||
c.Set(ctxRespBufferKey, &writer.body)
|
||||
if paymentCallback {
|
||||
// Callback acknowledgements and provider payloads must not flow into
|
||||
// the generic response/error audit pipeline.
|
||||
c.Set(ctxRespBufferKey, &bytes.Buffer{})
|
||||
} else {
|
||||
c.Set(ctxRespBufferKey, &writer.body)
|
||||
}
|
||||
if !requestReadFailed {
|
||||
c.Next()
|
||||
}
|
||||
@@ -82,6 +98,9 @@ func AccessLog(runtime *conf.Runtime, logger *slog.Logger, version string) gin.H
|
||||
return
|
||||
}
|
||||
responseText := redactJSON(writer.body.Bytes(), c.Writer.Header().Get("Content-Type"), logLimit)
|
||||
if paymentCallback {
|
||||
responseText = "[支付回调响应已省略]"
|
||||
}
|
||||
userID, authorityID := uint(0), uint(0)
|
||||
if claims := Claims(c); claims != nil {
|
||||
userID, authorityID = claims.ID, claims.AuthorityID
|
||||
@@ -95,22 +114,36 @@ func AccessLog(runtime *conf.Runtime, logger *slog.Logger, version string) gin.H
|
||||
bytesOut = 0
|
||||
}
|
||||
privateErrors := strings.TrimRight(c.Errors.ByType(gin.ErrorTypePrivate).String(), "\n")
|
||||
attributes := []any{
|
||||
"mod", "http", "ip", c.ClientIP(), "method", c.Request.Method, "http_path", c.Request.URL.Path, "http_route", route,
|
||||
"http_status", c.Writer.Status(), "latency_ms", time.Since(started).Milliseconds(),
|
||||
"request_id", stringValueFromContext(c, "request_id"), "trace_id", stringValueFromContext(c, "trace_id"),
|
||||
"bytes_in", bytesIn, "bytes_out", bytesOut, "user_id", userID, "authority_id", authorityID,
|
||||
"error", c.Writer.Status() >= http.StatusInternalServerError || privateErrors != "", "ua", c.Request.UserAgent(), "req_query", c.Request.URL.RawQuery}
|
||||
if config != nil && config.Zap != nil && config.Zap.AccessReqHeaders {
|
||||
var attributes []any
|
||||
if paymentCallback {
|
||||
attributes = []any{
|
||||
"mod", "payment-callback", "payment_provider", paymentCallbackProvider(c.Request.URL.Path),
|
||||
"http_status", c.Writer.Status(), "latency_ms", time.Since(started).Milliseconds(),
|
||||
"request_id", stringValueFromContext(c, "request_id"), "trace_id", stringValueFromContext(c, "trace_id"),
|
||||
"bytes_in", bytesIn, "bytes_out", bytesOut,
|
||||
"error", c.Writer.Status() >= http.StatusInternalServerError || privateErrors != "",
|
||||
"payment_callback", true, "payment_callback_summary", requestText,
|
||||
}
|
||||
} else {
|
||||
attributes = []any{
|
||||
"mod", "http", "ip", c.ClientIP(), "method", c.Request.Method, "http_path", c.Request.URL.Path, "http_route", route,
|
||||
"http_status", c.Writer.Status(), "latency_ms", time.Since(started).Milliseconds(),
|
||||
"request_id", stringValueFromContext(c, "request_id"), "trace_id", stringValueFromContext(c, "trace_id"),
|
||||
"bytes_in", bytesIn, "bytes_out", bytesOut, "user_id", userID, "authority_id", authorityID,
|
||||
"error", c.Writer.Status() >= http.StatusInternalServerError || privateErrors != "", "ua", c.Request.UserAgent(),
|
||||
"req_query", c.Request.URL.RawQuery,
|
||||
}
|
||||
}
|
||||
if !paymentCallback && config != nil && config.Zap != nil && config.Zap.AccessReqHeaders {
|
||||
attributes = append(attributes, "req_headers", redactHeaders(c.Request.Header))
|
||||
}
|
||||
if config != nil && config.Zap != nil && config.Zap.AccessReqBody {
|
||||
if !paymentCallback && config != nil && config.Zap != nil && config.Zap.AccessReqBody {
|
||||
attributes = append(attributes, "req_body", requestText)
|
||||
}
|
||||
if config != nil && config.Zap != nil && config.Zap.AccessRespData {
|
||||
if !paymentCallback && config != nil && config.Zap != nil && config.Zap.AccessRespData {
|
||||
attributes = append(attributes, "resp_data", responseText)
|
||||
}
|
||||
if privateErrors != "" {
|
||||
if !paymentCallback && privateErrors != "" {
|
||||
attributes = append(attributes, "error_msg", privateErrors)
|
||||
}
|
||||
logger.InfoContext(c.Request.Context(), "请求完成", attributes...)
|
||||
@@ -122,6 +155,56 @@ func isMediaUploadRoute(route string) bool {
|
||||
strings.HasSuffix(route, "/mediaUpload/chunk")
|
||||
}
|
||||
|
||||
func isPaymentCallbackPath(path string) bool {
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
for index := 0; index+1 < len(parts); index++ {
|
||||
if parts[index] == "payment" && parts[index+1] == "callback" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func paymentCallbackProvider(path string) string {
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
for index := 0; index+2 < len(parts); index++ {
|
||||
if parts[index] == "payment" && parts[index+1] == "callback" {
|
||||
return parts[index+2]
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func paymentCallbackSummary(body []byte, contentType string) string {
|
||||
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil || mediaType == "" {
|
||||
mediaType = strings.TrimSpace(strings.SplitN(contentType, ";", 2)[0])
|
||||
}
|
||||
if mediaType == "" {
|
||||
mediaType = "unknown"
|
||||
}
|
||||
digest := sha256.Sum256(body)
|
||||
return "[支付回调正文已省略 body_bytes=" + strconv.Itoa(len(body)) + " body_sha256=" + hex.EncodeToString(digest[:]) + " content_type=" + mediaType + "]"
|
||||
}
|
||||
|
||||
func isPaymentIntegrationConfigWrite(method, path string) bool {
|
||||
if method != http.MethodPut {
|
||||
return false
|
||||
}
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
for index := 0; index+3 < len(parts); index++ {
|
||||
if parts[index] == "integration" && parts[index+1] == "configs" && parts[index+2] == "payment" && parts[index+3] != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func paymentConfigSummary(body []byte) string {
|
||||
digest := sha256.Sum256(body)
|
||||
return "[支付配置正文已省略 body_bytes=" + strconv.Itoa(len(body)) + " body_sha256=" + hex.EncodeToString(digest[:]) + "]"
|
||||
}
|
||||
|
||||
func redactHeaders(headers map[string][]string) map[string]string {
|
||||
out := make(map[string]string, len(headers))
|
||||
for key, values := range headers {
|
||||
|
||||
Reference in New Issue
Block a user