1. 介绍
在微服务项目中,一个请求到达后端后,在处理业务的过程中,可能还会调用其他多个微服务来实现功能,在这个过程中,整个请求的链路追踪就非常重要,我们需要知道每个节点的调用信息。通过这些信息我们能够在程序报错时快速定位到问题或者根据每个节点的请求情况进行性能优化。
Spring Cloud Sleuth是Spring Cloud官方提供的针对分布式链路追踪的解决方案。
1.1 基本术语
Spring Cloud Sleuth的术语借鉴了Google的Dapper。
Span:基本工作单元。最常见的就是发送一个HTTP请求调用另一个微服务。
Trace:一系列span组成的树状结构。
Annotation:用于记录链路中事件。
- cs: Client Sent,客户端发送一个请求,此注解表示一个span的开始。
- sr: Server Received,服务端接收到请求并开始处理,此时时间戳减去
cs
的时间戳即可得到网络延迟。 - ss: Server Sent,请求处理完成时的注解,即发送响应给客户端时。此时时间戳减去
sr
的时间戳即可得到服务端处理请求所需的时间。 - cr: Client Received,客户端成功接收到服务端的响应,表明了一个span的结束。此时时间戳减去
cs
的时间戳即可得到整个请求所需的时间。
下面是一个官方示意图,展现了一个完整的请求链路,每个颜色表示一个span。
2. 快速使用
2.1 引入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-sleuthartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-sleuthartifactId>
dependency>
启动项目后,会出现类似下面的日志:
2020-11-03 17:36:29.472 INFO [foo,a8cfa21613384b70,a8cfa21613384b70,true] 22392 --- [ parallel-1] ...
2020-11-03 17:36:29.474 INFO [foo,a8cfa21613384b70,a8cfa21613384b70,true] 22392 --- [ parallel-1] ...
2020-11-03 17:36:29.472 INFO [foo,a8cfa21613384b70,a8cfa21613384b70,true] 22392 --- [ parallel-1] ...
2020-11-03 17:36:29.474 INFO [foo,a8cfa21613384b70,a8cfa21613384b70,true] 22392 --- [ parallel-1] ...
引入依赖后,Spring Cloud Sleuth就会将traceId和spanId等信息添加到Slf4J MDC中。此功能主要通过TraceEnvironmentPostProcessor
修改了logging.pattern.level
属性。上面的[foo,a8cfa21613384b70,a8cfa21613384b70,true]
分别为:
- applicationName,应用名
- traceId
- spanId
- exportable,是否导出,比如发送到Zipkin
2.2 属性配置
spring:
sleuth:
enabled: true # 开启sleuth,默认true
trace-id128: false # 生成128位id,默认false生成64位
sampler:
probability: 1.0 # 采样率,此处设置为100%采样,优先于限流
rate: 10 # 限流,每秒钟次数,默认10
log:
slf4j:
enabled: true # 开启Slf4J MDC功能,默认true
spring:
sleuth:
enabled: true # 开启sleuth,默认true
trace-id128: false # 生成128位id,默认false生成64位
sampler:
probability: 1.0 # 采样率,此处设置为100%采样,优先于限流
rate: 10 # 限流,每秒钟次数,默认10
log:
slf4j:
enabled: true # 开启Slf4J MDC功能,默认true
2.3 组件支持
- OpenTracing
- Runnable和Callable
- Spring Cloud CircuitBreaker
- Hystrix
- Rxjava
- HTTP
- HTTP Client,包括
RestTemplate
和WebClient
等 - Feign
- gRPC
- 异步方法,包括
@Async
、@Scheduled
注解的方法以及Executor
、ExecutorService
、ScheduledExecutorService
- Messaging,包括
RabbitMQ
、Kafka
、JMS
- Zuul
- Redis
- Quartz
- Reactor
3. Zipkin
生成Trace信息后,我们还需要一个系统来查看和分析链路信息,这时候我们就需要Zipkin了。Zipkin是一个分布式跟踪系统。它可以根据收集到的数据来分析系统中的延迟问题,而且还可以根据条件进行查找。
Zipkin UI还提供了一个依赖关系图,能够显示每个应用的具体请求情况。
3.1 引入依赖
如果我们在项目中引入了依赖,那么当一个span关闭的时候,它就会异步发送到Zipkin服务器。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
3.2 属性配置
3.2.1 Web
默认情况下,应用通过Web的方式发送数据到Zipkin,可以通过属性配置Zipkin服务器地址。
spring:
zipkin:
sender:
type: web
base-url: http://localhost:9411/
compression:
enabled: true #压缩
spring:
zipkin:
sender:
type: web
base-url: http://localhost:9411/
compression:
enabled: true #压缩
3.2.2 RabbitMQ
需要引入spring-rabbit
依赖,默认发送到zipkin队列。
spring:
zipkin:
sender:
type: rabbit
rabbitmq:
queue: zipkin
spring:
zipkin:
sender:
type: rabbit
rabbitmq:
queue: zipkin
3.2.3 Kafka
需要引入spring-kafka
依赖,默认发送到zipkin主题。
spring:
zipkin:
sender:
type: kafka
kafka:
topic: zipkin
spring:
zipkin:
sender:
type: kafka
kafka:
topic: zipkin
3.3 Zipkin服务器搭建
3.3.1 启动
可执行jar包方式(最低Java 8)
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
docker方式
docker run -d -p 9411:9411 openzipkin/zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
3.3.2 配置
Zipkin配置主要包含2个方面:数据收集和数据存储。
一般情况下我们还会生成依赖关系图,所以可以使用docker-compose
的方式一起启动zipkin
和zipkin-dependencies
,这里以RabbitMQ收集ElasticSearch存储为例:
version: '2'
services:
# The zipkin process services the UI, and also exposes a POST endpoint that
# instrumentation can send trace data to. Scribe is disabled by default.
zipkin:
image: openzipkin/zipkin:2.22.0
container_name: zipkin
# Environment settings are defined here https://github.com/openzipkin/zipkin/blob/master/zipkin-server/README.md#environment-variables
environment:
# collector-rabbitmq
- RABBIT_ADDRESSES=http://localhost:5672
- RABBIT_USER=guest
- RABBIT_PASSWORD=guest
- RABBIT_VIRTUAL_HOST=/
# zipkin-storage-elasticsearch
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://localhost:9200
- ES_USERNAME=elastic
- ES_PASSWORD=elastic
- ES_DATE_SEPARATOR=.
- ES_INDEX_SHARDS=1
- ES_INDEX_REPLICAS=0
# Uncomment to see requests to and from elasticsearch
# - ES_HTTP_LOGGING=BODY
# Uncomment to enable scribe
# - SCRIBE_ENABLED=true
# Uncomment to enable self-tracing
# - SELF_TRACING_ENABLED=true
# Uncomment to enable debug logging
# - JAVA_OPTS=-Dlogging.level.zipkin2=DEBUG
restart: always
ports:
# Port used for the Zipkin UI and HTTP Api
- 9411:9411
# Uncomment if you set SCRIBE_ENABLED=true
# - 9410:9410
# Adds a cron to process spans since midnight every hour, and all spans each day
# This data is served by http://192.168.99.100:8080/dependency
#
# For more details, see https://github.com/openzipkin/docker-zipkin-dependencies
zipkin-dependencies:
image: openzipkin/zipkin-dependencies:2.3.2
container_name: zipkin-dependencies
entrypoint: crond -f
environment:
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://localhost:9200
- ES_USERNAME=elastic
- ES_PASSWORD=elastic
- ES_DATE_SEPARATOR=.
# Uncomment to see dependency processing logs
# - ZIPKIN_LOG_LEVEL=DEBUG
# Uncomment to adjust memory used by the dependencies job
# - JAVA_OPTS=-verbose:gc -Xms1G -Xmx1G
restart: always
version: '2'
services:
# The zipkin process services the UI, and also exposes a POST endpoint that
# instrumentation can send trace data to. Scribe is disabled by default.
zipkin:
image: openzipkin/zipkin:2.22.0
container_name: zipkin
# Environment settings are defined here https://github.com/openzipkin/zipkin/blob/master/zipkin-server/README.md#environment-variables
environment:
# collector-rabbitmq
- RABBIT_ADDRESSES=http://localhost:5672
- RABBIT_USER=guest
- RABBIT_PASSWORD=guest
- RABBIT_VIRTUAL_HOST=/
# zipkin-storage-elasticsearch
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://localhost:9200
- ES_USERNAME=elastic
- ES_PASSWORD=elastic
- ES_DATE_SEPARATOR=.
- ES_INDEX_SHARDS=1
- ES_INDEX_REPLICAS=0
# Uncomment to see requests to and from elasticsearch
# - ES_HTTP_LOGGING=BODY
# Uncomment to enable scribe
# - SCRIBE_ENABLED=true
# Uncomment to enable self-tracing
# - SELF_TRACING_ENABLED=true
# Uncomment to enable debug logging
# - JAVA_OPTS=-Dlogging.level.zipkin2=DEBUG
restart: always
ports:
# Port used for the Zipkin UI and HTTP Api
- 9411:9411
# Uncomment if you set SCRIBE_ENABLED=true
# - 9410:9410
# Adds a cron to process spans since midnight every hour, and all spans each day
# This data is served by http://192.168.99.100:8080/dependency
#
# For more details, see https://github.com/openzipkin/docker-zipkin-dependencies
zipkin-dependencies:
image: openzipkin/zipkin-dependencies:2.3.2
container_name: zipkin-dependencies
entrypoint: crond -f
environment:
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=http://localhost:9200
- ES_USERNAME=elastic
- ES_PASSWORD=elastic
- ES_DATE_SEPARATOR=.
# Uncomment to see dependency processing logs
# - ZIPKIN_LOG_LEVEL=DEBUG
# Uncomment to adjust memory used by the dependencies job
# - JAVA_OPTS=-verbose:gc -Xms1G -Xmx1G
restart: always
4. MySQL、MongoDB集成
4.1 MySQL
Spring Cloud Sleuth默认没有集成对MySQL的支持,通过查看brave-instrumentation-mysql8文档,可以通过在数据库连接地址后追加queryInterceptors=brave.mysql8.TracingQueryInterceptor&exceptionInterceptors=brave.mysql8.TracingExceptionInterceptor
两个参数来集成,当然同时也要引入依赖:
<dependency>
<groupId>io.zipkin.bravegroupId>
<artifactId>brave-instrumentation-mysql8artifactId>
dependency>
<dependency>
<groupId>io.zipkin.bravegroupId>
<artifactId>brave-instrumentation-mysql8artifactId>
dependency>
但是通过追加参数的配置方式,每次开启或关闭链路追踪都需要修改数据库配置,比较麻烦,所以想参考官方的方式,只需要配置一个enabled
的属性即可控制。
4.1.1 EnvironmentPostProcessor
第一个想到的方案就是自定义一个EnvironmentPostProcessor
,在Environment
准备好后根据enabled
的值来改写数据库连接的url达到目的,但是通过调试发现,此时读取到的Environment
的值都是本地配置文件,在Spring Cloud项目中,很多环境下都是从config-server读取配置,而默认情况下远程配置的优先级是最高的,就算此时往Environment
里添加PropertySource
,改写后的数据库url也会被远程配置覆盖,所以此方法行不通。
EnvironmentPostProcessor
的实现类需要在META-INF/spring.factories
文件中注册。# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.TraceMySQLEnvironmentPostProcessor
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.TraceMySQLEnvironmentPostProcessor
4.2.2 BeanPostProcessor
上述方法不可行后,我们可以通过实现BeanPostProcessor
接口,在DataSourceProperties
调用初始化回调方法之前,设置一个新的url值以达到目的。
public class TraceMySQLBeanPostProcessor implements BeanPostProcessor, EnvironmentAware {
private static final String URL_PREFIX = "jdbc:";
private static final String QUERY_INTERCEPTORS_KEY = "queryInterceptors";
private static final String QUERY_INTERCEPTORS_VALUE = "brave.mysql8.TracingQueryInterceptor";
private static final String EXCEPTION_INTERCEPTORS_KEY = "exceptionInterceptors";
private static final String EXCEPTION_INTERCEPTORS_VALUE = "brave.mysql8.TracingExceptionInterceptor";
private static final boolean TRACE_MYSQL_PRESENT = ClassUtils.isPresent(QUERY_INTERCEPTORS_VALUE,
TraceMySQLApplicationContextInitializer.class.getClassLoader());
private Environment environment;
@Override
public void setEnvironment(@NonNull Environment environment) {
this.environment = environment;
}
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) {
if (bean instanceof DataSourceProperties) {
DataSourceProperties properties = (DataSourceProperties) bean;
this.postProcessBean(properties);
}
return bean;
}
private void postProcessBean(DataSourceProperties properties) {
// 默认不启用
boolean enabled = environment.getProperty("hosjoy.sleuth.mysql.enabled", boolean.class, false);
// 启用并且存在相关类
if (!(enabled && TRACE_MYSQL_PRESENT)) {
return;
}
// 首先获取配置的数据库url
String url = properties.getUrl();
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url);
if (StringUtils.isBlank(url)) {
return;
}
// 不是mysql
if (!DatabaseDriver.MYSQL.equals(databaseDriver)) {
return;
}
String urlWithoutPrefix = url.substring(URL_PREFIX.length());
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(urlWithoutPrefix);
MultiValueMap oldParams = uriComponentsBuilder.build().getQueryParams();if (!oldParams.containsKey(QUERY_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(QUERY_INTERCEPTORS_KEY, QUERY_INTERCEPTORS_VALUE);
}if (!oldParams.containsKey(EXCEPTION_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(EXCEPTION_INTERCEPTORS_KEY, EXCEPTION_INTERCEPTORS_VALUE);
}
String newUrl = URL_PREFIX + uriComponentsBuilder.build().toUriString();
properties.setUrl(newUrl);
}
}
public class TraceMySQLBeanPostProcessor implements BeanPostProcessor, EnvironmentAware {
private static final String URL_PREFIX = "jdbc:";
private static final String QUERY_INTERCEPTORS_KEY = "queryInterceptors";
private static final String QUERY_INTERCEPTORS_VALUE = "brave.mysql8.TracingQueryInterceptor";
private static final String EXCEPTION_INTERCEPTORS_KEY = "exceptionInterceptors";
private static final String EXCEPTION_INTERCEPTORS_VALUE = "brave.mysql8.TracingExceptionInterceptor";
private static final boolean TRACE_MYSQL_PRESENT = ClassUtils.isPresent(QUERY_INTERCEPTORS_VALUE,
TraceMySQLApplicationContextInitializer.class.getClassLoader());
private Environment environment;
@Override
public void setEnvironment(@NonNull Environment environment) {
this.environment = environment;
}
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) {
if (bean instanceof DataSourceProperties) {
DataSourceProperties properties = (DataSourceProperties) bean;
this.postProcessBean(properties);
}
return bean;
}
private void postProcessBean(DataSourceProperties properties) {
// 默认不启用
boolean enabled = environment.getProperty("hosjoy.sleuth.mysql.enabled", boolean.class, false);
// 启用并且存在相关类
if (!(enabled && TRACE_MYSQL_PRESENT)) {
return;
}
// 首先获取配置的数据库url
String url = properties.getUrl();
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url);
if (StringUtils.isBlank(url)) {
return;
}
// 不是mysql
if (!DatabaseDriver.MYSQL.equals(databaseDriver)) {
return;
}
String urlWithoutPrefix = url.substring(URL_PREFIX.length());
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(urlWithoutPrefix);
MultiValueMap oldParams = uriComponentsBuilder.build().getQueryParams();if (!oldParams.containsKey(QUERY_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(QUERY_INTERCEPTORS_KEY, QUERY_INTERCEPTORS_VALUE);
}if (!oldParams.containsKey(EXCEPTION_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(EXCEPTION_INTERCEPTORS_KEY, EXCEPTION_INTERCEPTORS_VALUE);
}
String newUrl = URL_PREFIX + uriComponentsBuilder.build().toUriString();
properties.setUrl(newUrl);
}
}
通过测试发现此方法可行,通过/actuator/configprops
接口调用也能发现DataSourceProperties
的值确实是新的url,但是调用/actuator/env
接口还是老的url,即如果在程序中手动调用environment.getProperty("spring.datasource.url")
方法,获取到的还是老的url,不是很完美。
4.2.3 ApplicationContextInitializer
通过追踪Spring Boot的启动过程,发现Spring Cloud Config Client是通过PropertySourceBootstrapConfiguration
类来从远程获取配置然后放入Environment
中,PropertySourceBootstrapConfiguration
就是实现了ApplicationContextInitializer
接口。所以我们也可以实现一个自定义的ApplicationContextInitializer
,在读取远程配置后,把链路追踪的数据库url添加到Environment
中,并设置优先级最高。完整代码如下:
public class TraceMySQLApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
public static final String PROPERTY_SOURCE_NAME = "traceMySQLProperties";
private static final String PROPERTY = "spring.datasource.url";
private static final String URL_PREFIX = "jdbc:";
private static final String QUERY_INTERCEPTORS_KEY = "queryInterceptors";
private static final String QUERY_INTERCEPTORS_VALUE = "brave.mysql8.TracingQueryInterceptor";
private static final String EXCEPTION_INTERCEPTORS_KEY = "exceptionInterceptors";
private static final String EXCEPTION_INTERCEPTORS_VALUE = "brave.mysql8.TracingExceptionInterceptor";
private static final boolean TRACE_MYSQL_PRESENT = ClassUtils.isPresent(QUERY_INTERCEPTORS_VALUE,
TraceMySQLApplicationContextInitializer.class.getClassLoader());
/**
* 优先级最低, 在Spring Cloud Config Client加载完远程配置后再执行, 让traceMySQLProperties的优先级最高
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
// 默认不启用
boolean enabled = environment.getProperty("hosjoy.sleuth.mysql.enabled", boolean.class, false);
// 启用并且存在相关类
if (!(enabled && TRACE_MYSQL_PRESENT)) {
return;
}
// 首先获取配置的数据库url
String url = environment.getProperty(PROPERTY);
if (StringUtils.isBlank(url)) {
return;
}
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url);
// 不是mysql
if (!DatabaseDriver.MYSQL.equals(databaseDriver)) {
return;
}
String urlWithoutPrefix = url.substring(URL_PREFIX.length());
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(urlWithoutPrefix);
MultiValueMap oldParams = uriComponentsBuilder.build().getQueryParams();if (!oldParams.containsKey(QUERY_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(QUERY_INTERCEPTORS_KEY, QUERY_INTERCEPTORS_VALUE);
}if (!oldParams.containsKey(EXCEPTION_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(EXCEPTION_INTERCEPTORS_KEY, EXCEPTION_INTERCEPTORS_VALUE);
}
String newUrl = URL_PREFIX + uriComponentsBuilder.build().toUriString();
ImmutableMap map = ImmutableMap.of(PROPERTY, newUrl);
MapPropertySource propertySource = new MapPropertySource(PROPERTY_SOURCE_NAME, map);
environment.getPropertySources().addFirst(propertySource);
}
}
public class TraceMySQLApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
public static final String PROPERTY_SOURCE_NAME = "traceMySQLProperties";
private static final String PROPERTY = "spring.datasource.url";
private static final String URL_PREFIX = "jdbc:";
private static final String QUERY_INTERCEPTORS_KEY = "queryInterceptors";
private static final String QUERY_INTERCEPTORS_VALUE = "brave.mysql8.TracingQueryInterceptor";
private static final String EXCEPTION_INTERCEPTORS_KEY = "exceptionInterceptors";
private static final String EXCEPTION_INTERCEPTORS_VALUE = "brave.mysql8.TracingExceptionInterceptor";
private static final boolean TRACE_MYSQL_PRESENT = ClassUtils.isPresent(QUERY_INTERCEPTORS_VALUE,
TraceMySQLApplicationContextInitializer.class.getClassLoader());
/**
* 优先级最低, 在Spring Cloud Config Client加载完远程配置后再执行, 让traceMySQLProperties的优先级最高
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
// 默认不启用
boolean enabled = environment.getProperty("hosjoy.sleuth.mysql.enabled", boolean.class, false);
// 启用并且存在相关类
if (!(enabled && TRACE_MYSQL_PRESENT)) {
return;
}
// 首先获取配置的数据库url
String url = environment.getProperty(PROPERTY);
if (StringUtils.isBlank(url)) {
return;
}
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url);
// 不是mysql
if (!DatabaseDriver.MYSQL.equals(databaseDriver)) {
return;
}
String urlWithoutPrefix = url.substring(URL_PREFIX.length());
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(urlWithoutPrefix);
MultiValueMap oldParams = uriComponentsBuilder.build().getQueryParams();if (!oldParams.containsKey(QUERY_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(QUERY_INTERCEPTORS_KEY, QUERY_INTERCEPTORS_VALUE);
}if (!oldParams.containsKey(EXCEPTION_INTERCEPTORS_KEY)) {
uriComponentsBuilder.queryParam(EXCEPTION_INTERCEPTORS_KEY, EXCEPTION_INTERCEPTORS_VALUE);
}
String newUrl = URL_PREFIX + uriComponentsBuilder.build().toUriString();
ImmutableMap map = ImmutableMap.of(PROPERTY, newUrl);
MapPropertySource propertySource = new MapPropertySource(PROPERTY_SOURCE_NAME, map);
environment.getPropertySources().addFirst(propertySource);
}
}
同
EnvironmentPostProcessor
一样,ApplicationContextInitializer
的实现类也需要在META-INF/spring.factories
文件中注册。# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
com.example.TraceMySQLApplicationContextInitializer
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
com.example.TraceMySQLApplicationContextInitializer
4.2 MongoDB
相比于MySQL,MongoDB的集成就比较简单了,我们只需要根据条件配置一个Bean即可。
<dependency>
<groupId>io.zipkin.bravegroupId>
<artifactId>brave-instrumentation-mongodbartifactId>
dependency>
<dependency>
<groupId>io.zipkin.bravegroupId>
<artifactId>brave-instrumentation-mongodbartifactId>
dependency>
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({MongoClient.class, MongoDBTracing.class})
@ConditionalOnProperty(prefix = SleuthProperties.PREFIX, name = "mongodb.enabled")
@AutoConfigureAfter(org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration.class)public class MongoDBConfiguration {
@Bean
public MongoClientSettingsBuilderCustomizer traceMongoClientSettingsBuilderCustomizer() {
CommandListener listener = MongoDBTracing.create(Tracing.current()).commandListener();
return builder -> builder.addCommandListener(listener);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({MongoClient.class, MongoDBTracing.class})
@ConditionalOnProperty(prefix = SleuthProperties.PREFIX, name = "mongodb.enabled")
@AutoConfigureAfter(org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration.class)public class MongoDBConfiguration {
@Bean
public MongoClientSettingsBuilderCustomizer traceMongoClientSettingsBuilderCustomizer() {
CommandListener listener = MongoDBTracing.create(Tracing.current()).commandListener();
return builder -> builder.addCommandListener(listener);
}
}