在上一篇文章【/apiboot-logging-using-openfeign-transparent-traceid.html】中我们详细的讲解了ApiBoot Logging整合SpringCloud通过Openfeign进行透传链路信息,包括traceId(链路编号)、parentSpanId(上级单元编号)等信息。
ApiBoot Logging不仅仅可以使用Openfeign传递链路信息,还支持RestTemplate方式,本篇文章来详细的讲解下具体的使用方式。
搭建Logging Admin
我们需要搭建Logging Admin服务,用于接收业务服务上报的请求日志信息,请参考【/apiboot-report-logs-by-logging-to-admin.html】文章内容.
添加ApiBoot统一版本
由于本章采用是Maven 多模块的方式构建源码,所以我们只需要将ApiBoot统一版本的依赖配置在root项目的pom.xml内,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <properties> <java.version>1.8</java.version> <api.boot.version>2.1.5.RELEASE</api.boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-dependencies</artifactId> <version>${api.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
接下来我们营造本篇文章的模拟场景,查询用户基本信息时一并查询出用户的账号余额。
创建账户服务
创建一个名为account-service的SpringBoot项目。
添加相关依赖
在项目pom.xml配置文件内添加相关依赖,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-logging</artifactId> </dependency> </dependencies>
|
配置上报的Logging Admin
在application.yml配置文件内添加请求日志上报的Logging Admin地址,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: application: name: account-service server: port: 9090
api: boot: logging: show-console-log: true format-console-log-json: true admin: server-address: 127.0.0.1:8081
|
注意:server-address配置参数不需要添加http://前缀
启用Logging Client
添加完成依赖后我们通过@EnableLoggingClient注解来启用ApiBoot Logging,在AccountServiceApplication类上添加如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@SpringBootApplication @EnableLoggingClient public class AccountServiceApplication {
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的控制器来提供查询账户的余额信息,代码实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
@RestController @RequestMapping(value = "/account") public class AccountController {
static final HashMap<Integer, Double> ACCOUNTS = new HashMap() {{ put(1, 1233.22); put(2, 69269.22); }};
@GetMapping(value = "/{accountId}") public Double getBalance(@PathVariable("accountId") Integer accountId) { return ACCOUNTS.get(accountId); } }
|
至此我们的账户服务已经编写完成,下面我们来编写用户服务。
创建用户服务
我们来创建一个名为user-service的SpringBoot项目。
添加相关依赖
在项目pom.xml配置文件内添加相关依赖,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-logging</artifactId> </dependency> </dependencies>
|
配置上报的Logging Admin
本章我们使用指定Logging Admin地址的方式配置,修改application.yml配置文件如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: application: name: user-service server: port: 9091
api: boot: logging: show-console-log: true format-console-log-json: true admin: server-address: 127.0.0.1:8081
|
启用Logging Client
添加完依赖后我们需要在XxxApplication入口类上添加@EnableLoggingClient注解来启用ApiBoot Logging,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@SpringBootApplication @EnableLoggingClient public class UserServiceApplication {
static Logger logger = LoggerFactory.getLogger(UserServiceApplication.class);
public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); logger.info("{}服务启动成功.", "用户"); } }
|
实例化RestTemplate对象
在user-service需要访问账户服务获取当前用户的余额,所以我们需要在user-service内实例化RestTemplate,这样我们才可以通过RestTemplate访问获取用户账户余额信息,我们直接在UserServiceApplication类内添加实例,如下所示:
1 2 3 4 5 6 7 8 9 10
|
@Bean @ConditionalOnMissingBean public RestTemplate restTemplate() { return new RestTemplate(); }
|
注解解释:
@ConditionalOnMissingBean:这是SpringBoot条件注入其中的一个注解,表示当IOC容器内不存在RestTemplate类型的实例时才会去执行restTemplate()方法创建对象。
查询用户信息代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
@RestController @RequestMapping(value = "/user") public class UserController {
static final HashMap<Integer, User> USERS = new HashMap() {{ put(1, new User(1, "恒宇少年")); put(2, new User(2, "于起宇")); }};
@Autowired private RestTemplate restTemplate;
@GetMapping(value = "/{userId}") public User getUserInfo(@PathVariable("userId") Integer userId) { ResponseEntity<Double> 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,如下所示:
1 2
| ➜ ~ curl http://localhost:9091/user/1 {"id":1,"name":"恒宇少年","balance":1233.22}
|
下面我看来看下logging-admin控制台接收到的请求日志。
接收user-service请求日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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请求日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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进行绑定的。
代码示例
如果您喜欢本篇文章请为源码仓库点个Star,谢谢!!!
本篇文章示例源码可以通过以下途径获取,目录为apiboot-logging-using-resttemplate-transparent-traceid: