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

使用 zap logger 将 protobuf 消息记录为未转义的 JSON 格式

使用 zap logger 将 protobuf 消息记录为未转义的 JSON 格式

Go
侃侃无极 2022-09-12 20:51:45
我有一个Go项目,我使用Zap结构化日志记录来记录结构的内容。这就是我初始化记录器的方式:zapLog, err := zap.NewProductionConfig().Build()if err != nil {    panic(err)}最初,我从我自己的结构开始,带有json标签,一切都很完美:zapLog.Info("Event persisted", zap.Any("event", &event))结果:{"level":"info","ts":1626448680.69099,"caller":"persisters/log.go:56", "msg":"Event persisted","event":{"sourceType":4, "sourceId":"some-source-id",  "type":"updated", "value":"{...}", "context":{"foo":"bar"}}}我现在切换到原型布夫,我正在努力实现相同的结果。最初,在使用zap时,我只是得到了“反射地图”版本。任何():zapLog.Info("Event persisted", zap.Any("event", &event)){"level":"info","ts":1626448680.69099,"caller":"persisters/log.go:56", "msg":"Event persisted","event":"sourceType:TYPE_X sourceId:\"some-source-id\",  type:\"updated\" value:{...}, context:<key: foo, value:bar>}我尝试使用 jsonpb 编组器对对象进行编组,该编组器在自身上生成了正确的输出,但是,当我在 中使用它时,字符串被转义,因此我在每个引号前面得到一组额外的“\”。由于稍后会处理日志,因此这会导致问题,因此我想避免它:zap.String()m := jsonpb.Marshaler{}var buf bytes.Bufferif err := m.Marshal(&buf, msg); err != nil {    // handle error}zapLog.Info("Event persisted", zap.ByteString("event", buf.Bytes()))结果:{"level":"info","ts":1626448680.69099,"caller":"persisters/log.go:56", "msg":"Event persisted","event":"{\"sourceType\":\"TYPE_X\", \"sourceId\":\"some-source-id\",  \"type\":\"updated\", \"value\":\"{...}\", \"context\":{\"foo\":"bar\"}}"}然后,我尝试使用最接近我需要的东西来代替它,除了枚举被渲染为它们的数值(初始解没有枚举,所以这在protobuf之前的解决方案中也不起作用):zap.Reflect()zap.Any()zapLog.Info("Event persisted", zap.Reflect("event", &event))结果:{"level":"info","ts":1626448680.69099,"caller":"persisters/log.go:56", "msg":"Event persisted","event":{"sourceType":4, "sourceId":"some-source-id",  "type":"updated", "value":"{...}", "context":{"foo":"bar"}}}到目前为止,我看到的唯一选择是编写自己的函数:MarshalLogObject()但是由于它是一个复杂的结构,我宁愿使用一个不易出错和维护较重的解决方案。理想情况下,我会告诉zap以某种方式使用jsonpb编组器,但我不知道这是否可能。
查看完整描述

2 回答

?
杨魅力

TA贡献1811条经验 获得超6个赞

使用扎普。任何带有 json 的内容。原始消息。您可以直接转换 的字节输出:jsonpb.Marshaler


 foo := &pb.FooMsg{

        Foo: "blah", 

        Bar:  1,

    }


    m := jsonpb.Marshaler{}

    var buf bytes.Buffer

    if err := m.Marshal(&buf, foo); err != nil {

        // handle error

    }


    logger, _ := zap.NewDevelopment()

    logger.Info("Event persisted", zap.Any("event", json.RawMessage(buf.Bytes())))

字节将打印为:


事件持久 {“事件”: {“foo”:“blah”,“bar”:“1”}}'


我相信这是最简单的方法,但是我也知道一个包卡泽古苏里/go-proto-zap-marshaler(我不隶属于它),它生成实现作为原型插件。您可能也想看看。MarshalLogObject()


查看完整回答
反对 回复 2022-09-12
?
慕勒3428872

TA贡献1848条经验 获得超6个赞

我使用了另一种方法来 json 化原型。


由于原型可以自然地封送,我只是将它们包装在严格到json的封送处理器中。


您可以修改内部结构以使用原型(较新的 jsonpb)。


与上一个解决方案中的封送处理器不同,此封送处理程序不需要预先记录处理。



type jsonObjectMarshaler struct {

    obj  any

}


func (j *jsonObjectMarshaler) MarshalJSON() ([]byte, error) {

    bytes, err := json.Marshal(j.obj)

    // bytes, err := protojson.Marshal(j.obj)

    if err != nil {

        return nil, fmt.Errorf("json marshaling failed: %w", err)

    }

    return bytes, nil

}


func ZapJsonable(key string, obj any) zap.Field {

    return zap.Reflect(key, &jsonObjectMarshaler{obj: obj})

}

然后使用它,只是


logger, _ := zap.NewDevelopment()

logger.Info("Event persisted", ZapJsonable("event", buf))


查看完整回答
反对 回复 2022-09-12
  • 2 回答
  • 0 关注
  • 343 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号