V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
beego
Gota
V2EX  ›  Go 编程语言

分享一个处理结构化 error 的库

  •  
  •   Gota · 193 天前 · 1418 次点击
    这是一个创建于 193 天前的主题,其中的信息可能已经有所发展或是发生改变。

    和大家分享一个自己写的库 github.com/gota33/errors

    主要用于结构化 error 的生成、编码和解码。目前自用下来还可以,欢迎试用及提出建议。

    错误的描述信息是遵循 Google API design 设计的。

    这里贴一个输出到控制台的例子,当然也是可以编码成 JSON 在 RESTful 服务间传递的。

    更多的例子可以参考项目首页的文档。

    // ...
    err := Annotate(
        context.DeadlineExceeded,
        DeadlineExceeded,
        StackTrace("heavy job"),
        RequestInfo{RequestId: "<uuid>"},
        LocalizedMessage{Local: "en-US", Message: "Background task timeout"},
        LocalizedMessage{Local: "zh-CN", Message: "后台任务超时"},
    )
    
    fmt.Printf("%+v", err)
    
    // Output:
    // status: "504 DEADLINE_EXCEEDED"
    // message: "context deadline exceeded"
    // detail[0]:
    // 	type: "type.googleapis.com/google.rpc.DebugInfo"
    // 	detail: "heavy job"
    // 	stack:
    // 		goroutine 1 [running]:
    // 		runtime/debug.Stack(0xc00005e980, 0x40, 0x40)
    // 			/home/user/go/src/runtime/debug/stack.go:24 +0xa5
    // 		github.com/gota33/errors.StackTrace.Annotate(0xfe36af, 0x9, 0x1056490, 0xc00005e980)
    // 			/home/user/github/gota33/errors/detail.go:368 +0x2d
    // 		github.com/gota33/errors.Annotate(0x1051780, 0x1257e60, 0xc00010fc00, 0x5, 0x5, 0xc00010fba8, 0x10)
    // 			/home/user/github/gota33/errors/errors.go:79 +0x97
    // 		github.com/gota33/errors.ExampleAnnotate()
    // 			/home/user/github/gota33/errors/example_test.go:10 +0x251
    // 		testing.runExample(0xfe589a, 0xf, 0xfff6c0, 0xfead08, 0x1a, 0x0, 0x0)
    // 			/home/user/go/src/testing/run_example.go:63 +0x222
    // 		testing.runExamples(0xc00010fed0, 0x120aee0, 0x3, 0x3, 0x0)
    // 			/home/user/go/src/testing/example.go:44 +0x185
    // 		testing.(*M).Run(0xc000114100, 0x0)
    // 			/home/user/go/src/testing/testing.go:1419 +0x27d
    // 		main.main()
    // 			_testmain.go:71 +0x145
    //
    // detail[1]:
    // 	type: "type.googleapis.com/google.rpc.RequestInfo"
    // 	request_id: "<uuid>"
    // 	serving_data: ""
    // detail[2]:
    // 	type: "type.googleapis.com/google.rpc.LocalizedMessage"
    // 	local: "en-US"
    // 	message: "Background task timeout"
    // detail[3]:
    // 	type: "type.googleapis.com/google.rpc.LocalizedMessage"
    // 	local: "zh-CN"
    // 	message: "后台任务超时"
    
    第 1 条附言  ·  192 天前
    如果想了解错误结构设计的思路,可以先看一下 Google API Design 的文档: https://cloud.google.com/apis/design/errors
    6 条回复    2021-12-20 11:25:20 +08:00
    godlovesxcjtest
        1
    godlovesxcjtest  
       193 天前
    挺好的,但是,老哥你不觉得这样处理错误太麻烦了吗。要写好多,go 语言的错误处理本来就麻烦的有要死,如果按照你这种用法,岂不是处理错误的代码都要写好多
    Gota
        2
    Gota  
    OP
       193 天前
    @godlovesxcjtest 谢谢评价。

    这个库主要在微服务的场景下使用。这时候需要考虑到错误的传递,比如不同的 status code 和 http code ,以及不同的错误类型需要有不同的 payload 来描述错误细节,再如 request_id 这样的字段。

    当然简单的用法也有,比如只附加 status code 而不加具体的 detail ,但这里为了演示就把所有的字段都加上了。
    godlovesxcjtest
        3
    godlovesxcjtest  
       193 天前
    @Gota request_id 没必要放到 error 里面。可以放到 context 里面,打印日志的时候,传入 context ,这样每条日志都可以有 request_id 。

    我没仔细看源码,想问一下,底层使用你的库抛出错误后,调用的上层想加上一些错误信息,类似 errors.Withmessage 这种,使用什么方法,上层是不是还需要加上错误吗呢
    Gota
        4
    Gota  
    OP
       193 天前
    @godlovesxcjtest 是这样的,由于服务之间传递错误需要一个固定的格式,所以这里采用的是 Google API design 里的建议格式。所以里面的 request_id 不是用来记录日志的,而是错误格式本身所定义的。

    关于错误码,任意层级都是可以设置的,以最后设置的为准。如果是增加非结构化的错误信息可以直接用 fmt.Errorf(),如果是结构化错误信息就需要用 errors.Annotate() 了。
    eudore
        5
    eudore  
       190 天前
    我都直接 logger 把 error 发送到 jaeger 面板上去了。
    Gota
        6
    Gota  
    OP
       190 天前
    @eudore 只是记录 error 是不够的,应尽量在系统内消化错误。所以需要一种方式来标准化错误格式,这样就能传递和处理跨服务的 error 了。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2923 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:55 · PVG 08:55 · LAX 17:55 · JFK 20:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.