一、日志
1、日志的作用
日志记录用户操作、系统运行状态,好的日志系统可以帮助研发和运维:
- 掌握线上服务运行状态;
- 快速定位线上问题;
- 发现系统瓶颈;
- 服务报警;
- 挖掘数据价值;
- ……
2、日志级别
基本级别(由低到高):
- DEBUG:The DEBUG Level designates fine-grained informational events that are most useful to debug an application.
- INFO:The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
- WARN:The WARN level designates potentially harmful situations.
- ERROR:The ERROR level designates error events that might still allow the application to continue running.
- FATAL:The FATAL level designates very severe error events that will presumably lead the application to abort.
二、日志系统的约定
|
1、日志名字:同一个服务的每个级别日志打印到对应的文件中,可以选择按天/小时分割,示例如下:
- 2019120917.debug.log
- 2019120917.info.log
- 2019120917.warn.log
- 2019120917.error.log
- 2019120917.fatal.log
2、时间戳:日志记录产生的时间
- 日志文件名大概定位日志记录产生时段;
- 每行日志内时间字段需要十分精确:
- 目前看再不规范的日志系统最起码都打了这个字段;
2、代码文件及行数
- 定位问题、发现系统瓶颈等;
3、日志级别
- 如果不同级别的日志打印到不同文件中,这里也可以不打印该字段;
4、TraceId & SpanId:traceid表示所属的调用链,spanid表示本次rpc
- TraceId:全链路追踪,贯穿整个调用链传递,从而可以通过traceid一次性取出所有相关日志
- 动作发起方生成 traceId,中间处理服务使用并记录该 traceId;
- 一个完整的请求在各服务处理的 traceId理论是同一个;
- SpanId:代表一次rpc调用(一次rpc调用的两头分别关联了1个client和1个server),spanid生成规则体现了调用的层级与时序
- 反正服务调用的层级和时序;
- client端的span应该伴随request的生成而生成,伴随response的收到而释放(写到日志中);server端的span应该伴随request的收到而生成,伴随response的发出而释放(写到日志中);
5、annotation:日志正文
- kv格式具有自解释性,便于日志采集、分析;
- 字段之间采用统一的分隔符;
6、耗时
- 总耗时、具体某一函数处理耗时;
- 对于client来说,要记录request的发出时间和response的收到时间,之间的耗时相减可以得到;
- 对于server来说,要记录request的收到时间和response的发出时间,之间的耗时相减可以得到;
7、其他注意事项
- 编码:理论上日志都是明文信息,应尽量避免二进制等其他格式的出现,在无法避免的情况下应该采用base64或者其他转码;
- IP、Port等信息如果需要也可以加上;
三、日志系统的实现
1、封装日志库 → 通信框架、应用层框架支持日志库 → 服务打印日志
日志系统的建设不是某一个服务做到就可以的,尤其在分布系统环境、全链路问题跟踪。
四、参考资料
1、Google论文(翻译):http://bigbully.github.io/Dapper-translation/
Google论文(原文):https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/papers/dapper-2010-1.pdf
2、分布式调用跟踪系统调研:https://www.jianshu.com/p/e02972487e00