refactor: 后端日志系统重构
- 新增模块化日志器(pkg/logger/module.go) - 新增 GORM 日志适配器 - 统一日志入口,移除所有 zap.L() 全局 logger 调用 - 字段标准化 - 启动阶段使用结构化日志 - 更新所有相关测试
This commit is contained in:
130
backend/pkg/logger/gorm.go
Normal file
130
backend/pkg/logger/gorm.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gorm.io/gorm"
|
||||
gormlogger "gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type GormLogger struct {
|
||||
logger *zap.Logger
|
||||
level zapcore.Level
|
||||
}
|
||||
|
||||
func NewGormLogger(logger *zap.Logger) *GormLogger {
|
||||
return &GormLogger{
|
||||
logger: logger.Named("database"),
|
||||
level: zapcore.DebugLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface {
|
||||
newLogger := &GormLogger{
|
||||
logger: l.logger,
|
||||
level: l.gormLevelToZap(level),
|
||||
}
|
||||
return newLogger
|
||||
}
|
||||
|
||||
func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.level > zapcore.DebugLevel {
|
||||
return
|
||||
}
|
||||
l.log(ctx, zapcore.DebugLevel, msg, data...)
|
||||
}
|
||||
|
||||
func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.level > zapcore.WarnLevel {
|
||||
return
|
||||
}
|
||||
l.log(ctx, zapcore.WarnLevel, msg, data...)
|
||||
}
|
||||
|
||||
func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.level > zapcore.ErrorLevel {
|
||||
return
|
||||
}
|
||||
l.log(ctx, zapcore.ErrorLevel, msg, data...)
|
||||
}
|
||||
|
||||
func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||
if l.level > zapcore.DebugLevel {
|
||||
return
|
||||
}
|
||||
|
||||
elapsed := time.Since(begin)
|
||||
sql, rows := fc()
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.String("sql", l.formatSQL(sql)),
|
||||
zap.Int64("rows", rows),
|
||||
zap.Duration("latency", elapsed),
|
||||
}
|
||||
|
||||
if requestIDField := RequestIDFromContext(ctx); requestIDField != zap.Skip() {
|
||||
fields = append([]zap.Field{requestIDField}, fields...)
|
||||
}
|
||||
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
fields = append(fields, zap.Error(err))
|
||||
l.logger.Error("SQL执行错误", fields...)
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.Debug("SQL查询", fields...)
|
||||
}
|
||||
|
||||
func (l *GormLogger) log(ctx context.Context, level zapcore.Level, msg string, data ...interface{}) {
|
||||
fields := make([]zap.Field, 0, len(data)/2+1)
|
||||
|
||||
if requestIDField := RequestIDFromContext(ctx); requestIDField != zap.Skip() {
|
||||
fields = append(fields, requestIDField)
|
||||
}
|
||||
|
||||
for i := 0; i < len(data); i += 2 {
|
||||
if i+1 < len(data) {
|
||||
key, ok := data[i].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
fields = append(fields, zap.Any(key, data[i+1]))
|
||||
}
|
||||
}
|
||||
|
||||
switch level {
|
||||
case zapcore.DebugLevel:
|
||||
l.logger.Debug(fmt.Sprintf(msg, data...), fields...)
|
||||
case zapcore.WarnLevel:
|
||||
l.logger.Warn(fmt.Sprintf(msg, data...), fields...)
|
||||
case zapcore.ErrorLevel:
|
||||
l.logger.Error(fmt.Sprintf(msg, data...), fields...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GormLogger) gormLevelToZap(level gormlogger.LogLevel) zapcore.Level {
|
||||
switch level {
|
||||
case gormlogger.Silent:
|
||||
return zapcore.PanicLevel
|
||||
case gormlogger.Error:
|
||||
return zapcore.ErrorLevel
|
||||
case gormlogger.Warn:
|
||||
return zapcore.WarnLevel
|
||||
case gormlogger.Info:
|
||||
return zapcore.DebugLevel
|
||||
default:
|
||||
return zapcore.DebugLevel
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GormLogger) formatSQL(sql string) string {
|
||||
re := regexp.MustCompile(`\s+`)
|
||||
return strings.TrimSpace(re.ReplaceAllString(sql, " "))
|
||||
}
|
||||
Reference in New Issue
Block a user