package middleware import ( "bytes" "context" "encoding/json" "io" "time" "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" kratoshttp "github.com/go-kratos/kratos/v2/transport/http" ) // LogLayout 日志layout type LogLayout struct { Time time.Time `json:"time"` Metadata map[string]interface{} `json:"metadata,omitempty"` Path string `json:"path"` Query string `json:"query,omitempty"` Body string `json:"body,omitempty"` IP string `json:"ip"` UserAgent string `json:"user_agent"` Error string `json:"error,omitempty"` Cost time.Duration `json:"cost"` Source string `json:"source"` } // LoggerConfig 日志中间件配置 type LoggerConfig struct { // Filter 用户自定义过滤 Filter func(ctx context.Context, path string) bool // FilterKeyword 关键字过滤 FilterKeyword func(layout *LogLayout) bool // AuthProcess 鉴权处理 AuthProcess func(ctx context.Context, layout *LogLayout) // Print 日志处理 Print func(LogLayout) // Source 服务唯一标识 Source string } // Logger 日志中间件 func Logger(cfg LoggerConfig) middleware.Middleware { if cfg.Print == nil { cfg.Print = func(layout LogLayout) { v, _ := json.Marshal(layout) log.Info(string(v)) } } if cfg.Source == "" { cfg.Source = "Kratos" } return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (interface{}, error) { var ( path string query string body string ip string userAgent string ) if tr, ok := transport.FromServerContext(ctx); ok { path = tr.Operation() if header := tr.RequestHeader(); header != nil { userAgent = header.Get("User-Agent") } if ht, ok := tr.(kratoshttp.Transporter); ok { r := ht.Request() query = r.URL.RawQuery ip = getClientIP(r) // 读取body(仅在未过滤时) if cfg.Filter == nil || !cfg.Filter(ctx, path) { bodyBytes, _ := io.ReadAll(r.Body) r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) body = string(bodyBytes) } } } // 检查是否需要过滤 if cfg.Filter != nil && cfg.Filter(ctx, path) { return handler(ctx, req) } start := time.Now() reply, err := handler(ctx, req) cost := time.Since(start) layout := LogLayout{ Time: time.Now(), Path: path, Query: query, Body: body, IP: ip, UserAgent: userAgent, Cost: cost, Source: cfg.Source, } if err != nil { layout.Error = err.Error() } // 处理鉴权信息 if cfg.AuthProcess != nil { cfg.AuthProcess(ctx, &layout) } // 关键字过滤 if cfg.FilterKeyword != nil { cfg.FilterKeyword(&layout) } // 输出日志 cfg.Print(layout) return reply, err } } } // DefaultLogger 默认日志中间件 func DefaultLogger() middleware.Middleware { return Logger(LoggerConfig{ Source: "Kratos", }) }