为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在 Uber Zap 中调用 logger.With 后自定义编码会丢失?

为什么在 Uber Zap 中调用 logger.With 后自定义编码会丢失?

Go
ibeautiful 2022-10-24 09:20:53
我用自定义的编码器替换了我的 uber-zap 记录器的编码器,以在每个日志条目前加上 SystemD 友好的错误级别 ( <LEVEL>),但是现在在我使用带有附加字段 ( With(fields ...Field)) 的记录器后,自定义的前置就消失了:package mainimport (    "os"    "go.uber.org/zap"    "go.uber.org/zap/buffer"    "go.uber.org/zap/zapcore")func getConfig() zap.Config {    // your current config options    return zap.NewProductionConfig()}type prependEncoder struct {    // embed a zapcore encoder    // this makes prependEncoder implement the interface without extra work    zapcore.Encoder    // zap buffer pool    pool buffer.Pool}// EncodeEntry implementing only EncodeEntryfunc (e *prependEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {    // new log buffer    buf := e.pool.Get()    // prepend the JournalD prefix based on the entry level    buf.AppendString(e.toJournaldPrefix(entry.Level))    buf.AppendString(" ")    // calling the embedded encoder's EncodeEntry to keep the original encoding format    consolebuf, err := e.Encoder.EncodeEntry(entry, fields)    if err != nil {        return nil, err    }    // just write the output into your own buffer    _, err = buf.Write(consolebuf.Bytes())    if err != nil {        return nil, err    }    return buf, nil}// some mapper functionfunc (e *prependEncoder) toJournaldPrefix(lvl zapcore.Level) string {    switch lvl {    case zapcore.DebugLevel:        return "<7>"    case zapcore.InfoLevel:        return "<6>"    case zapcore.WarnLevel:        return "<4>"    }    return ""}func main() {    cfg := getConfig()    // constructing our prependEncoder with a ConsoleEncoder using your original configs    enc := &prependEncoder{        Encoder: zapcore.NewConsoleEncoder(cfg.EncoderConfig),        pool:    buffer.NewPool(),    }我得到的输出是:<6> 1.640656130756576e+09   info    this is info<7> 1.640656130756611e+09   debug   this is debug<4> 1.640656130756615e+09   warn    this is warn1.6406561307566311e+09  info    this does not have the prefix :(    {"foo": "bar"}我究竟做错了什么?
查看完整描述

1 回答

?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

您还必须Clone()从zapcore.Encoder接口实现。如果您希望保持父记录器不变,则必须构建一个实际的克隆——可能具有相同的配置,因此您可能希望将其存储为一个字段:


type prependEncoder struct {

    zapcore.Encoder

    pool buffer.Pool

    cfg  zapcore.EncoderConfig

}


func (e *prependEncoder) Clone() zapcore.Encoder {

    return &prependEncoder{

        // cloning the encoder with the base config

        Encoder: zapcore.NewConsoleEncoder(e.cfg),

        pool:    buffer.NewPool(),

        cfg:     e.cfg,

    }

}

如果你不实现它,运行的方法是调用时下一个最浅的方法logger.Clone(),它是Clone()在嵌入的声明的zapcore.Encoder。那一个就没有你的习惯EncodeEntry了。


现在运行以下命令:


    logger.Info("this is info")

    logger.Debug("this is debug")

    logger.Warn("this is warn")

    child := logger.With(zap.String("foo", "bar"))

    logger.Warn("original")

    child.Info("new one")

输出:


<6> INFO        this is info

<7> DEBUG       this is debug

<4> WARN        this is warn

cloning...

<4> WARN        original

<6> INFO        new one {"foo": "bar"}


查看完整回答
反对 回复 2022-10-24
  • 1 回答
  • 0 关注
  • 78 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信