ApiBoot Logging使用RestTemplate透傳鏈路資訊
- 2019 年 11 月 11 日
- 筆記
在上一篇文章【ApiBoot Logging使用SpringCloud Openfeign透傳鏈路資訊】中我們詳細的講解了ApiBoot Logging整合SpringCloud通過Openfeign進行透傳鏈路資訊,包括traceId(鏈路編號)、parentSpanId(上級單元編號)等資訊。 ApiBoot Logging不僅僅可以使用Openfeign傳遞鏈路資訊,還支援RestTemplate方式,本篇文章來詳細的講解下具體的使用方式。
部落格原文地址:http://blog.yuqiyu.com/apiboot-logging-using-resttemplate-transparent-traceid.html
搭建Logging Admin
我們需要搭建Logging Admin服務,用於接收業務服務上報的請求日誌資訊,請參考【將ApiBoot Logging採集的日誌上報到Admin】文章內容.
添加ApiBoot統一版本
由於本章採用是Maven 多模組的方式構建源碼,所以我們只需要將ApiBoot統一版本的依賴配置在root項目的pom.xml內,如下所示:
<properties> <java.version>1.8</java.version> <!--ApiBoot版本號--> <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配置文件內添加相關依賴,如下所示:
<dependencies> <!--SpringBoot Web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--ApiBoot Logging--> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-logging</artifactId> </dependency> </dependencies>
配置上報的Logging Admin
在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://前綴
啟用Logging Client
添加完成依賴後我們通過@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<Integer, Double> 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配置文件內添加相關依賴,如下所示:
<dependencies> <!--SpringBoot Web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--ApiBoot Logging--> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-logging</artifactId> </dependency> </dependencies>
配置上報的Logging Admin
本章我們使用指定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
啟用Logging Client
添加完依賴後我們需要在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("{}服務啟動成功.", "用戶"); } }實例化RestTemplate對象
在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<Integer, User> 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<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,如下所示:
➜ ~ 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進行綁定的。
程式碼示例 本篇文章示例源碼可以通過以下途徑獲取,目錄為SpringBoot2.x/apiboot-logging-using-resttemplate-transparent-traceid: