引言

日志用来记录用户操作、系统运行状态等,是一个系统的重要组成部分。 然而,由于日志通常不属于系统的核心功能,所以常常不被团队成员所重视。对于一些简单的小程序,可能并不需要在如何记录日志的问题上花费太多精力。但是对于作为基础平台为很多产品提供服务的后端程序,就必须要考虑如何依靠良好的日志来保证系统可靠的运行了。

工程配置

使用slf4j作为日志门面,logback作为日志实现,把其他日志组件的调用转换到slf4j。

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 可到https://mvnrepository.com获取最新version版本
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- common-logging 实际调用slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- java.util.logging 实际调用slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- log4j实际调用slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>

logback配置

详见:logback配置

jrebel配置

在本地开发过程中,希望把日志打印到stdout,需要配合jrebel插件来实现。通过jrebel插件来启动tomcat的时候,就会优先找到 target/test­-classes/logback­-test.xml文件,这样就会把日志信息输出到stdout了。当正式打包的时候,不会打包test目录下的资源信息。这样就能实现线上和线下2套配置,互不影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">

<classpath>
<!-- 查找资源文件的时候,优先从target/test-classes目录下查找 -->
<dir name="/Users/max/Documents/workSpace/open-msg/target/test-classes">
</dir>
<dir name="/Users/max/Documents/workSpace/open-msg/target/classes">
</dir>
</classpath>
<web>
<link target="/">
<dir name="/Users/max/Documents/workSpace/open-msg/src/main/webapp">
</dir>
</link>
</web>
</application>

合理的日志级别

  1. 要用异步日志;
  2. 要做日志轮转;
  3. 要有上下文信息;
  4. 不要疯狂打日志。
日志级别 打印建议
DEBUG(调试) 不建议在线上环境打印DEBUG日志,在需要的时候可以通过开关打开DEBUG日志,默认需要关闭DEBUG日志。过多的DEBUG日志,并不是好事,特别反对通过aop把函数调用的参数和返回值信息都记录到DEBUG日志中的做法。
INFO(通知) 业务日志用来记录业务的主流程的走向。INFO日志级别主要用于记录系统运行状态等关联信息。该日志级别,常用于反馈系统当前状态给最终用户。所以,在这里输出的信息,应该对最终用户具有实际意义,也就是最终用户要能够看得明白是什么意思才行。
WARN(警告) WARN日志常用来表示系统模块发生问题,但并不影响系统运行。 此时,进行一些修复性的工作,还能把系统恢复到正常的状态。参数验证错误类的可以使用WARN。
ERROR(错误) 此信息输出后,主体系统核心模块正常工作,需要修复才能正常工作。

必要的日志元素

理想的日志中应该记录不多不少的信息。
所谓不多,是指不要在日志中记录无用的信息。实践中常见到的无用的日志有:

  • 能够放在一条日志里的东西,放在多条日志中输出;
  • 预期会发生且能够被正常处理的异常,打印出一堆无用的堆栈;
  • 开发人员在开发过程中为了调试方便而加入的“临时”日志;

所谓不少,是指对于日志的使用者,能够从日志中得到所有需要的信息。在实践中经常发生日志不够的情况,例如:

  • 请求出错时不能通过日志直接来定位问题,而需要开发人员再临时增加日志并要求请求的发送者重新发送同样的请求才能定位问题;
  • 无法确定服务中的后台任务是否按照期望执行;
  • 无法确定服务的内存数据结构的状态;
  • 无法确定服务的异常处理逻辑(如重试)是否正确执行;
  • 无法确定服务启动时配置是否正确加载;
  • ……