任务二完成
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
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",
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user