后端开发日志规范
文章目录
- 后端开发日志规范
-
- 日志的作用
- 什么时候记录日志
- 日志记录原则
- 日志等级设置规范
- 日志使用实践
-
- 打印日志的代码不允许失败,阻断流程
- 禁止使用System.out.println()输出日志
- 禁止直接使用日志系统(Log4j、Logback)中的API
- 声明日志工具对象Logger应声明为private static final
- 对于trace/debug/info级别的日志输出,必须进行日志级别的开关判断
- 捕获异常后不要使用e.printStackTrace()打印日志
- 打印异常日志一定要输出全部错误信息
- 日志打印时禁止直接用JSON工具将对象转换成String
- 不要打印无意义(无业务上下文、无关联日志链路id)的日志
- 不要在循环中打印INFO级别日志
- 不要打印重复的日志
- 避免敏感信息输出
- 日志语言尽量使用英文
- 重要方法可以记录调用日志
- 在核心业务逻辑中遇到if...else等条件,尽量每个分支首行都打印日志
- 建议只打印必要的参数,不要整个对象打印
日志的作用
故障排查和调试
- 日志记录了系统运行过程中的各种事件、操作和错误信息,有助于开发人员快速定位和解决问题,提高系统的稳定性和可靠性。
性能监控和优化
- 通过分析日志信息,可以了解系统的性能表现,包括请求响应时间、资源利用情况等,有助于发现性能瓶颈并进行优化。
安全审计和监控
- 日志记录了系统的操作轨迹和访问记录,可以用于安全审计和监控,及时发现异常行为和安全漏洞。
用户行为分析
- 通过分析用户的操作行为和访问记录,可以了解用户的偏好和行为习惯,为产品改进和优化提供参考。
什么时候记录日志
代码初始化时或进入逻辑入口时
- 系统或者服务的启动参数。核心模块或者组件初始化过程中往往依赖一些关键配置,根据参数不同会提供不一样的服务。务必在这里记录
INFO
日志,打印出参数以及启动完成态服务表述。
编程语言提示异常
- 这类捕获的异常是系统告知开发人员需要加以关注的,是质量非常高的报错。应当适当记录日志,根据实际结合业务的情况使用
WARN
或者ERROR级别。
业务流程预期不符
- 项目代码中结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确,数据处理问题导致返回码不在合理范围内等等。
系统/业务核心逻辑的关键动作
- 系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录
INFO
级别日志。
第三方服务远程调用
- 微服务架构体系中有一个重要的点就是第三方永远不可信,对于第三方服务远程调用建议打印请求和响应的参数,方便在和各个终端定位问题,不会因为第三方服务日志的缺失变得手足无措。
日志记录原则
清晰性和一致性
- 日志消息应该清晰、简洁,并且在格式上保持一致,以便开发人员更容易阅读和理解。
相关性
- 只记录与故障排查、监控或审计相关的信息。避免记录敏感信息,如密码或个人数据。
日志级别
- 适当使用不同的日志级别(如
DEBUG
、INFO
、WARN、ERROR
)来指示日志消息的严重程度。这有助于过滤和优先处理日志消息。
时间戳
- 在日志消息中包含时间戳,以提供事件的时间顺序记录。这有助于理解操作的顺序和诊断问题。
上下文信息
- 在日志消息中包含相关的上下文信息,如请求参数、用户ID和错误详情,以提供更多的调试上下文。
错误处理
- 当发生异常时,记录详细的错误消息,包括堆栈跟踪。这些信息对于识别错误的根本原因至关重要。
性能影响
- 注意日志记录对性能的影响。避免过度记录可能降低系统性能的日志信息。
日志轮换和保留
- 实施日志轮换和保留策略,有效管理日志文件,并防止占用过多的磁盘空间。
日志等级设置规范
DEBUG(调试)
DEUBG
级别的主要输出调试性质的内容,该级别日志主要用于在开发、测试阶段输出。该级别的日志应尽可能地详尽,开发人员可以将各类详细信息记录到DEBUG
里,起到调试的作用,包括参数信息,调试细节信息,返回值信息等等,便于在开发、测试阶段出现问题或者异常时,对其进行分析。
INFO(信息)
INFO
级别的主要记录系统关键信息,旨在保留系统正常工作期间关键运行指标,开发人员可以将初始化系统配置、业务状态变化信息,或者用户业务流程中的核心处理记录到INFO日志中,方便日常运维工作以及错误回溯时上下文场景复现。- 建议在项目完成后,在测试环境将日志级别调成
INFO
,然后通过INFO
级别的信息看看是否能了解这个应用的运用情况,如果出现问题后是否这些日志能否提供有用的排查问题的信息。
WARN(警告)
WARN
级别的主要输出警告性质的内容,这些内容是可以预知且是有规划的,比如,某个方法入参为空或者该参数的值不满足运行该方法的条件时。- 在
WARN
级别的时应输出较为详尽的信息,以便于事后对日志进行分析。
ERROR(错误)
ERROR
级别主要针对于一些不可预知的信息,诸如:错误、异常等,比如,在catch块中抓获的网络通信、数据库连接等异常,若异常对系统的整个流程影响不大,可以使用WARN
级别日志输出。- 在输出
ERROR
级别的日志时,尽量多地输出方法入参数、方法执行过程中产生的对象等数据,在带有错误、异常对象的数据时,需要将该对象一并输出。
TRACE(跟踪)
- 用于记录非常详细的信息,有助于跟踪请求或操作在应用程序中的流程。跟踪消息比调试消息更为细致。
OFF(关闭)
- 关闭所有日志记录。通常情况下不使用此级别,但可以在某些场景下设置为完全禁用日志记录。
日志使用实践
打印日志的代码不允许失败,阻断流程
- 一定要确保不会因为日志打印语句抛出异常造成业务流程中断,如下图所示,
shop
为null
的会导致抛出NPE
。
public void doSth(){
log.info("do sth and print log: {}", shop.getId());
// 业务逻辑
...
}
禁止使用System.out.println()输出日志
反例:
public void doSth(){
System.out.println("doSth...");
// 业务逻辑
...
}
分析:
- 通过分析
System.out.println
源码可知,System.out.println是一个同步方法,在高并发的情况下,大量执行println
方法会严重影响性能。
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
- 不能实现日志按等级输出。具体来说就是不能和日志框架一样,有
debug
,info
,error
等级别的控制。 - System.out、System.error打印的日志都并没有打印在日志文件中,而是直接打印在终端,无法对日志进行收集。
正例:
在日常开发或者调试的过程中,尽量使用标准日志记录系统log4j2
或者logback
(但不要直接使用其中的API
),异步的进行日志统一收集。
public void doSth(){
log.info("doSth...");
// 业务逻辑
...
}
禁止直接使用日志系统(Log4j、Logback)中的API
- 应用中不可直接使用日志系统(
Log4j
、Logback)中的API
,而应依赖使用日志框架 (SLF4J、JCL--Jakarta Commons Logging
)中的API。
分析:
直接使用Log4j
或者Logback
中的API会导致系统代码实现强耦合日志系统,后续需要切换日志实现时会产生比较大的改造成本,统一使用SLF4J
或者JCL
等日志框架的API
,其是使用门面模式的日志框架,可以做到解耦具体日志实现的作用,有利于后续维护和保证各个类的日志处理方式统一。
正例:
// 使用 SLF4J:
import org.slf4j.Logger;
import org.slf4j.<