竹简文档
日志系统

GORM 集成

SlogLogger 适配器将 GORM 日志输出到 slog

GORM 集成

SlogLogger 是 GORM 日志适配器,实现 gorm.io/gorm/logger.Interface 接口,将数据库操作日志输出到 slog。

SlogLogger

gorm.go
type SlogLogger struct {
    logger                    *slog.Logger
    config                    GormLoggerConfig
    slowThreshold             time.Duration
    logLevel                  LogLevel
    ignoreRecordNotFoundError bool
}

GormLoggerConfig

gorm.go
type GormLoggerConfig struct {
    SlowThreshold             int      // 慢查询阈值(毫秒),超过此值以 WARN 级别记录
    LogLevel                  LogLevel // 日志级别
    IgnoreRecordNotFoundError bool     // 是否忽略 ErrRecordNotFound 错误
    Colorful                  bool     // 是否启用彩色输出(预留字段)
}

配置说明

字段

类型

日志级别

gorm.go
type LogLevel int

const (
    LevelSilent LogLevel = iota + 1  // 静默模式,不输出任何日志
    LevelError                        // 仅输出错误日志
    LevelWarn                         // 输出错误和警告日志
    LevelInfo                         // 输出所有级别日志(包括 SQL 语句)
)

字段

类型

NewSlogLogger

创建 GORM slog 日志适配器:

gorm.go
func NewSlogLogger(slogger *slog.Logger, config GormLoggerConfig) logger.Interface

参数说明:

  • slogger: slog.Logger 实例,推荐使用 slog.Default().WithGroup(xLog.NamedREPO)
  • config: GORM Logger 配置

示例:

gormLogger := xLog.NewSlogLogger(
    slog.Default().WithGroup(xLog.NamedREPO),
    xLog.GormLoggerConfig{
        SlowThreshold:             200,            // 200ms 慢查询阈值
        LogLevel:                  xLog.LevelInfo, // 日志级别
        IgnoreRecordNotFoundError: true,           // 忽略记录未找到错误
    },
)

日志输出规则

SQL 追踪

Trace 方法根据执行情况输出不同级别的日志:

gorm.go
func (l *SlogLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
    switch {
    // 执行出错 → ERROR 级别
    case err != nil && l.logLevel >= LevelError:
        l.logger.LogAttrs(ctx, slog.LevelError, "执行SQL语句失败", ...)

    // 慢查询 → WARN 级别
    case elapsed > l.slowThreshold && l.logLevel >= LevelWarn:
        l.logger.LogAttrs(ctx, slog.LevelWarn, "发现SQL慢查询", ...)

    // 普通查询 → DEBUG 级别
    case l.logLevel >= LevelInfo:
        l.logger.LogAttrs(ctx, slog.LevelDebug, "成功执行SQL语句", ...)
    }
}

日志属性

每条 SQL 日志包含以下属性:

字段

类型

使用示例

基础集成

register_database.go
func (r *Reg) DatabaseInit() {
    dsn := "host=localhost user=postgres dbname=myapp"

    // 创建 GORM Logger
    gormLogger := xLog.NewSlogLogger(
        slog.Default().WithGroup(xLog.NamedREPO),
        xLog.GormLoggerConfig{
            SlowThreshold:             200,
            LogLevel:                  xLog.LevelInfo,
            IgnoreRecordNotFoundError: true,
        },
    )

    // 连接数据库
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
        Logger: gormLogger,
    })
    if err != nil {
        panic(err)
    }
}

环境区分

func createGormLogger(isDebug bool) logger.Interface {
    config := xLog.GormLoggerConfig{
        SlowThreshold:             200,
        IgnoreRecordNotFoundError: true,
    }

    if isDebug {
        config.LogLevel = xLog.LevelInfo  // 开发环境:输出所有 SQL
    } else {
        config.LogLevel = xLog.LevelWarn  // 生产环境:仅输出警告和错误
    }

    return xLog.NewSlogLogger(
        slog.Default().WithGroup(xLog.NamedREPO),
        config,
    )
}

链路追踪

GORM 操作自动继承 Context 中的 Trace ID:

repository/user.go
func (r *UserRepo) FindByID(ctx context.Context, id int64) (*entity.User, error) {
    var user entity.User
    // WithContext 传递 Trace ID,日志会自动关联
    err := r.db.WithContext(ctx).First(&user, id).Error
    return &user, err
}

日志输出:

2024-01-15 10:30:00.123 [DEBU] [abc123] [REPO] 成功执行SQL语句
    elapsed_ms=1.234
    rows=1
    sql=SELECT * FROM users WHERE id = 12345 LIMIT 1

慢查询监控

// 设置较低的阈值以捕获更多慢查询
gormLogger := xLog.NewSlogLogger(
    slog.Default().WithGroup(xLog.NamedREPO),
    xLog.GormLoggerConfig{
        SlowThreshold: 100, // 100ms
        LogLevel:      xLog.LevelWarn,
    },
)

慢查询日志:

2024-01-15 10:30:00.123 [WARN] [abc123] [REPO] 发现SQL慢查询
    elapsed_ms=156.789
    rows=1000
    sql=SELECT * FROM orders WHERE created_at > '2024-01-01'
    threshold=100ms

完整示例

startup/startup_database.go
package startup

import (
    "log/slog"
    "os"

    xLog "github.com/bamboo-services/bamboo-base-go/common/log"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

func InitDatabase() *gorm.DB {
    dsn := os.Getenv("DATABASE_URL")
    isDebug := os.Getenv("APP_ENV") == "development"

    // 根据环境配置日志级别
    logLevel := xLog.LevelWarn
    if isDebug {
        logLevel = xLog.LevelInfo
    }

    gormLogger := xLog.NewSlogLogger(
        slog.Default().WithGroup(xLog.NamedREPO),
        xLog.GormLoggerConfig{
            SlowThreshold:             200,
            LogLevel:                  logLevel,
            IgnoreRecordNotFoundError: true,
        },
    )

    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
        Logger: gormLogger,
    })
    if err != nil {
        panic(err)
    }

    return db
}

下一步

On this page