kra/internal/server/middleware/logger.go

134 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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",
})
}