聊聊gorm的logger

2021-01-25 10:45:48 浏览数 (1)

本文主要研究一下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

0 人点赞