1
0
Files
nex/backend/pkg/logger/gorm.go
lanyuanxiaoyao 280099b89c refactor: 后端日志系统重构
- 新增模块化日志器(pkg/logger/module.go)
- 新增 GORM 日志适配器
- 统一日志入口,移除所有 zap.L() 全局 logger 调用
- 字段标准化
- 启动阶段使用结构化日志
- 更新所有相关测试
2026-04-23 18:37:51 +08:00

131 lines
2.9 KiB
Go

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