如何进行日志维护
写的破玩意越来越多了,不得不写日志维护了,我还真不知道自己写的什么玩意。
总则
- 更新日志绝对不应该是git日志的堆砌物
- 日志中不要记录无用信息,防止无用日志淹没重要信息
- 要明确不同日志的用途,对日志内容进行分类
- 日志信息要准确全面,努力做到仅凭日志就可以定位问题
- 日志格式要统一规范
- 日志要不断优化、完善
日志是什么
一个由人工编辑,以时间为倒序的列表。 这个列表记录版本变动、事件。
日志分级
遵循 RFC 5424,将日志级别分为以下 8 种等级:
- 0 Emergency: system is unusable
- 1 Alert: action must be taken immediately
- 2 Critical: critical conditions
- 3 Error: error conditions
- 4 Warning: warning conditions
- 5 Notice: normal but significant condition
- 6 Informational: informational messages
- 7 Debug: debug-level messages
各级日志等级信息记录内容如下:
Emergency
- 导致系统不可用的事故,属于最严重的日志级别,因此该日志级别必须慎用
- 通常情况下,一个进程的声明周期中应该只记录一次 Emergency 级别的日志
Alert
- 必须马上处理的问题,紧急程度低于 Emergency
- Alert 错误发生时,已经影响了用户的正常访问
- 与 Emergency 的区别是,Alert 状态下系统依旧是可用的。例如:DB / Cache 无法连接。
Critical
紧急情况,程序组件不可用,需要立刻进行修复。例如:用户注册逻辑模块不能发送邮件。
Error
- 运行时出现的错误,不必要立即进行修复
- 错误不影响整个逻辑的运行,但需要记录并做检测。
Warning
- 可能影响系统功能,需要提醒的重要事件
- 该日志标示系统可能出现问题,也可能没有(比如网络波动)。对于那些目前还不是错误,然而不及时处理也会变为错误的情况,也可以记为 Warning 日志。例如一个存储系统的磁盘使用量超过阀值,或者系统中某个用户的存储配额快用完等等
- 对于 Warining 级别的日志,虽然不需要马上处理,但也需要及时查看并处理
Notice
- 不影响正常功能,但需要注意的消息
- 执行过程中较 Infomational 级别更为重要的信息。
Infomational
- 用于记录系统正常运行情况下的一般信息,强调应用程序的运行过程。例如:某个子模块的初始化、某个请求的成功执行等
- 通过查看 Infomational 级别的日志,可以很快对系统中出现的 0~5 级别的错误进行定位
Debug
帮助开发、测试、运维人员对系统进行诊断的信息。
功能分类
日志从功能来说,可分为诊断日志、统计日志、审计日志。
诊断日志
- 请求入口和出口
- 外部服务调用和返回
- 资源消耗操作: 打开文件等
- 容错行为: 譬如云硬盘的副本修复操作
- 程序异常: 譬如数据库无法连接
- 后台操作:清理程序
- 启动、关闭、配置加载
- 抛出异常时,不记录日志
统计日志
- 用户访问统计
- 计费日志(如记录用户使用的网络资源或磁盘占用,格式较为严格,便于统计)
审计日志
- 管理操作
规范
- 统一字段命名:对于不同请求中的同一含义的字段,只能有一个名字
- 统一字段风格:例如字段一律使用
xxx_yyy
的下划线命名风格 - 统一日志层级风格
- 统一字段顺序:例如统一使用
请求ID/服务名/请求参数/响应数据/响应时间
作为日志字段顺序 - 每个请求需要加入请求 ID
request_id
日志中记录什么
推荐记录的日志内容
- 在系统启动或初始化时记录重要的系统初始化参数
- 记录系统运行过程中的所有的错误
- 记录系统运行过程中的所有的警告
- 在持久化数据修改时记录修改前和修改后的值
- 记录系统各主要模块之间的请求和响应
- 重要的状态变化
- 系统中一些长期执行的任务的执行进度
不推荐记录的日志内容
- 函数入口信息:除非该函数入口表示了一个重要事件的开始,或者将该信息记入 DEBUG 级别日志
- 文件内容或者一大段消息的内容:如果实在需要记录,则可以截取其中一些重要的信息来记入日志
- “良性”错误:有时候虽然出现了错误,然而错误处理的流程可以正确解决这种情况,例如插入数据库时有重复的记录,尽管是个错误,然而错误处理流程可以对这种情况进行处理
更新日志
以上是较为常用的日志规范了,下面整点我常用的,更新日志。
示例如下
1 |
|
1 |
|
怎么定义好的更新日志
一个好的更新日志,一定满足:
- 给人而不是机器写的。所以要说人话。
- 快速跳转到任意段。所以采用markdown格式
- 一个版本对应一个章节。
- 最新的版本在上,最老的在下面。
- 所有日期采用’YYYY-MM-DD’这种规范。(例如北京奥运会的2008年8月8日是2008-08-08)这个是国际通用,任何语言 都能理解的,并且还被xkcd推荐呢!
- 标出来是否遵守语义化版本格式
- 每一个软件的版本必须:
- 标明日期(要用上面说过的规范)
- 标明分类(采用英文)。规范如下:
- ‘Added’ 添加的新功能
- ‘Changed’ 功能变更
- ‘Deprecated’ 不建议使用,未来会删掉
- ‘Removed’ 之前不建议使用的功能,这次真的删掉了
- ‘Fixed’ 改的bug
- ‘Security’ 改的有关安全相关bug
怎么尽可能减少耗费的精力?
永远在文档最上方提供一个’Unreleased’ 未发布区域,来记录当前的变化。 这样作有两大意义。
- 大家可以看到接下来会有什么变化
- 在发布时,只要把’Unreleased’改为当前版本号,然后再添加一个新的’Unreleased’就行了
注意:
- 把git日志扔到更新日志里。看似有用,然并卵。
- 不写’deprecations’就删功能。不带这样坑队友的。
- 采用各种不靠谱日期格式 2012年12月12日,也就中国人能看懂了。
参考
Logging best practices to get the most out of application level logging – Slides