本文主要研究一下gorm的logger
gorm.io/gorm@v1.20.10/logger/logger.go
type logger struct { Writer Config infoStr, warnStr, errStr string traceStr, traceErrStr, traceWarnStr string } type Writer interface { Printf(string, ...interface{}) } type Config struct { SlowThreshold time.Duration Colorful bool LogLevel LogLevel }
logger内嵌了Writer、Config、定义了info、warn、err、trace、traceErr、traceWarn属性
gorm.io/gorm@v1.20.10/logger/logger.go
func New(writer Writer, config Config) Interface { var ( infoStr = "%s\n[info] " warnStr = "%s\n[warn] " errStr = "%s\n[error] " traceStr = "%s\n[%.3fms] [rows:%v] %s" traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s" traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s" ) if config.Colorful { infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s" traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s" } return &logger{ Writer: writer, Config: config, infoStr: infoStr, warnStr: warnStr, errStr: errStr, traceStr: traceStr, traceWarnStr: traceWarnStr, traceErrStr: traceErrStr, } }
logger.New根据config来创建logger
// Interface logger interface type Interface interface { LogMode(LogLevel) Interface Info(context.Context, string, ...interface{}) Warn(context.Context, string, ...interface{}) Error(context.Context, string, ...interface{}) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) }
logger.Interface接口定义了LogMode、Info、Warn、Error、Trace方法
// LogMode log mode func (l *logger) LogMode(level LogLevel) Interface { newlogger := *l newlogger.LogLevel = level return &newlogger } // Info print info func (l logger) Info(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Info { l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Warn print warn messages func (l logger) Warn(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Warn { l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Error print error messages func (l logger) Error(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Error { l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Trace print sql message func (l logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { if l.LogLevel > Silent { elapsed := time.Since(begin) switch { case err != nil && l.LogLevel >= Error: sql, rows := fc() if rows == -1 { l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql) } else { l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql) } case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= Warn: sql, rows := fc() slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold) if rows == -1 { l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql) } else { l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql) } default: sql, rows := fc() if rows == -1 { l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql) } else { l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql) } } } }
logger实现了logger.Interface接口定义的LogMode、Info、Warn、Error、Trace方法
gorm.io/gorm@v1.20.10/gorm.go
type Session struct { DryRun bool PrepareStmt bool NewDB bool SkipHooks bool SkipDefaultTransaction bool DisableNestedTransaction bool AllowGlobalUpdate bool FullSaveAssociations bool QueryFields bool Context context.Context Logger logger.Interface NowFunc func() time.Time CreateBatchSize int }
Logger定义了Logger属性,最后设置到DB.Logger
gorm.io/gorm@v1.20.10/callbacks.go
func (c *callback) Remove(name string) error { c.processor.db.Logger.Warn(context.Background(), "removing callback `%v` from %v\n", name, utils.FileWithLineNum()) c.name = name c.remove = true c.processor.callbacks = append(c.processor.callbacks, c) return c.processor.compile() } func (c *callback) Replace(name string, fn func(*DB)) error { c.processor.db.Logger.Info(context.Background(), "replacing callback `%v` from %v\n", name, utils.FileWithLineNum()) c.name = name c.handler = fn c.replace = true c.processor.callbacks = append(c.processor.callbacks, c) return c.processor.compile() }
callback的Remove、Replace等方法会使用db.Logger进行打印
func loggerDemo() { newLogger := logger.New( log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer logger.Config{ SlowThreshold: time.Second, // 慢 SQL 阈值 LogLevel: logger.Silent, // Log level Colorful: true, // 彩色打印 }, ) // 全局模式 db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{ Logger: newLogger, }) if err != nil { panic(err) } if err := db.AutoMigrate(&User{}); err != nil { panic(err) } // 新建会话模式 tx := db.Session(&gorm.Session{Logger: newLogger}) user := User{Name: "Tom", Age: 18, Birthday: time.Now()} result := db.Create(&user) // pass pointer of data to Create log.Println("userId:", user.ID) log.Println("result.RowsAffected:", result.RowsAffected, "result.Error:", result.Error) tx.First(&user) log.Printf("%+v", user) tx.Model(&user).Update("Age", 18) }
输出
2021/01/10 23:32:42 userId: 6 2021/01/10 23:32:42 result.RowsAffected: 1 result.Error: <nil> 2021/01/10 23:32:42 {ID:6 Name:Tom Age:18 Birthday:2021-01-10 23:32:42.818057 +0800 +0800 DeletedAt:<nil> CreatedAt:2021-01-10 23:32:42.818107 +0800 +0800 UpdatedAt:2021-01-10 23:32:42.818107 +0800 +0800}
gorm的logger提供了Interface接口,可以自己实现并全局设置或者在session级别设置;gorm默认的logger实现了logger.Interface接口定义的LogMode、Info、Warn、Error、Trace方法。