优化结构
This commit is contained in:
@@ -432,6 +432,8 @@ func routedLogPaths(module string, level zapcore.Level) []string {
|
||||
paths = append(paths, filepath.Join("http", "access.log"))
|
||||
case "timedTask":
|
||||
paths = append(paths, filepath.Join("timedTask", "task.log"))
|
||||
case "websocket":
|
||||
paths = append(paths, filepath.Join("websocket", "websocket.log"))
|
||||
case "error":
|
||||
paths = append(paths, filepath.Join("error", "error.log"))
|
||||
default:
|
||||
|
||||
@@ -41,6 +41,7 @@ func TestZapHandlerRoutesHTTPAndErrorLogs(t *testing.T) {
|
||||
handler, cleanup := newZapHandler(root, "application.log", Options{Level: "info", Format: "json"}, nil)
|
||||
logger := slog.New(handler)
|
||||
logger.Info("request", "mod", "http", "request_id", "req-1")
|
||||
logger.Info("handshake", "mod", "websocket")
|
||||
logger.Error("failed", "mod", "users")
|
||||
cleanup()
|
||||
|
||||
@@ -52,6 +53,7 @@ func TestZapHandlerRoutesHTTPAndErrorLogs(t *testing.T) {
|
||||
paths := []string{
|
||||
filepath.Join(root, date, "application.log"),
|
||||
filepath.Join(root, date, "http", "access.log"),
|
||||
filepath.Join(root, date, "websocket", "websocket.log"),
|
||||
filepath.Join(root, date, "users", "application.log"),
|
||||
filepath.Join(root, date, "error", "error.log"),
|
||||
}
|
||||
|
||||
+73
-3
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
kratoshttp "github.com/go-kratos/kratos/v3/transport/http"
|
||||
melody "github.com/olahol/melody"
|
||||
)
|
||||
|
||||
func NewGinEngineWithRuntime(runtime *config.Store, access *systemservice.AccessControlService, auth middleware.TokenAuthenticator, security *systemservice.SecurityService, audit *systemservice.AuditRecorder, logger *slog.Logger, version string, routes platformmodule.RouteRegistrar, ws *websocket.Server) *gin.Engine {
|
||||
@@ -27,7 +28,7 @@ func NewGinEngineWithRuntime(runtime *config.Store, access *systemservice.Access
|
||||
if err := engine.SetTrustedProxies(nil); err != nil && logger != nil {
|
||||
logger.Error("disable trusted proxies failed", "error", err)
|
||||
}
|
||||
engine.Use(middleware.RequestMeta(), middleware.Recovery(logger), middleware.AccessLog(runtime, logger, version), middleware.CORS(runtime), middleware.ErrorAudit(logger), middleware.SecurityRateLimit(security))
|
||||
engine.Use(middleware.RequestMeta(), middleware.Recovery(logger), websocketHandshakeLogger(logger), middleware.AccessLog(runtime, logger, version), middleware.CORS(runtime), middleware.ErrorAudit(logger), middleware.SecurityRateLimit(security))
|
||||
|
||||
prefix := ""
|
||||
snapshot := runtime.Snapshot()
|
||||
@@ -46,16 +47,58 @@ func NewGinEngineWithRuntime(runtime *config.Store, access *systemservice.Access
|
||||
if routes != nil {
|
||||
routes.RegisterRoutes(public, private, engine)
|
||||
}
|
||||
if ws != nil && logger != nil {
|
||||
ws.OnConnect(func(session *melody.Session) {
|
||||
request := session.Request
|
||||
logger.InfoContext(request.Context(), "websocket connection established",
|
||||
"mod", "websocket", "path", request.URL.Path, "remote_addr", request.RemoteAddr,
|
||||
"origin", request.Header.Get("Origin"), "user_id", session.Keys["user_id"],
|
||||
"request_id", session.Keys["request_id"])
|
||||
})
|
||||
ws.OnDisconnect(func(session *melody.Session) {
|
||||
request := session.Request
|
||||
logger.InfoContext(request.Context(), "websocket connection closed",
|
||||
"mod", "websocket", "path", request.URL.Path, "remote_addr", request.RemoteAddr,
|
||||
"user_id", session.Keys["user_id"], "request_id", session.Keys["request_id"])
|
||||
})
|
||||
}
|
||||
handleWebSocket := func(c *gin.Context) {
|
||||
wsLogger := logger
|
||||
hasToken := middleware.RequestToken(c, true) != ""
|
||||
if ws == nil || !ws.Enabled() || c.Request.URL.Path != ws.Path() {
|
||||
if wsLogger != nil {
|
||||
wsLogger.WarnContext(c.Request.Context(), "websocket handshake rejected: endpoint unavailable",
|
||||
"mod", "websocket", "path", c.Request.URL.Path, "expected_path", websocketPath(ws),
|
||||
"enabled", ws != nil && ws.Enabled(), "has_token", hasToken)
|
||||
}
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !middleware.AuthenticateWebSocket(c, auth) {
|
||||
if wsLogger != nil {
|
||||
wsLogger.WarnContext(c.Request.Context(), "websocket handshake rejected: authentication failed",
|
||||
"mod", "websocket", "path", c.Request.URL.Path, "status", c.Writer.Status(),
|
||||
"has_token", hasToken, "origin", c.GetHeader("Origin"))
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := ws.HandleRequest(c.Writer, c.Request); err != nil && logger != nil {
|
||||
logger.Warn("websocket request failed", "mod", "websocket", "error", err)
|
||||
claims := middleware.Claims(c)
|
||||
keys := map[string]any{
|
||||
"request_id": contextString(c, "request_id"),
|
||||
}
|
||||
if claims != nil {
|
||||
keys["user_id"] = claims.ID
|
||||
}
|
||||
if wsLogger != nil {
|
||||
wsLogger.InfoContext(c.Request.Context(), "websocket authentication accepted; upgrading connection",
|
||||
"mod", "websocket", "path", c.Request.URL.Path, "origin", c.GetHeader("Origin"),
|
||||
"remote_addr", c.Request.RemoteAddr, "user_id", keys["user_id"],
|
||||
"request_id", keys["request_id"])
|
||||
}
|
||||
if err := ws.HandleRequestWithKeys(c.Writer, c.Request, keys); err != nil && wsLogger != nil {
|
||||
wsLogger.WarnContext(c.Request.Context(), "websocket upgrade failed", "mod", "websocket",
|
||||
"path", c.Request.URL.Path, "origin", c.GetHeader("Origin"), "error", err,
|
||||
"request_id", keys["request_id"])
|
||||
}
|
||||
}
|
||||
if ws != nil && ws.Enabled() {
|
||||
@@ -89,6 +132,33 @@ func NewGinEngineWithRuntime(runtime *config.Store, access *systemservice.Access
|
||||
return engine
|
||||
}
|
||||
|
||||
func websocketHandshakeLogger(logger *slog.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if logger != nil && strings.EqualFold(strings.TrimSpace(c.GetHeader("Upgrade")), "websocket") {
|
||||
logger.InfoContext(c.Request.Context(), "websocket handshake packet received",
|
||||
"mod", "websocket", "path", c.Request.URL.Path, "host", c.Request.Host,
|
||||
"remote_addr", c.Request.RemoteAddr, "origin", c.GetHeader("Origin"),
|
||||
"has_token", middleware.RequestToken(c, true) != "",
|
||||
"connection", c.GetHeader("Connection"), "user_agent", c.Request.UserAgent(),
|
||||
"request_id", contextString(c, "request_id"))
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func contextString(c *gin.Context, key string) string {
|
||||
value, _ := c.Get(key)
|
||||
text, _ := value.(string)
|
||||
return text
|
||||
}
|
||||
|
||||
func websocketPath(ws *websocket.Server) string {
|
||||
if ws == nil {
|
||||
return ""
|
||||
}
|
||||
return ws.Path()
|
||||
}
|
||||
|
||||
func NewGinServer(c *config.Server, engine *gin.Engine) *kratoshttp.Server {
|
||||
network, address := "tcp", ":8000"
|
||||
if c != nil && c.HTTP != nil {
|
||||
|
||||
Reference in New Issue
Block a user