# 日志规范 ## 前言概述 编写稳定优雅的代码固然重要,而写好日志亦非常重要,无论是何种编程语言,日志信息输出几乎无处不在, 日志是属于系统一个重要的组件模块,正确的日志输出,可以帮助我们开发时的调试 与 减轻程序后期的维护压力。 在实际开发中,很多开发者输出日志都是因为程序调试而输出,并没有一个程序全局日志规范输出的习惯,也就是说程序还有很多代码片段需要输出日志的。程序在开发联调的时候,假设程序运行出现异常或者报错,我们第一件事就是查看当时的日志输出,因为日志涵盖了程序运行时的情况信息,可以快速定位到问题的根本原因,生产环境亦是一样。作为开发人员,我们应该重视日志,认识到日志在系统中的地位,更要养成良好日志输出的习惯。 **功能完成开发后,在`review` 自己的代码的时候、务必合理地安排时间将日志填充** ## 日志输出原则 - 不能影响程序的正常运行 - 不允许输出涉及安全 与 隐私的数据 - 输出有意义的日志信息,同时确保日志的可读性 - 避免日志泛滥 ## 日志的重要性 - 记载用户行为的审计日志 - 可快速定位问题的根源,日志是排查问题的重要手段之一 - 方便开发调试 - 监控报警 - 查询历史 与 统计分析 ## 认识日志级别 日志级别通常有如下几种: - `verbose` 此级别输出任意级别的日志,不推荐使用 - `debug` 此级别一般用于项目开发调试或测试使用,生产环境不允许出现 `debug` 级别 - `info` 此级别用于记录一般行为数据,比如用户行为、`SQL`语句、参数等 - `notice` 此级别记录程序重要的参数 - `warning` 此级别记录非错误性的异常 或 非期望的结果 - `error` 此级别用于记录程序运行时的错误信息,比如程序异常捕获信息 - `critical` 此级别用于记录程序组件不可用的异常,属于紧急级别,比如某一个微服务通讯失败 - `alert` 此级别记录程序依赖组建或服务异常,比如`redis`、`MySQL`通讯异常 - `emergency` 当系统不可用,那就使用此日志级别记录 实际开发中,常用的是 `debug`, `info`, `warning` 和 `error` 这几种,**必须要掌握它们使用的原则**。 ### 优雅日志示范 ``` 2022-03-12 23:36:37.310839 INFO: push cash {"user_id":9510,"cash":"52.00"} 2022-03-12 23:36:37.311712 DEBUG: source data come from cache 2022-03-12 23:36:37.311935 WARNING: logout failed {"user_id":8888} 2022-03-15 13:38:22.175 [grpc-default-executor-2985] ERROR com.ywt.rpc.impl.UserServiceImpl - getUserInfoByOpenId(21, oXqGisxBk08MtJBVFDSZc2UpTbQk): UNAVAILABLE: all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial tcp ***.**.**.***:****: getsockopt: connection refused" io.grpc.StatusRuntimeException: UNAVAILABLE: all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial tcp ***.**.**.***:****: getsockopt: connection refused" at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:210) at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:191) at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:124) ``` ## 日志输出规范要求 #### 日志结构体 日志输出的信息结构体必须涵盖**日期**、**时间**、**日志级别**、**代码位置**、**日志内容**等信息。 #### 日志内容 日志内容输出规范相当重要,因为日志是给人阅读的,日志内容词语必须是业务相关的专业术语,可以顾名思义,即可以让人一看就清楚知道什么业务的日志,执行到了哪一步,执行的结果是什么,最禁忌的是使用意义不明的自费作为日志信息,如:`==========`、`—————`、`111111111111111`。 禁止输出敏感信息,比如账号密码等。 #### 日志时效性 顾名思义就是日志文件时间的有效性,中小型的项目保留时间一般设定为`7~30`天。有时候出现了问题 或 异常,我们并不能及时发现,这时我们就需要追溯到之前的历史日志,因而需要将日志保存一定的时长以便于日志追溯。 #### 日志聚合 目前我们的架构使用 `ELK` 技术栈,`Elasticsearch` + `FileBeat` + `Kibana` 三大组件,提供分布式搜索引擎、数据收集处理引擎以及数据缓冲队列,实现全文搜索和分析引擎、提供搜集、分析和存储数据三大功能。 #### 日志性能 首先明确一点,无论是将日志写于文件还是记录于数据库,都是**需要消耗 IO 资源**,IO 操作必然会带来 CPU 的抢占与消耗,因而打印日志并不是越多越好,适当合理才是最好的,也就是需要合理地输出日志才有利于提高程序的性能。 #### 注意事项: - 尽量避免在循环体做日志输出,大量日志输出会降低系统性能 - 禁止输出日志内容体日志,比如 `base64` 的图片、Excel 表格内容数据等 - 生产上不允许执行调试级别的日志 - 禁止输出没有意义性的日志 - 开发调试过程中的 **debug 日志,如无必要,提交代码前请注释掉** ## 对日志的思考 正确看待日志的重要性,**养成合理打印日志信息习惯**,请务必对自己的编码 `review` ,**检查日志是否满足规范**。