如何复制输入密钥并将其显示在与 Uber Zap 相同的日志中?

How can I duplicate entry keys and show it in the same log with Uber Zap?

我想用另一个键名 method 复制条目键 caller 并在日志中显示两者...

{"level":"error", "caller: "testing/testing.go:1193", "method": "testing/testing.go:1193", "message": "foo"}

有什么想法吗?

您无法更改 zapcore.Entry 的字段。您 可以 更改它的编组方式,但老实说,将 ghost 字段添加到结构是一个糟糕的 hack。您可以做的是使用自定义编码器,并向 []zapcore.Field 附加一个带有调用者副本的新字符串项。特别是,JSON 编码器的默认输出是从 Caller.TrimmedPath():

获得的
type duplicateCallerEncoder struct {
    zapcore.Encoder
}

func (e *duplicateCallerEncoder) Clone() zapcore.Encoder {
    return &duplicateCallerEncoder{Encoder: e.Encoder.Clone()}
}

func (e *duplicateCallerEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
    // appending to the fields list
    fields = append(fields, zap.String("method", entry.Caller.TrimmedPath()))
    return e.Encoder.EncodeEntry(entry, fields)
}

注意上面的实现Encoder.Clone()。详情见此:

然后您可以通过构建新的 Zap 核心或注册自定义编码器来使用它。已注册的构造函数将 JSONEncoder 嵌入到您的自定义编码器中,这是生产记录器的默认编码器:

func init() {
    // name is whatever you like
    err := zap.RegisterEncoder("duplicate-caller", func(config zapcore.EncoderConfig) (zapcore.Encoder, error) {
        return &duplicateCallerEncoder{Encoder: zapcore.NewJSONEncoder(config)}, nil
    })
    // it's reasonable to panic here, since the program can't initialize
    if err != nil {
        panic(err)
    }
}

func main() {
    cfg := zap.NewProductionConfig()
    cfg.Encoding = "duplicate-caller"
    logger, _ := cfg.Build()
    logger.Info("this is info")
}

以上内容使用您的自定义配置复制了生产记录器的初始化。

对于如此简单的配置,我更喜欢 init()zap.RegisterEncoder 的方法。如果需要,它可以更快地重构代码,and/or 如果您将它放在其他包中开始。您当然可以在main()中进行注册;或者如果您需要额外的定制,那么您可以使用 zap.New(zapcore.NewCore(myCustomEncoder, /* other args */))

你可以在这个游乐场看到完整的程序:https://go.dev/play/p/YLDXbdZ-qZP

它输出:

{"level":"info","ts":1257894000,"caller":"sandbox3965111040/prog.go:24","msg":"this is info","method":"sandbox3965111040/prog.go:24"}