猿问

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

我用自定义的编码器替换了我的 uber-zap 记录器的编码器,以在每个日志条目前加上 SystemD 友好的错误级别 ( <LEVEL>),但是现在在我使用带有附加字段 ( With(fields ...Field)) 的记录器后,自定义的前置就消失了:

package main


import (

    "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 EncodeEntry

func (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 function

func (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 warn

1.6406561307566311e+09  info    this does not have the prefix :(    {"foo": "bar"}

我究竟做错了什么?


ibeautiful
浏览 126回答 1
1回答

沧海一幻觉

您还必须Clone()从zapcore.Encoder接口实现。如果您希望保持父记录器不变,则必须构建一个实际的克隆——可能具有相同的配置,因此您可能希望将其存储为一个字段:type prependEncoder struct {&nbsp; &nbsp; zapcore.Encoder&nbsp; &nbsp; pool buffer.Pool&nbsp; &nbsp; cfg&nbsp; zapcore.EncoderConfig}func (e *prependEncoder) Clone() zapcore.Encoder {&nbsp; &nbsp; return &prependEncoder{&nbsp; &nbsp; &nbsp; &nbsp; // cloning the encoder with the base config&nbsp; &nbsp; &nbsp; &nbsp; Encoder: zapcore.NewConsoleEncoder(e.cfg),&nbsp; &nbsp; &nbsp; &nbsp; pool:&nbsp; &nbsp; buffer.NewPool(),&nbsp; &nbsp; &nbsp; &nbsp; cfg:&nbsp; &nbsp; &nbsp;e.cfg,&nbsp; &nbsp; }}如果你不实现它,运行的方法是调用时下一个最浅的方法logger.Clone(),它是Clone()在嵌入的声明的zapcore.Encoder。那一个就没有你的习惯EncodeEntry了。现在运行以下命令:&nbsp; &nbsp; logger.Info("this is info")&nbsp; &nbsp; logger.Debug("this is debug")&nbsp; &nbsp; logger.Warn("this is warn")&nbsp; &nbsp; child := logger.With(zap.String("foo", "bar"))&nbsp; &nbsp; logger.Warn("original")&nbsp; &nbsp; child.Info("new one")输出:<6> INFO&nbsp; &nbsp; &nbsp; &nbsp; this is info<7> DEBUG&nbsp; &nbsp; &nbsp; &nbsp;this is debug<4> WARN&nbsp; &nbsp; &nbsp; &nbsp; this is warncloning...<4> WARN&nbsp; &nbsp; &nbsp; &nbsp; original<6> INFO&nbsp; &nbsp; &nbsp; &nbsp; new one {"foo": "bar"}
随时随地看视频慕课网APP

相关分类

Go
我要回答