Go错误处理和Error日志打印实践

Go错误处理和Error日志打印实践

如何参数校验?

遵循:永不相信外部系统,永远相信内部系统

  • 对前端/上游服务传来的参数做最严格的校验,不对传来的参数有任何假设
  • 对下游服务的返回值做最严格的校验,不对返回的结果有任何假设
  • 对内部系统做宽松的校验,let it panic (保证外层有recover,不要裸开一个goroutine,除非你能保证这个goroutine永不panic,否则会导致成个程序挂掉)

如何打印日志?

日志级别 打印标准
Fatal 一个或多个关键业务功能不符合预期,导致整个系统无法正常运行
Error 一个或多个功能不符合预期,导致部分功能无法正确运行
Warn 发生了不符合预期的行为,但相关功能仍能正常运行
Info 发生了某件事,我们可能会在排查业务问题或查询相关信息时用到
Notice 同上,一般不用
Debug 用于调试
Trace 用于调试
  • 打印最上层打印req和resp
  • 关键路径打印info/debug,配置conf文件路径以便控制是否打印debug日志

什么时候打印Error 日志?

原则:

  • error应为上游提供简单易懂的提示
  • error应为问题排查提供帮助
  • error是业务处理的一部分,应尽可能处理error,防止未知错误以及panic
  • 遵循依赖倒置原则

什么时候打印 error ?

  • 发生了非预期的情况

如果打印error级别log,则认为一定发生了非预期的情况。 例如mysql/下游挂了或自己代码中有bug,发生了从未考虑过的情况。 其他的业务error一律是warn级别,例如扣钱时发现用户钱不够了这种业务错误 或不可信的上游(例如前端)传来的参数有问题

BadCase 1:打印并直接向上传递

kotlin 复制代码
err : = json.Unmarshal(data, &task)
if err != nil {
  logs.CtxError(ctx, "unmarshal error, err=%v", err)
  return err
}

原始错误层层向上传递,每一层打印错误日志。这样会造成:

  1. 错误日志很多,并且都是重复错误,对排查造成干扰
  2. 打印的是原始错误,有些是其他http接口返回的错误,很难找到到底是哪里出现的,什么原因。

建议:

不需要处理的错误,错误级别不要使用Error级别,可以打印成Warn、Info、Debug等。

BadCase 2:添加上下文后向上传递

go 复制代码
err:= json.Unmarshal(data, &task)
if err != nil {
  return fmt.Errorf("unmarshal error, err=%v", err)
}

虽然日志变少了,但是也破坏了原始错误信息,如果上层需要判断原始错误则无法实现。

比如:查数据库时,有的时需要忽略没查到结果的情况,需要判断错误是不是 gorm.ErrRecordNotFound("record not found"), 如果包裹了信息,则无法实现了。然后就需要通过字符串匹配,判断 err.Error()中的信息,这是非常不合理的。

建议

  1. 处理错误的原则:只处理(打印)一次错误
  • 如果错误不需要被处理,添加上下文信息,并返回给上层,不需要打印。
  • 需要处理错误的地方,就不要返回给上层调用者了。
  1. err错误打印
arduino 复制代码
logs.CtxError(ctx, "%v", err)  //普通错误打印
logs.CtxError(ctx, "%+v", err) //带有堆栈的错误打印
  1. 错误产生时(最底层),需要在当前函数打印一次Error。这样做可以让metrics采集到日志产生的代码行。在错误日志有突增时,可以快速分析定位。
  2. 一般来说错误都需要向上传递,传递到最上层(一般是controller或者handler,转换成rsp code

参考资料

相关推荐
不知更鸟5 小时前
Django 项目设置流程
后端·python·django
黄昏恋慕黎明6 小时前
spring MVC了解
java·后端·spring·mvc
G探险者8 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
百锦再8 小时前
第18章 高级特征
android·java·开发语言·后端·python·rust·django
Tony Bai8 小时前
Go 在 Web3 的统治力:2025 年架构与生态综述
开发语言·后端·架构·golang·web3
程序猿20238 小时前
项目结构深度解析:理解Spring Boot项目的标准布局和约定
java·spring boot·后端
RainbowSea9 小时前
内网穿透配置和使用
java·后端
掘金码甲哥9 小时前
网关上的限流器
后端
q***062910 小时前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
开发语言·后端·golang
GOTXX10 小时前
用Rust实现一个简易的rsync(远程文件同步)工具
开发语言·后端·rust