背景是這樣的,前端頁面有一個日志level的枚舉值傳遞給后端肉渴,server端會對該枚舉值的有效性進行校驗宋光,QA測試階段使用了默認的level(也就是Info
)瑞凑,并沒有測試出這個bug纵苛。但是線上業(yè)務需要配置一個Debug
的level冷冗,出現(xiàn)了提交失敗的問題(后端校驗為非法的枚舉值)角骤。示例代碼如下:
枚舉的定義:
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富岳,看看是否發(fā)現(xiàn)了問題...
我當時看了好多遍,實在無法發(fā)現(xiàn)是哪個地方出現(xiàn)了問題陈瘦,所以看似簡單的問題才是最迷惑的,不知道你有同感沒。
最后直接放大招痊项,IDE debug搞起:前端傳遞Debug
的level是使用的是接口文檔中約束的枚舉: 0锅风,根據(jù)我的理解FormatVlogLevel函數(shù)應該返回"Debug",然后直接返回了"Unknown"鞍泉;最后添加了萬能輸出代碼: fmt.Println(l) fmt.Println(VlogLevelDebug)
皱埠。第一個輸出是0,第二個輸出是1咖驮,這边器。。托修。忘巧。
后來發(fā)現(xiàn)IDE給出了常量值的解析結果:
后來猜測可能和前面的那個枚舉定義有關,將
VlogLevelUnknown = "Unknown"
調整到此const(...)
域以外睦刃,發(fā)現(xiàn)結果就符合預期了:總結:
這種錯誤在編譯環(huán)節(jié)是不會報錯的砚嘴,而且后期排查起來也非常困難。我嘗試google了一下這類錯誤涩拙,發(fā)現(xiàn)并沒有多少有價值的資料际长,是個不小心就可能引起大問題的坑。所以歸納幾條建議兴泥,供大家參考:
- iota前不要定義任何常量值
- 如果有必要請直接使用字面量直接初始化常量值
- 編寫單元測試工育,確保枚舉值和預期嚴格一致
參考資料: