You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zerolog钩子未注册:日志级别高于警告时钩子不触发

Zerolog自定义AlertHook未触发问题排查

问题描述

实现了自定义AlertHook,期望当日志级别高于WarnLevel时触发alert函数打印内容,但错误日志能正常输出,alert函数无任何打印。

代码片段

Hook定义与日志初始化

type AlertHook struct{}

func (t *AlertHook) Run(e *zerolog.Event, level zerolog.Level, message string) {
    if level > zerolog.WarnLevel {
        _ = alert(message)
    }
}

func alert(msg string) error {
    fmt.Println(msg)
    return nil
}

var once sync.Once
var log zerolog.Logger

func Get() zerolog.Logger {
    once.Do(func() {
        zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
        zerolog.TimeFieldFormat = time.RFC3339Nano

        logLevel, err := strconv.Atoi(os.Getenv("LOG_LEVEL"))
        if err != nil {
            logLevel = int(zerolog.InfoLevel) // default to INFO
        }

        var output io.Writer = zerolog.ConsoleWriter{
            Out:        os.Stdout,
            TimeFormat: time.RFC3339,
        }

        if os.Getenv("APP_ENV") != "development" {
            fileLogger := &lumberjack.Logger{
                Filename:   "service.log",
                MaxSize:    5,
                MaxBackups: 10,
                MaxAge:     14,
                Compress:   true,
            }

            output = zerolog.MultiLevelWriter(os.Stderr, fileLogger)
        }

        var gitRevision string
        buildInfo, ok := debug.ReadBuildInfo()
        if ok {
            for _, v := range buildInfo.Settings {
                if v.Key == "vcs.revision" {
                    gitRevision = v.Value
                    break
                }
            }
        }

        log = zerolog.New(output).
            Level(zerolog.Level(logLevel)).
            With().
            Timestamp().
            Str("git_revision", gitRevision).
            Str("go_version", buildInfo.GoVersion).
            Logger()
    })
    log.Hook(&AlertHook{})
    return log
}

测试代码

// CreateClientHandler is the handler for creating a new client.
// It is used to create a new client.
func CreateClientHandler(si *server.ServerInstance) fiber.Handler {
    return func(c *fiber.Ctx) error {
        l := logs.Get()
        l.Error().Msg("test error") // SHOULD TRIGGER HOOK
        o := new(models.APIClientUser)

        if err := c.BodyParser(o); err != nil {
            return c.Status(fiber.StatusBadRequest).JSON(models.NewErrorBadRequest(&err))
        }

        result := si.DB.ORM.Create(&o)
        if result.Error != nil {
            return c.Status(fiber.StatusBadRequest).JSON(models.NewErrorBadRequest(&result.Error))
        }

        return c.Status(fiber.StatusCreated).JSON(models.NewSuccessCreated(o))
    }
}

问题根源

Zerolog的Logger是不可变对象,所有修改Logger配置的方法(包括Hook())都会返回一个新的Logger实例,而非修改原有实例。

在Get()函数中,log.Hook(&AlertHook{})创建了带Hook的新Logger,但你既没有将这个新实例赋值给全局log变量,也没有返回该新实例——最终返回的还是初始化时不带Hook的原log变量,导致Hook从未真正绑定到你使用的Logger上。

修复方案

方案1:初始化时直接添加Hook(推荐)

将Hook整合到初始化流程中,确保全局Logger从一开始就带有Hook:

log = zerolog.New(output).
    Level(zerolog.Level(logLevel)).
    With().
    Timestamp().
    Str("git_revision", gitRevision).
    Str("go_version", buildInfo.GoVersion).
    Logger().
    Hook(&AlertHook{}) // 在此处添加Hook

方案2:返回带Hook的新实例

如果需要动态添加Hook(不推荐,全局初始化一次即可),需将Hook()返回的新Logger赋值并返回:

once.Do(...)
// 创建带Hook的新Logger并返回
return log.Hook(&AlertHook{})

额外验证

你的级别判断level > zerolog.WarnLevel是正确的,Zerolog级别优先级为:TraceLevel < DebugLevel < InfoLevel < WarnLevel < ErrorLevel < FatalLevel < PanicLevel,Error()级别确实满足触发条件。

内容的提问来源于stack exchange,提问作者rak1n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:55:35