序
本文主要研究一下gorm的logger
logger
gorm.io/gorm@v1.20.10/logger/logger.go
代码语言:javascript复制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
代码语言:javascript复制func New(writer Writer, config Config) Interface {
var (
infoStr = "%sn[info] "
warnStr = "%sn[warn] "
errStr = "%sn[error] "
traceStr = "%sn[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %sn[%.3fms] [rows:%v] %s"
traceErrStr = "%s %sn[%.3fms] [rows:%v] %s"
)
if config.Colorful {
infoStr = Green "%sn" Reset Green "[info] " Reset
warnStr = BlueBold "%sn" Reset Magenta "[warn] " Reset
errStr = Magenta "%sn" Reset Red "[error] " Reset
traceStr = Green "%sn" Reset Yellow "[%.3fms] " BlueBold "[rows:%v]" Reset " %s"
traceWarnStr = Green "%s " Yellow "%sn" Reset RedBold "[%.3fms] " Yellow "[rows:%v]" Magenta " %s" Reset
traceErrStr = RedBold "%s " MagentaBold "%sn" 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
代码语言:javascript复制// 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
代码语言:javascript复制// 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
代码语言:javascript复制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
代码语言:javascript复制func (c *callback) Remove(name string) error {
c.processor.db.Logger.Warn(context.Background(), "removing callback `%v` from %vn", 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 %vn", 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进行打印
实例
代码语言:javascript复制func loggerDemo() {
newLogger := logger.New(
log.New(os.Stdout, "rn", 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)
}
输出
代码语言:javascript复制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