1. 程式人生 > 程式設計 >ApiBoot Logging使用RestTemplate透傳鏈路資訊

ApiBoot Logging使用RestTemplate透傳鏈路資訊

在上一篇文章【ApiBoot Logging使用SpringCloud Openfeign透傳鏈路資訊】中我們詳細的講解了ApiBoot Logging整合SpringCloud通過Openfeign進行透傳鏈路資訊,包括traceId(鏈路編號)、parentSpanId(上級單元編號)等資訊。 ApiBoot Logging不僅僅可以使用Openfeign傳遞鏈路資訊,還支援RestTemplate方式,本篇文章來詳細的講解下具體的使用方式。

部落格原文地址:blog.yuqiyu.com/apiboot-log…

搭建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-serviceSpringBoot專案。

新增相關依賴

在專案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-serviceSpringBoot專案。

新增相關依賴

在專案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,"使用者");
    }
}
複製程式碼

例項化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,"parentSpanId":"f8cff018-42d5-481f-98df-c19b7196b3c3","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","requestUri":"/account/1","responseBody":"1233.22","serviceId":"account-service","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(單元編號),因為沒有上級單元所以parentSpanIdnull.
  • 而通過檢視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檢視。

不管你一次請求跨度幾個服務,都可以將請求入口生成的鏈路資訊進行依次傳遞,而上下級關係則是根據parentSpanIdspanId進行繫結的。

程式碼示例

如果您喜歡本篇文章請為原始碼倉庫點個Star,謝謝!!! 本篇文章示例原始碼可以通過以下途徑獲取,目錄為SpringBoot2.x/apiboot-logging-using-resttemplate-transparent-traceid

作者個人 部落格 使用開源框架 ApiBoot 助你成為Api介面服務架構師