序
本文次要钻研一下 gorm 的 logger
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 属性
logger.New
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
// 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
// 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 办法
Session.Logger
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
callback
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 办法。
doc
- gorm