6.1.1. 常用

通常一个线上问题的定位流程是:通过 Metric 发现问题,根据 Trace 定位到问题模块,根据模块具体的日志定位问题原因。 Logging,Metrics 和 Tracing 有各自专注的部分:

Logging - 用于记录离散的事件
    例如, 应用程序的调试信息或错误信息,它是我们诊断问题的依据
Metrics - 用于记录可聚合的数据
    例如,
    队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新
    HTTP 请求个数可被定义为一个计数器,新请求到来时进行累加
Tracing - 用于记录请求范围内的信息
    例如, 一次远程方法调用的执行过程和耗时,它是我们排查系统性能问题的利器

这三者也有相互重叠的部分,如下图所示 [1] :

../../_images/tracing_logging_metrics.png

K8s 中的日志输出总结 [2]

如何选择日志等级:

// 作为程序员,一定要合理设置日志等级
1. FATAL 类型日志一定是非常严重的错误、需要人工处理的场景打印的
2. ERROR 和 WARNING 的区别很多程序员难以选择,可以从告警角度考虑
   ERROR 为一般需要告警,WARNING 为不需要
3. 日志等级一方面是为了能够表示日志的严重程度,另一方面也是为了控制应用程序的日志输出量
   通常线上只能打开 INFO 或 WARN 的日志
4. DEBUG 日志可以多打,方便分析问题
5. 所有用户请求日志,必须记录
6. 对于不确定的外部系统调用,日志需尽可能覆盖周全
7. 程序中的日志库需要具备运行期间变更日志等级的能力,方便在遇到问题需要分析时临时更改日志等级
8. 通常在新功能上线, 涉及的日志可适当提升一个等级, 方便实时观察和监控, 待稳定后再调整到正常

日志内容规范:

// 日志中通常必备的字段有:Time、Level、Location.对特定模块/流程/业务,还需要有下面字段
1. 如果使用 Trace 系统,可以把 TraceID 附加到日志中;
2. 固定的流程需要附加对应的字段,例如:
  订单的生命周期中,一定要有订单号、用户 ID 等信息
  这些信息可以通过 Context 附加到对应流程的日志实例上
3. HTTP 请求需要记录: URL、Method、Status、Latency、Inflow、OutFlow、ClientIP、UserAgent
4. 如果多个模块的日志都打印到同一个流/文件中,必须有字段标识模块名

合理控制日志输出量:

1. 服务入口的请求和响应日志没有特殊原因都要输出并采集,采集的字段可以根据需求调整
2. 错误日志一般都要打印,如果太多,可以使用采样方式打印
3. 减少无效日志输出,尤其是循环中打印日志的情况需尽量减少
4. 请求型的日志
   4.1 (Ingress、Nginx 访问日志)一般不超过 5MB/s(500 字节每条,不超过 1W/s)
   4.2 应用程序日志不超过 200KB/s(2KB 每条,不超过 100 条/s)

控制日志性能消耗:

日志作为业务系统的辅助模块,一定不能影响到业务正常的工作,因此日志模块的性能消耗需要单独额外注意
一般在选择/开发日志库时,需要对日志库进行性能测试
确保正常情况下日志的性能消耗不超过整体 CPU 占用的 5%

容器标准输出对于 DockerEngine 的性能消耗特别大
实测 10W/s 的日志量会额外占用 DockerEngine 1 个核心的 CPU(单核 100%)

注意:一定要确保日志打印是异步的,不能阻塞业务系统运行
[1]http://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html
[2]https://www.cnblogs.com/alisystemsoftware/p/12408258.html