聊聊gorm的logger

本文主要研究一下gorm的logger

logger

gorm.io/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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: 
2021/01/10 23:32:42 {ID:6 Name:Tom Age:18 Birthday:2021-01-10 23:32:42.818057 +0800 +0800 DeletedAt: 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

你可能感兴趣的:(golang)