竹简文档
日志系统

自定义 Handler

LogHandler 实现双通道输出,支持彩色控制台和 JSON 文件

自定义 Handler

LogHandler 是基于 slog.Handler 接口的自定义实现,支持控制台彩色输出和文件 JSON 输出双通道。

LogHandler

handler.go
type LogHandler struct {
    opts        slog.HandlerOptions
    mu          *sync.Mutex
    console     io.Writer
    file        io.Writer
    group       string // logger 名称(通过 WithGroup 设置)
    attrs       []slog.Attr
    isDebugMode bool
}

HandlerConfig

handler.go
type HandlerConfig struct {
    Console     io.Writer  // 控制台输出(可选,默认 os.Stdout)
    File        io.Writer  // 文件输出(可选)
    Level       slog.Level // 日志级别
    IsDebugMode bool       // 是否调试模式
}

配置说明

字段

类型

NewLogHandler

创建自定义 slog Handler:

handler.go
func NewLogHandler(config HandlerConfig) slog.Handler

示例:

handler := xLog.NewLogHandler(xLog.HandlerConfig{
    Console:     os.Stdout,
    File:        rotator,           // RotatingWriter 实例
    Level:       slog.LevelDebug,
    IsDebugMode: true,
})

slog.SetDefault(slog.New(handler))

双通道输出

控制台输出

彩色格式,便于开发调试:

2024-01-15 10:30:00.123 [INFO] [abc123] [CORE] [DB] [Redis] >> 服务启动成功
    config=production
    port=8080

格式说明:

部分说明颜色
时间戳2006-01-02 15:04:05.000灰色
日志级别[DEBU] [INFO] [WARN] [ERRO]见下表
Trace ID请求追踪标识蓝色
Logger 名称主模块标识按类别着色
Option 名称额外命名空间青色(高亮)
消息日志内容默认色,前缀 >>
属性key=value 格式棕色

文件输出

JSON 格式,便于日志分析:

{
  "time": "2024-01-15T10:30:00.123456789+08:00",
  "level": "INFO",
  "message": "服务启动成功",
  "trace": "abc123",
  "logger": "CORE",
  "config": "production",
  "port": 8080
}

日志级别颜色

字段

类型

Logger 名称颜色

不同类别的命名常量显示不同颜色:

类别颜色包含常量
核心服务类蓝色CONT, SERV, LOGC, REPO, CORE, BASE, MAIN
路由网络类黄色ROUT, HTTP, GRPC, SOCK, CONN, LINK
安全认证类红色AUTH, USER, PERM, ROLE, TOKN, SIGN
业务逻辑类白色BUSI, PROC, FLOW, TASK, JOBS
其他已定义橙色RECO, UTIL, FILT, MIDE, VALD, INIT, THOW, RESU
未定义紫色其他自定义名称

Trace ID 提取

Handler 自动从 Context 中提取 Trace ID:

handler.go
func (h *LogHandler) extractContextUUID(ctx context.Context) string {
    // 1. 从 gin.Context 提取
    if ginCtx, ok := ctx.(*gin.Context); ok {
        if contextUUID, exists := ginCtx.Get(string(xCtx.RequestKey)); exists {
            return contextUUID.(string)
        }
    }

    // 2. 从标准 context.Context 提取(包括 GORM 场景)
    if contextUUID := ctx.Value(xCtx.RequestKey); contextUUID != nil {
        return contextUUID.(string)
    }

    return ""
}

支持的 Context 类型:

  • *gin.Context - HTTP 请求场景
  • context.Context - 标准 Context(包括 GORM 数据库操作)

错误堆栈

ERROR 级别日志自动附加堆栈信息:

// 错误级别添加堆栈
if r.Level >= slog.LevelError {
    buf.WriteString(h.getStack())
}

输出示例:

2024-01-15 10:30:00.123 [ERRO] [abc123] [REPO] 数据库连接失败
    error=connection refused
goroutine 1 [running]:
github.com/bamboo-services/bamboo-base-go/log.(*LogHandler).getStack(...)
    /path/to/handler.go:310
...

完整初始化示例

register_logger.go
func (r *Reg) LoggerInit() {
    // 1. 创建日志切割器
    rotator, err := xLog.NewRotatingWriter(xLog.RotatorConfig{
        Dir:      ".logs",
        BaseName: "log",
        Ext:      ".log",
        MaxSize:  10 * 1024 * 1024,
    })
    if err != nil {
        panic(err)
    }

    // 2. 创建自定义 Handler
    handler := xLog.NewLogHandler(xLog.HandlerConfig{
        Console:     os.Stdout,
        File:        rotator,
        Level:       slog.LevelDebug,
        IsDebugMode: true,
    })

    // 3. 设置为全局默认 Logger
    slog.SetDefault(slog.New(handler))
}

下一步

On this page