在传统系统中,如果能够提供日志输出,基本上已经能够满足需求的。但一旦将系统拆分成两套及以上的系统,再加上负载均衡等,调用链路就变得复杂起来。
特别是进一步向微服务方向演化,如果没有日志的合理规划、链路追踪,那么排查日志将变得异常困难。
比如系统A、B、C,调用链路为A -> B -> C,如果每套服务都是双活,则调用路径有2的三次方种可能性。如果系统更多,服务更多,调用链路则会成指数增长。
因此,无论是几个简单的内部服务调用,还是复杂的微服务系统,都需要通过一个机制来实现日志的链路追踪。让你系统的日志输出,像诗一样有形式美,又有和谐的韵律。
日志追踪其实已经有很多现成的框架了,比如Sleuth、Zipkin等组件。但这不是我们要讲的重点,本文重点基于Spring Boot、LogBack来手写实现一个简单的日志调用链路追踪功能。基于此实现模式,大家可以更细粒度的去实现。
Spring Boot中集成Logback
Spring Boot本身就内置了日志功能,这里使用logback日志框架,并对输出结果进行格式化。先来看一下SpringBoot对Logback的内置集成,依赖关系如下。当项目中引入了:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
spring-boot-starter-web中间接引入了:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
spring-boot-starter又引入了logging的starter:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-logging</artifactId>
- </dependency>
在logging中真正引入了所需的logback包:
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-to-slf4j</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jul-to-slf4j</artifactId>
- </dependency>
因此,我们使用时,只需将logback-spring.xml配置文件放在resources目录下即可。理论上配置文件命名为logback.xml也是支持的,但Spring Boot官网推荐使用的名称为:logback-spring.xml。
然后,在logback-spring.xml中进行日志输出的配置即可。这里不贴全部代码了,只贴出来相关日志输出格式部分,以控制台输出为例:
在value属性的表达式中,我们新增了自定义的变量值requestId,通过“[%X{requestId}]”的形式来展示。
这个requestId便是我们用来追踪日志的唯一标识。如果一个请求,从头到尾都使用了同一个requestId便可以把整个请求链路串联起来。如果系统还基于EKL等日志搜集工具进行统一收集,就可以更方便的查看整个日志的调用链路了。
那么,这个requestId变量是如何来的,又存储在何处呢?要了解这个,我们要先来了解一下日志框架提供的MDC功能。