美文网首页Golang进阶
Go iota引起的线上事故

Go iota引起的线上事故

作者: qishuai | 来源:发表于2023-07-19 14:58 被阅读0次

背景是这样的,前端页面有一个日志level的枚举值传递给后端,server端会对该枚举值的有效性进行校验,QA测试阶段使用了默认的level(也就是Info),并没有测试出这个bug。但是线上业务需要配置一个Debug的level,出现了提交失败的问题(后端校验为非法的枚举值)。示例代码如下:

枚举的定义:

type vlogLevel int

const (
    VlogLevelUnknown = "Unknown"

    VlogLevelDebug vlogLevel = iota
    VlogLevelInfo
    VlogLevelWarn
    VlogLevelError
    VlogLevelFatal
)

// FormatVlogLevel 返回vlog level的语义
func FormatVlogLevel(l int) string {
    switch vlogLevel(l) {
    case VlogLevelDebug:
        return "Debug"
    case VlogLevelInfo:
        return "Info"
    case VlogLevelWarn:
        return "Warn"
    case VlogLevelError:
        return "Error"
    case VlogLevelFatal:
        return "Fatal"
    }

    return VlogLevelUnknown
}

枚举值校验的代码:

if data.FormatVlogLevel(req.LogLevel) == data.VlogLevelUnknown {
    return nil, errors.New("invalid vlog_level value")
}

你可以暂停30s,看看是否发现了问题...

我当时看了好多遍,实在无法发现是哪个地方出现了问题,所以看似简单的问题才是最迷惑的,不知道你有同感没。
最后直接放大招,IDE debug搞起:前端传递Debug的level是使用的是接口文档中约束的枚举: 0,根据我的理解FormatVlogLevel函数应该返回"Debug",然后直接返回了"Unknown";最后添加了万能输出代码: fmt.Println(l) fmt.Println(VlogLevelDebug)。第一个输出是0,第二个输出是1,这。。。。

后来发现IDE给出了常量值的解析结果:

iota
后来猜测可能和前面的那个枚举定义有关,将VlogLevelUnknown = "Unknown"调整到此const(...)域以外,发现结果就符合预期了:
iota

总结:
这种错误在编译环节是不会报错的,而且后期排查起来也非常困难。我尝试google了一下这类错误,发现并没有多少有价值的资料,是个不小心就可能引起大问题的坑。所以归纳几条建议,供大家参考:

  • iota前不要定义任何常量值
  • 如果有必要请直接使用字面量直接初始化常量值
  • 编写单元测试,确保枚举值和预期严格一致

参考资料:

相关文章

  • iota

    关于iota的说明文档:iota在go中的使用

  • iota

    iota go语言中不支持枚举定义,但是使用iota可以实现类似效果 枚举定义 iota实际被定义为0,仅配合co...

  • golang学习笔记--iota

    go中的iota 1.iota只能在常量的表达式中使用、2.每次const出现时都会让iota初始化为03.用作枚...

  • 第01天(基本类型、流程控制)_02

    07_常量的使用.go 08_多个变量或常量定义.go 09_iota枚举.go 10_bool类型.go 11_...

  • 关于 iota 的使用

    在 Go 语言的 const 中,如果使用 iota,每新有一行 iota 都会自加一,但是注意观察下面的例子: ...

  • GO学习 iota

    第4天iota关键字 package main import "fmt" func main() { /* i...

  • 04-枚举常量

    Go语言枚举 c语言中的枚举 Go语言枚举 iota迭代器 Go语言输出函数 fmt.Printf("格式化字符串...

  • Go枚举(一)

    go没有明确意义上的enum定义,不过可以借助iota标识符实现一组自增常量值来实现枚举类型。1.iota自增 输...

  • Go语言--iota枚举

    介绍 iota 常量自动生成器,每个一行,自动累加1 iota给常量赋值使用3.iota遇到const,重置为04...

  • Go Enum和iota

    Golang没有内置的enum类型,通常都是用常量来模拟。如下例所示: 输出为false、true。我们可以用io...

网友评论

    本文标题:Go iota引起的线上事故

    本文链接:https://www.haomeiwen.com/subject/egaoudtx.html