1. 组件
日志组件有很多,日志门面的选择
- Slf4j
- Apache Commons Logging
日志的实现有:
- log4j
- logback
- log4j2
- Java Util Logging(jul)
- Jboss Logging
建议统一使用Slf4j作为日志门面,logback作为日志实现。
2. 级别
日志的级别有很多,我们一般只用四个。日志级别由低到高DEBUG - INFO - WARN - ERROR。
- DEBUG(调试):开发调试日志。一般来说,在系统实际运行过程中,不会输出该级别的日志。
- INFO(通知):INFO日志级别主要用于记录系统运行状态等关联信息。在这里输出的信息,应该对最终用户具有实际意义。
- WARN(警告):WARN日志常用来表示系统模块发生问题,但并不影响系统运行。虽然不需要马上处理,但是也需要引起重视。某些用户危险的操作,例如一直采用错误密码尝试登陆管理员账号的行为,可以提升到WARN日志级别记录。
- ERROR(错误):此信息输出后,主体系统核心模块需要修复才能正常工作。系统中出现该级别日志应该及时解决。
3. 场景
在我们的系统中,不同的日志级别的打印场景大致如下:
日志级别 | 打印场景 |
---|---|
DEBUG | 调试日志。没有严格要求。 |
INFO | 业务日志。用来记录业务的主流程的走向。 |
WARN | 警告日志。一般来说,发生对整个系统没什么影响的异常时,可以打印该级别的日志。 |
ERROR | 错误日志。级别比较高,一般如果发生一些异常,都需要打印。 |
4. 使用方式
编写位置
- 系统/应用启动和参数变更。当系统启动时,可以将相关的参数信息进行打印,以便出现问题时,更准确地查询原因;参数信息可能并不存储在本地,需要通过配置中心获取,而参数信息有变更时,也需要将变更后的内容输出在日志中。
- 关键操作节点。最典型的就是在关键位置添加日志,记录用户进行的某个操作。
- 大型任务进度上报。当系统在处理某个比较大型的任务时,可以在这个过程中增加相关的日志来表明任务处理的进度,防止因为长时间没有处理而无法得知程序执行的状态,比如在定时任务中,增加当前任务完成百分比。
- 异常。如果是通过 try-catch 处理,需要注意日志编写的位置。如果需要将日志在本层抛出,则不需要进行日志记录,否则会出现日志重复的问题。
- 批量操作。涉及到数量的操作要打印log,比如查询数据库和批量拷贝文件、上传下载、批量格式转换等批量操作,设计到的数量要打印出来。
格式
日志的格式布局会影响日志内容收集与管理的效率。日志编写时需要注意的事项:
- 系统之间格式保持一致:每个应用在日志格式上尽量保持统一,这样,在进行日志收集时,就可以采用统一的日志模板来收集和格式化内容。
- 不编写多行的日志内容:除了异常堆栈信息,不对日志内容进行多行的输出,多行的内容十分不便于数据解析,可能会出现生成多条日志的情况。
- 不要使用日志中的常见内容来分割:如果采用日志中常见的内容来分割,会在格式解析时出现问题,比如用户 ID 中的空格就是比较常见的内容。
面向接口
private static final Logger logger = LoggerFactory.getLogger(AuthAspect.class);
使用时应面向接口编程,要求使用slf4j日志门面,LOGGER/LoggerFactory应该都是slf4j的API。严禁直接使用日志实现包。原因大致有两点,第一是面向接口编程更优雅,这点不必说明;第二,便于切换具体的日志实现方式,举个例子,因为log4j已经几年不更新,老的项目可能使用了log4j,现在想要换用logback或者log4j2,如