阿里巴巴,日志与异常强制规范26条,Java篇(收藏不亏)

规范内容取自“阿里巴巴异常日志强制规范”(Java版),发布时间为2022.2.3,开源。

内容较多,3000字,建议收藏。

规范的原理,比规范本身,更加重要。

第一部分,异常处理强制规范【9条】

1. 可以通过预检查方式规避的 RuntimeException 异常不应该通过 catch 的方式来处理。

正例:

if (obj != null) {...}

反例:

try { obj.method(); } 

catch (NullPointerException e) {…}

2. 不要用异常捕获模块来做流程控制,条件控制。

画外音:异常捕获的初衷是解决程序运行中的各种意外情况,而不是处理业务异常分支。

3. 只 catch 非稳定代码。

稳定代码指的是无论如何不会出错的代码。

正例:

用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于简单... 这些是稳定代码,应该在程序上作出判断,并提示给用户,而不是放到 try catch 中。

4. 捕获异常的目的是为了处理它,不能捕获了却不处理而抛弃之。

如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,并将其转化为用户可以理解的内容。

5. 事务场景中,抛出异常被 catch 后,如果需要回滚,可能要考虑业务层面的补偿事务。

6. finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch 。

画外音:如果JDK7,可以使用 try-with-resources 方式。

7. 不要在 finally 块中使用 return

画外音:try 块中的 return 语句执行成功后,并不马上返回,而是继续执行 finally 块中的语句,如果此处存在 return 语句,则会在此直接返回,无情丢弃掉 try 块中的返回点。

反例:

11b7129379a069247e1dbd4177e090d1.png

8. 捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。

9. 在调用RPC、二方包、或动态生成类的相关方法时,捕捉异常使用 Throwable 类进行拦截。

画外音:二方包,是指公司内部的依赖库。

通过反射机制来调用方法,如果找不到方法,抛出 NoSuchMethodException 。

反例:

非核心服务引入了高版本的 spring ,导致运行到某段核心逻辑时,抛出 NoSuchMethodError 错误, catch 用的类却是 Exception ,堆栈向上抛,影响到上层业务。这是一个非核心功能点影响到核心应用的典型反例。

第二部分,错误码强制规范【7条】

1. 错误码的制定原则是:快速溯源、沟通标准化。

画外音:错误码必须能够方便的比对与查找(方便grep,方便代码查找),让人能够快速知晓错误来源,快速判断是谁的问题,并对错误原因快速达成一致认知。

2. 错误码不体现版本号和错误等级信息。

画外音:

错误码只追加,不修改,不使用版本号区分;

错误等级,由错误码本身的业务含义决定,由其他字段体现。

3. 没有错误,但不得不填充错误码时,错误码填写五个零:00000。

4. 错误码为字符串类型,共5位,分成两个部分:错误产生来源+四位数字编号。

其中,错误产生来源分为A/B/C。

A表示错误来源于用户,比如参数错误,用户安装版本过低等:

0cb129294dfb5739b577819431180a52.png

B表示错误来源于当前系统,往往是业务逻辑出错,例如:

46e331851e5af0c6552eade008d973b2.png

C表示错误来源于非自身系统,例如:

d3ff5a26bb7600f5d47a4953cd78cd3d.png

其次,四位数字编号从0001到9999,大类之间的步长间距预留100。

5. 错误码不与公司业务架构挂钩,不与组织架构挂钩,需要在统一平台审批,审批后生效,先到先得。

6. 禁止随意定义新的错误码。

画外音:尽可能在原有错误码表中找语义相同或者相近的错误码使用。

7. 错误码不能直接透传给用户。

画外音,作为工程师,应该区分好:

堆栈(stack_trace)

错误信息(error_message)

错误码(error_code)

用户提示(user_tip

它们有关联,但不要混用。

第三部分,日志强制规范【10条】

1. 应用中不可直接使用三方日志组件(Log4j、Logback)中的API,而应依赖使用统一日志框架(SLF4J、JCL—Jakarta Commons Logging)中的 API。

c62a77369c3f0874a2f8a04ef14109ad.png

画外音:使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

2. 普通日志保存天数与命名需要遵循规范。

(1)日志文件至少保存15天;

画外音:有些异常具备以“周”为频次发生的特点。

(2)当天日志,以“应用名.log”来保存;

(3)保存目录为:/{统一目录}/{应用名}/logs/;

(4)过往日志格式为:{logname}.log.{保存日期}

(5)日期格式为:yyyy-MM-dd

以 mppserver 应用为例:

日志保存为: /home/admin/mppserver/logs/mppserver.log

历史日志为: mppserver.log.2024-08-18

3. 根据国家法律,网络运行状态、网络安全事件、个人敏感信息操作等相关记录,留存的日志不少于六个月,并且要多机备份。

4. 应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:appName_logType_logName.log

logType:日志类型,如 stats / monitor / access 等;

logName:日志描述。

画外音:这种命名的好处是,通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。

例如,mppserver应用中单独监控时区转换异常:

mppserver_monitor_timeZoneConvert.log

5. 在日志输出时,字符串变量之间的拼接使用占位符。

字符串拼接使用 StringBuilder.append() ,有性能损耗。使用占位符仅是替换动作,可以有效提升性能。

正例:

logger.debug("Processing trade with id : {} and symbol : {}", id, symbol);

6. 对于 trace/debug/info 级别的日志输出,必须进行日志级别的开关判断。

虽然在debug(参数) 的方法体内第一行代码 isDisabled(Level.DEBUG_INT)  为真时就直接 return, 但是参数可能会进行字符串拼接运算。

正例:

2750b976a8799112d738228b808f10aa.png

7. 避免重复打印日志,浪费磁盘空间,必须在日志配置中设置additivity=false

8. 生产环境禁止使用 System.out 或 System.err 输出或使用 e.printStackTrace() 打印异常堆栈。

画外音:标准日志输出与标准错误输出文件每次 Jboss 重启时才滚动,如果大量输出,容易造成文件大小超过操作系统大小限制。

9. 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出。

正例:

logger.error("inputParams: {} and errorMessage: {}", 各类参数或者对象toString(), e.getMessage(), e);

10. 日志打印时禁止直接用JSON工具将对象转换成String。

画外音:如果对象里某些get方法被覆写,存在抛出异常的情况,则可能会因为打印日志而影响正常业务流程的执行。

规范背后的原理,比规范本身,更有价值。

讨论:

你觉得日志与异常需要被规范吗?

你们公司有相关规范吗?执行情况如何?

相关文章

阿里巴巴MySQL规范,五千字版(收藏)

希望大家有收获,谢转。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值