在上一篇文章【ApiBoot Logging使用SpringCloud Openfeign透传链路信息】中我们详细的讲解了ApiBoot Logging整合SpringCloud通过Openfeign进行透传链路信息,包括traceId(链路编号)、parentSpanId(上级单元编号)等信息。ApiBoot Logging不仅仅可以使用Openfeign传递链路信息,还支持RestTemplate方式,本篇文章来详细的讲解下具体的使用方式。
我们需要搭建Logging Admin服务,用于接收业务服务上报的请求日志信息,请参考【将ApiBoot Logging采集的日志上报到Admin】文章内容.
由于本章采用是Maven 多模块的方式构建源码,所以我们只需要将ApiBoot统一版本的依赖配置在root项目的pom.xml内,如下所示:
1.82.1.5.RELEASEorg.minbox.frameworkapi-boot-dependencies${api.boot.version}pomimport
接下来我们营造本篇文章的模拟场景,查询用户基本信息时一并查询出用户的账号余额。
创建一个名为account-service的SpringBoot项目。
在项目pom.xml配置文件内添加相关依赖,如下所示:
org.springframework.bootspring-boot-starter-weborg.minbox.frameworkapi-boot-starter-logging
在application.yml配置文件内添加请求日志上报的Logging Admin地址,如下所示:
spring:
application:
name: account-service
server:
port: 9090
api:
boot:
logging:
# 控制台打印请求日志
show-console-log: true
# 美化请求日志
format-console-log-json: true
# Logging Admin地址
admin:
server-address: 127.0.0.1:8081
注意:server-address配置参数不需要添加http://前缀
添加完成依赖后我们通过@EnableLoggingClient注解来启用ApiBoot Logging,在AccountServiceApplication类上添加如下所示:
/**
* 账户服务
*
* @author 恒宇少年
*/
@SpringBootApplication
@EnableLoggingClient
public class AccountServiceApplication {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(AccountServiceApplication.class);
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
logger.info("{}服务启动成功.", "账户");
}
}
@EnableLoggingClient注解就实例化部分ApiBoot Logging内部所需要的类,将实例放置到Spring IOC容器内。
我们创建一个名为AccountController的控制器来提供查询账户的余额信息,代码实现如下所示:
/**
* 账户服务实现
*
* @author 恒宇少年
*/
@RestController
@RequestMapping(value = "/account")
public class AccountController {
/**
* 示例,内存账户列表
*/
static final HashMap ACCOUNTS = new HashMap() {{
put(1, 1233.22);
put(2, 69269.22);
}};
/**
* 获取指定账户的余额
*
* @param accountId
* @return
*/
@GetMapping(value = "/{accountId}")
public Double getBalance(@PathVariable("accountId") Integer accountId) {
return ACCOUNTS.get(accountId);
}
},>
至此我们的账户服务已经编写完成,下面我们来编写用户服务。
我们来创建一个名为user-service的SpringBoot项目。
在项目pom.xml配置文件内添加相关依赖,如下所示:
org.springframework.bootspring-boot-starter-weborg.minbox.frameworkapi-boot-starter-logging
本章我们使用指定Logging Admin地址的方式配置,修改application.yml配置文件如下所示:
spring:
application:
name: user-service
server:
port: 9091
api:
boot:
logging:
# 控制台打印请求日志
show-console-log: true
# 美化请求日志
format-console-log-json: true
# Logging Admin地址
admin:
server-address: 127.0.0.1:8081
添加完依赖后我们需要在XxxApplication入口类上添加@EnableLoggingClient注解来启用ApiBoot Logging,如下所示:
/**
* 用户服务
*
* @author 恒宇少年
*/
@SpringBootApplication
@EnableLoggingClient
public class UserServiceApplication {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(UserServiceApplication.class);
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
logger.info("{}服务启动成功.", "用户");
}
}
在user-service需要访问账户服务获取当前用户的余额,所以我们需要在user-service内实例化RestTemplate,这样我们才可以通过RestTemplate访问获取用户账户余额信息,我们直接在UserServiceApplication类内添加实例,如下所示:
/**
* 实例化RestTemplate
*
* @return {@link RestTemplate}
*/
@Bean
@ConditionalOnMissingBean
public RestTemplate restTemplate() {
return new RestTemplate();
}
注解解释:
@ConditionalOnMissingBean:这是SpringBoot条件注入其中的一个注解,表示当IOC容器内不存在RestTemplate类型的实例时才会去执行restTemplate()方法创建对象。
/**
* 用户基本信息控制器
*
* @author 恒宇少年
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
/**
* 示例,用户列表
*/
static final HashMap USERS = new HashMap() {{
put(1, new User(1, "恒宇少年"));
put(2, new User(2, "于起宇"));
}};
/**
* 注入RestTemplate
*/
@Autowired
private RestTemplate restTemplate;
/**
* 获取用户基本信息
*
* @param userId 用户编号
* @return
*/
@GetMapping(value = "/{userId}")
public User getUserInfo(@PathVariable("userId") Integer userId) {
ResponseEntity responseEntity = restTemplate.getForEntity("http://localhost:9090/account/{accountId}", Double.class, userId);
Double balance = responseEntity.getBody();
User user = USERS.get(userId);
if (ObjectUtils.isEmpty(user)) {
throw new RuntimeException("用户:" + userId + ",不存在.");
}
user.setBalance(balance);
return user;
}
@Data
public static class User {
private Integer id;
private String name;
private Double balance;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
}
},>
我们所需要的两个服务都已经编写完成,下面我们来测试RestTemplate是可以透传ApiBoot Logging的链路信息?
依次启动logging-admin > user-service > account-service。
我们使用curl命令访问user-service提供的地址/user,如下所示:
➜ ~ curl http://localhost:9091/user/1
{"id":1,"name":"恒宇少年","balance":1233.22}
下面我看来看下logging-admin控制台接收到的请求日志。
接收user-service请求日志
Receiving Service: 【user-service -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1573032865311,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"host":"localhost:9091",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"GET",
"requestParam":"{}",
"requestUri":"/user/1",
"responseBody":"{/"id/":1,/"name/":/"恒宇少年/",/"balance/":1233.22}",
"responseHeaders":{},
"serviceId":"user-service",
"serviceIp":"127.0.0.1",
"servicePort":"9091",
"spanId":"f8cff018-42d5-481f-98df-c19b7196b3c3",
"startTime":1573032865130,
"timeConsuming":181,
"traceId":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57"
}
]
接收account-service请求日志
Receiving Service: 【account-service -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1573032865309,
"httpStatus":200,
"parentSpanId":"f8cff018-42d5-481f-98df-c19b7196b3c3",
"requestBody":"",
"requestHeaders":{
"minbox-logging-x-parent-span-id":"f8cff018-42d5-481f-98df-c19b7196b3c3",
"minbox-logging-x-trace-id":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57",
"host":"localhost:9090",
"connection":"keep-alive",
"accept":"application/json, application/*+json",
"user-agent":"Java/1.8.0_211"
},
"requestIp":"127.0.0.1",
"requestMethod":"GET",
"requestParam":"{}",
"requestUri":"/account/1",
"responseBody":"1233.22",
"responseHeaders":{},
"serviceId":"account-service",
"serviceIp":"127.0.0.1",
"servicePort":"9090",
"spanId":"63b18b40-5718-431c-972f-78956ce78380",
"startTime":1573032865307,
"timeConsuming":2,
"traceId":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57"
}
]
user-service服务内的/user路径时,因为是第一次访问ApiBoot Logging会主动创建traceId(链路编号)、spanId(单元编号),因为没有上级单元所以parentSpanId为null.
而通过查看account-service服务上报的请求日志时,可以看到ApiBoot Logging相关的链路信息是通过HttpHeader的方式进行传递的
minbox-logging-x-trace-id -> 链路编号minbox-logging-x-parent-span-id -> 上级单元编号
ApiBoot Logging在内部自动化实现了RestTemplate的拦截器配置,所以我们只需要创建实例就可以,而不需要主动去配置拦截器信息,具体源码请访问org.minbox.framework.logging.client.http.rest.LoggingRestTemplateInterceptor查看。
不管你一次请求跨度几个服务,都可以将请求入口生成的链路信息进行依次传递,而上下级关系则是根据parentSpanId、spanId进行绑定的。
审核编辑 黄昊宇
全部0条评论
快来发表一下你的评论吧 !