日志
引言
新技术层出不穷,很多人觉得抓住新技术就能抓住知识,抓住地位,最后其实什么都抓不住。工作多年后我发现那些优秀的程序员其实大多在『吃老本』,比如他们懂网络编程,懂数据库,再懂点业务在Web领域就可以混的风生水起,无论新技术迭代多快,本质还是离不开网络编程和数据库。
写日志是一件很不起眼的事,老板绝对不会因为你日志写的好给你加工资。但是如果你日志写的好,肯定能在Web领域混的风生水起,因为日志在Web领域有着举足轻重的地位,类似飞机上的黑匣子。
如果你常因为写日志而烦恼,请牢记下面这些规范。
日志记录总则
1、日志中不要记录无用信息,防止无用日志淹没重要信息
2、要明确不同日志的用途,对日志内容进行分类
3、日志信息要准确全面,努力做到仅凭日志就可以定位问题
4、日志格式要统一规范
5、日志要不断优化、完善
日志格式规范
1、一字段命名:对于不同请求中的同一含义的字段,只能有一个名字
2、统一字段风格:例如字段一律使用 xxx_yyy 的下划线命名风格
3、统一日志层级风格
4、统一字段顺序:例如统一使用 请求ID/服务名/请求参数/响应数据/响应时间 作为日志字段顺序
5、每个请求需要加入请求 ID request_id
一. 日志要有分隔符
大多时候我们使用 | 作为分隔符,格式如下:
类名|方法名|输入参数|输出参数
分隔符作为参数的边界非常重要,它决定着日志是否可用,是否好用。分析数据的时候直接用分隔符拆分就是对应的字段属性。
错误例子:
类名方法名输入参数输出参数 (不用分隔符)
类名#方法名 输入参数|输出参数 (用多总分隔符)
二. 避免重复记录
在一次请求中,同样的内容理论上只需要记录一次。比如接口传入的参数。重复记录会造成磁盘空间的浪费,不利于快速定位错误点。
三. 通过uuid和编号来保证日志的连贯性
一个请求应该有一个唯一的编号,每记录一次日志还应该有一个对应的编号。比如下面的日志记录。
api.ERROR: 79a8ea37dceff105|0|responseObj is error:{"return_code":"SUCCESS","return_msg":"OK"}
api.ERROR: 79a8ea37dceff105|1|App\Request|{"subject":"201906179ae"}
79a8ea37dceff105 是本次请求的全局uuid,0,1表示记录的顺序编号。这样能保证一次请求的所有日志都可追踪,可查看链路信息。
四. 日志编码统一用json
在记录数组和对象时统一使用jsonEncode(),json是比较通用的格式,方便解析。不要使用print(),serialize()等扩展性不好的数据格式。
五. 日志种类区分
错误日志一定要有error关键字,否则没人知道那是错误日志。普通日志需要有info,notice等关键字。之后无论是日志归拢还是分隔,一眼就知道日志的属性。
六. 服务日志
服务的输入与输出应该统一在接口的入口和出口函数中记录,过程中不记录。千万不要在代码中使用die() 和 exit() 等强制退出函数。任何时候die() 和 exit() 都是可以通过 if return 等语法代替。
规范的做法应该像nginx,将请求的参数和返回的http code统一记录,中间除非报错否则不会产出额外日志。
服务接口执行过程中应该只记录重要的中间处理数据,比如调用了第三方接口,可以记录第三方接口的请求和返回数据。
七. 自定义日志
自定义的日志一定要和上下文数据一起记录,比如想记录微信支付失败,那么一定要记录请求微信支付的相关参数与微信支付接口返回的参数。如果只记录微信支付失败这几个字是毫无意义的,必须要有上下文这几个文字信息才有意义。
PS:最优秀的做法是不要有自定义日志,如果判断到了错误信息,应该直接返回给接口调用方,由上层统一记录日志。
八. 重要日志需要脱敏
用户绑定手机号或者邮箱时,会把手机号和邮箱作为参数传到服务端,我们在记录日志时应该把用户手机号和邮箱做脱敏处理,比如中间几位用*号代替。还有密码,身份证等敏感信息更要脱敏。
日志级别划分
Emergency
导致系统不可用的事故,属于最严重的日志级别,因此该日志级别必须慎用
通常情况下,一个进程的声明周期中应该只记录一次 Emergency 级别的日志
Alert
必须马上处理的问题,紧急程度低于 Emergency
Alert 错误发生时,已经影响了用户的正常访问
与 Emergency 的区别是,Alert 状态下系统依旧是可用的。例如:DB / Cache 无法连接。
Critical
紧急情况,程序组件不可用,需要立刻进行修复。例如:用户注册逻辑模块不能发送邮件
Error
运行时出现的错误,不必要立即进行修复
错误不影响整个逻辑的运行,但需要记录并做检测。
Warning
可能影响系统功能,需要提醒的重要事件
该日志标示系统可能出现问题,也可能没有(比如网络波动)。对于那些目前还不是错误,然而不及时处理也会变为错误的情况,也可以记为 Warning 日志。例如一个存储系统的磁盘使用量超过阀值,或者系统中某个用户的存储配额快用完等等
对于 Warining 级别的日志,虽然不需要马上处理,但也需要及时查看并处理
Notice
不影响正常功能,但需要注意的消息
执行过程中较 Infomational 级别更为重要的信息。
Notice
不影响正常功能,但需要注意的消息
执行过程中较 Infomational 级别更为重要的信息。
Infomational
用于记录系统正常运行情况下的一般信息,强调应用程序的运行过程。例如:某个子模块的初始化、某个请求的成功执行等
通过查看 Infomational 级别的日志,可以很快对系统中出现的 0~5 级别的错误进行定位
Debug
帮助开发、测试、运维人员对系统进行诊断的信息。
最后,大量地输出无效日志不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:
这些日志真的有人看吗?
看到这条日志你能做什么?
能不能给问题排查带来好处?写日志的最高境界是帮助自己用最少的字符得到最有用的结论。