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

     2023-02-18     36

关键词:

【中文标题】使用 zap logger 将 protobuf 消息正确记录为未转义的 JSON【英文标题】:Correctly log protobuf messages as unescaped JSON with zap logger 【发布时间】:2021-09-25 10:11:35 【问题描述】:

我有一个 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"

我现在切换到 protobuf 并且我正在努力实现相同的结果。最初,我在使用 zap.Any() 时获得了“反射地图”版本:

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 marshaller 对对象进行编组,这会在其自身上生成正确的输出,但是,当我在 zap.String() 中使用它时,字符串被转义,所以我在前面得到了一组额外的 '\'每个引号。由于稍后会处理日志,这会导致那里出现问题,因此我想避免它:

m := jsonpb.Marshaler
var buf bytes.Buffer
if 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\""

然后我尝试使用 zap.Reflect() 而不是 zap.Any() 这是我能得到的最接近我需要的东西,除了枚举被呈现为它们的数值(初始解决方案没有枚举,所以没有也不能在 pre-protobuf 解决方案中工作):

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() 函数:

type ZapEvent struct 
    event *Event


func (z *ZapEvent) MarshalLogObject(encoder zapcore.ObjectEncoder) error 

  encoder.AddString("sourceType", z.event.SourceType.String()
  // implement encoder for each attribute



func processEvent(e Event) 
   ...
   zapLog.Info("Event persisted", zap.Object("event", &ZapEventevent: &e))

但由于它是一个复杂的结构,我宁愿使用不易出错且维护繁重的解决方案。理想情况下,我会告诉 zap 以某种方式使用 jsonpb 编组器,但我不知道这是否可能。

【问题讨论】:

【参考方案1】:

使用zap.Anyjson.RawMessage。可以直接转换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())))

字节将被打印为:

事件持续存在 "event": "foo":"blah","bar":"1"`

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

【讨论】:

太棒了!奇迹般有效。非常感谢!

Zap logger 打印到控制台和日志文件

...程序集成,我们将日志打印在两个日志文件中,并且我还使用Lumberjack进行日志轮换。但我也试图在控制台中显示日志,但这种情况没有运气。以下是我在logger.go中的代码var(Logger*zap.Logger 查看详情

golangzap快速上手(代码片段)

...,包括console、json、file等。zap性能比较优秀,它使用了ZeroAllocation的设计理念,在不影响性能的情况下尽量避免内存分配。2.zap快速上手1.安装Zap使用GolangZap需要先安装它。您可以使用goget命令从GitHub下载最新版本的Zap... 查看详情

如何在单元测试中正确捕获 zap logger 输出

】如何在单元测试中正确捕获zaplogger输出【英文标题】:Howtoproperlycapturezaploggeroutputinunittests【发布时间】:2022-01-2019:23:00【问题描述】:根据zap.NewDevelopmentConfig()和zap.NewProductionConfig()的配置,我假设zap将日志写入stderr。但是,... 查看详情

如何将钩子添加到 zap 记录器中?

...ogger?【发布时间】:2021-02-2410:35:41【问题描述】:我尝试使用WithOptions添加钩子,但没有打印任何内容来捕获一些日志事件:logger.WithOptions(zap.Hooks(func(entryzapcore.Entry)errorfmt.Println("testhookstesthooks")retur 查看详情

如何测试从自定义配置构建的 zap Logger 的日志记录?

】如何测试从自定义配置构建的zapLogger的日志记录?【英文标题】:HowtotestloggingofazapLoggerbuiltfromcustomConfig?【发布时间】:2019-03-1500:41:46【问题描述】:我有一个从自定义配置(即config.Build())生成的Zap记录器。我想通过在测试... 查看详情

zap简单使用(代码片段)

...的功能,当然,最显眼的还是他很快,本文介绍zap模块的基本使用正文zap的使用由编码器和初始化组成,编码器表示输出的格式,DEMO如下packagetoolimport( "go.uber.org/zap" "go.uber.org/zap/zapcore")//LogzapLog对象varLog*zap.Logger//编码器f... 查看详情

golang高性能日志库zap配置示例(代码片段)

...mport("go.uber.org/zap""time")funcmain()//zap.NewDevelopment格式化输出logger,_:=zap.NewDevelopment()deferlogger.Sync()logger.Info("无法获取网址",zap.String("url","http://www.baidu.com"),zap.Int("attempt",3),zap.Duration("backoff",time.Second),)格式化输出打印结果:2019-01-02T15:0... 查看详情

go语言项目中使用zap日志库(翻译)(代码片段)

本文先介绍了Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档。在Go语言项目中使用Uber-go的ZapLogger介绍在许多Go语言项目中,我们需要一个好的日志... 查看详情

从golog库到zap,怎么打造出好用又实用的logger(代码片段)

日志无论对于程序还是程序员都非常重要,有多重要呢,想要长期在公司健健康康的干下去就得学会阶段性划水,阶段性划水的一大关键的就是干活快过预期但是装作。。。不对,这个开头不对劲,下面重来... 查看详情

从golog库到zap,怎么打造出好用又实用的logger(代码片段)

日志无论对于程序还是程序员都非常重要,有多重要呢,想要长期在公司健健康康的干下去就得学会阶段性划水,阶段性划水的一大关键的就是干活快过预期但是装作。。。不对,这个开头不对劲,下面重来... 查看详情

Zap logger 是不是支持转义字符 '\n' 和 '\t' 来打印换行错误verbose 或 stacktrace

】Zaplogger是不是支持转义字符\\\'\\\\n\\\'和\\\'\\\\t\\\'来打印换行错误verbose或stacktrace【英文标题】:DoesZaploggersupportescapecharacter\'\\n\'and\'\\t\'toprintnewlineerrorVerboseorstacktraceZaplogger是否支持转义字符\'\\n\'和\'\\t\'来打印换行错误verbose... 查看详情

如何将 Sentry 与 go.uber.org/zap/zapcore 记录器一起使用

】如何将Sentry与go.uber.org/zap/zapcore记录器一起使用【英文标题】:HowtouseSentrywithgo.uber.org/zap/zapcorelogger【发布时间】:2021-02-2407:14:45【问题描述】:我正在使用go.uber.org/zap/zapcore登录我的Go应用程序。packageloggerimport("go.uber.org/zap""go... 查看详情

如何为 zap 全局记录器使用省略号

】如何为zap全局记录器使用省略号【英文标题】:Howtouseellipsisforzapgloballogger【发布时间】:2022-01-1522:04:50【问题描述】:您好,我正在尝试将糖记录器更改为全局更长的时间我检查了我可以使用的可能字段,但我无法解决我的... 查看详情

如何在詹金斯中使用 Zap 插件执行 selenium 脚本

】如何在詹金斯中使用Zap插件执行selenium脚本【英文标题】:HowtoexecuteseleniumscriptusingZapPlugininjenkins【发布时间】:2018-10-1500:51:05【问题描述】:我对Jenkins中的Zap插件有疑问。假设我在java中编写了selenium脚本,它将启动浏览器并... 查看详情

使用 API 调用的 ZAP 身份验证

】使用API调用的ZAP身份验证【英文标题】:ZAPAuthenticationusingAPIcalls【发布时间】:2015-02-2004:52:40【问题描述】:我正在使用ZAPAPI调用来使用命令行测试站点。但是即使我遵循正确的步骤,我的用户身份验证也存在问题。但是当蜘... 查看详情

使用 Jackson 将 protobuf 转换为 JSON?

】使用Jackson将protobuf转换为JSON?【英文标题】:ConvertaprotobuftoJSONusingJackson?【发布时间】:2019-01-0609:32:56【问题描述】:使用Jackson的ObjectMapper将protobuf转换为JSON时出现以下错误:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:Dir... 查看详情

OWASP ZAP:持续集成中的主动扫描器

...2016-04-1123:15:56【问题描述】:尝试在持续集成(CI)设置中使用ZAP(2.4.3)。我可以将ZAP作为守护程序运行,通过使用ZAP作为代理运行我所有的Selenium测试(在Java中),然后能够使用调用htmlreport的RESTapi来获得被动扫描器的最终 查看详情

使用 C# Google.Protobuf 将 ByteString 反序列化为对象

】使用C#Google.Protobuf将ByteString反序列化为对象【英文标题】:DeserializingByteStringintoanobjectusingC#Google.Protobuf【发布时间】:2020-03-0311:00:30【问题描述】:所以我有一条来自不同服务的gRPC消息(用另一种编程语言编写)。这是这个... 查看详情