diff --git a/design/provide-logger-with-mothed/task-middleware.md b/design/provide-logger-with-mothed/task-middleware.md index 63b270a..ccd0b7f 100644 --- a/design/provide-logger-with-mothed/task-middleware.md +++ b/design/provide-logger-with-mothed/task-middleware.md @@ -1,25 +1,25 @@ - **`internal/app/middleware/auth.go`** - **中间件函数改造 (`AuthMiddleware`)**: - - [ ] 在 `AuthMiddleware` 返回的 `echo.HandlerFunc` 内部,获取 `echo.Context` 的 `request.Context()` 作为 + - [x] 在 `AuthMiddleware` 返回的 `echo.HandlerFunc` 内部,获取 `echo.Context` 的 `request.Context()` 作为 `upstreamCtx`。 - - [ ] 使用 `newCtx, logger := logs.Trace(upstreamCtx, context.Background(), "AuthMiddleware")` 来创建 `newCtx` + - [x] 使用 `newCtx, logger := logs.Trace(upstreamCtx, context.Background(), "AuthMiddleware")` 来创建 `newCtx` 和 `logger` 实例。 - - [ ] 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `newCtx` 写入 `echo.Context`,以便后续处理链使用。 - - [ ] 将所有对 `controller.SendErrorWithStatus` 的调用替换为 `controller.SendErrorWithAudit`。 - - [ ] 确保 `controller.SendErrorWithAudit` 接收 `newCtx` 作为第一个参数,并提供适当的 `actionType`, + - [x] 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `newCtx` 写入 `echo.Context`,以便后续处理链使用。 + - [x] 将所有对 `controller.SendErrorWithStatus` 的调用替换为 `controller.SendErrorWithAudit`。 + - [x] 确保 `controller.SendErrorWithAudit` 接收 `newCtx` 作为第一个参数,并提供适当的 `actionType`, `description`, `targetResource`。 - 例如,对于“请求未包含授权标头”的错误,`actionType` 可以是“认证失败”,`description` 是“请求未包含授权标头”, `targetResource` 为 `nil`。 - 对于“无效的Token”错误,`actionType` 可以是“认证失败”,`description` 是“无效的Token”,`targetResource` 是 `tokenString`。 - - [ ] 在 `AuthMiddleware` 内部,如果需要日志记录(例如 `tokenService.ParseToken` 失败或 `userRepo.FindByID` + - [x] 在 `AuthMiddleware` 内部,如果需要日志记录(例如 `tokenService.ParseToken` 失败或 `userRepo.FindByID` 失败),使用新创建的 `logger` 实例进行日志输出。 - - [ ] **关键**: 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `Context` 写回 `echo.Context` + - [x] **关键**: 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `Context` 写回 `echo.Context` ,以便传递给后续的中间件和 `Controller`。 - **`internal/app/middleware/audit.go`** - **改造动作**: - - [ ] 检查并重构所有日志记录中间件。 - - [ ] 中间件应该从请求的 `c.Request().Context()` 中提取 `upstreamCtx`。 - - [ ] 使用 `logs.Trace` 或 `logs.AddFuncName` 创建新的 `Context` 和 `Logger`。 - - [ ] **关键**: 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `Context` 写回 `echo.Context` + - [x] 检查并重构所有日志记录中间件。 + - [x] 中间件应该从请求的 `c.Request().Context()` 中提取 `upstreamCtx`。 + - [x] 使用 `logs.Trace` 或 `logs.AddFuncName` 创建新的 `Context` 和 `Logger`。 + - [x] **关键**: 使用 `c.SetRequest(c.Request().WithContext(newCtx))` 将更新后的 `Context` 写回 `echo.Context` ,以便传递给后续的中间件和 `Controller`。 diff --git a/internal/app/api/router.go b/internal/app/api/router.go index d81fdc1..9774987 100644 --- a/internal/app/api/router.go +++ b/internal/app/api/router.go @@ -1,6 +1,7 @@ package api import ( + "context" "net/http" "net/http/pprof" @@ -52,8 +53,8 @@ func (a *API) setupRoutes() { // --- Authenticated Routes --- // 所有在此注册的路由都需要通过 JWT 身份验证 authGroup := a.echo.Group("/api/v1") - authGroup.Use(middleware.AuthMiddleware(a.tokenService, a.userRepo)) // 1. 身份认证中间件 - authGroup.Use(middleware.AuditLogMiddleware(a.auditService)) // 2. 审计日志中间件 + authGroup.Use(middleware.AuthMiddleware(logs.AddCompName(context.Background(), "AuthMiddleware"), a.tokenService, a.userRepo)) // 1. 身份认证中间件 + authGroup.Use(middleware.AuditLogMiddleware(logs.AddCompName(context.Background(), "AuditLogMiddleware"), a.auditService)) // 2. 审计日志中间件 { // 用户相关路由组 userGroup := authGroup.Group("/users") diff --git a/internal/app/middleware/audit.go b/internal/app/middleware/audit.go index 7479dfe..2a09dc5 100644 --- a/internal/app/middleware/audit.go +++ b/internal/app/middleware/audit.go @@ -1,16 +1,21 @@ package middleware import ( + "context" + "git.huangwc.com/pig/pig-farm-controller/internal/domain/audit" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "github.com/labstack/echo/v4" ) // AuditLogMiddleware 创建一个Echo中间件,用于在请求结束后记录用户操作审计日志。 // 它依赖于控制器通过调用 SendSuccessWithAudit 或 SendErrorWithAudit 在上下文中设置的审计信息。 -func AuditLogMiddleware(auditService audit.Service) echo.MiddlewareFunc { +func AuditLogMiddleware(ctx context.Context, auditService audit.Service) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { + newCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuditLogMiddleware") + // 首先执行请求链中的后续处理程序(即业务控制器) err := next(c) @@ -44,6 +49,7 @@ func AuditLogMiddleware(auditService audit.Service) echo.MiddlewareFunc { // 调用审计服务记录日志(异步) auditService.LogAction( + newCtx, user, reqCtx, actionType, diff --git a/internal/app/middleware/auth.go b/internal/app/middleware/auth.go index 57a757d..8f9b9fb 100644 --- a/internal/app/middleware/auth.go +++ b/internal/app/middleware/auth.go @@ -2,12 +2,14 @@ package middleware import ( + "context" "errors" "net/http" "strings" "git.huangwc.com/pig/pig-farm-controller/internal/app/controller" "git.huangwc.com/pig/pig-farm-controller/internal/domain/token" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "github.com/labstack/echo/v4" @@ -16,9 +18,11 @@ import ( // AuthMiddleware 创建一个Echo中间件,用于JWT身份验证 // 它依赖于 TokenService 来解析和验证 token,并使用 UserRepository 来获取完整的用户信息 -func AuthMiddleware(tokenService token.Service, userRepo repository.UserRepository) echo.MiddlewareFunc { +func AuthMiddleware(ctx context.Context, tokenService token.Service, userRepo repository.UserRepository) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { + reqCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuthMiddleware") + // 从 Authorization header 获取 token authHeader := c.Request().Header.Get("Authorization") if authHeader == "" { @@ -40,7 +44,7 @@ func AuthMiddleware(tokenService token.Service, userRepo repository.UserReposito } // 根据 token 中的用户ID,从数据库中获取完整的用户信息 - user, err := userRepo.FindByID(claims.UserID) + user, err := userRepo.FindByID(reqCtx, claims.UserID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { // Token有效,但对应的用户已不存在