ApiBoot Logging可以無縫整合SpringCloud來采集請求日志,目前支持RestTemplate、Openfeign兩種方式,我們本章來講解下在使用Openfeign完成服務之間請求相互調用的一條鏈路請求日志是否可以都采集到。
搭建Eureka Server
我們先來搭建一個Eureka Server,請訪問【搭建服務注冊中心Eureka Server】文章內容查看具體搭建流程。
搭建Logging Admin
我們需要搭建一個Logging Admin用于接收Logging Client上報的請求日志,請訪問【ApiBoot Logging整合SpringCloud Eureka負載均衡上報日志】查看具體的搭建流程。
我們本章來模擬提交訂單的業務邏輯,涉及到兩個服務,分別是:商品服務、訂單服務,接下來我們需要來創建這兩個服務。
添加ApiBoot & SpringCloud統一版本
由于是采用Maven 多模塊項目,存在繼承關系,我們只需要在root模塊添加版本依賴即可,其他子模塊就可以直接使用,如下所示:
1.82.1.5.RELEASEGreenwich.SR3org.minbox.frameworkapi-boot-dependencies${api.boot.version}pomimportorg.springframework.cloudspring-cloud-dependencies${spring.cloud.version}pomimport
創建公共Openfeign接口定義
學習過Openfeign的同學應該都知道,Openfeign可以繼承實現,我們只需要創建一個公共的服務接口定義,在實現該接口的服務進行業務實現,在調用該接口的地方直接注入即可。
下面我們創建一個名為common-openfeign的公共依賴項目,pom.xml添加依賴如下所示:
org.springframework.bootspring-boot-starter-webtrueorg.springframework.cloudspring-cloud-starter-openfeigntrue
在提交訂單時我們簡單模擬需要獲取商品的單價,所以在common-openfeign項目內我們要提供一個查詢商品單價的服務接口,創建一個名為GoodClient的接口如下所示:
package org.minbox.chapter.common.openfeign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 商品服務接口定義
*
* @author 恒宇少年
*/
@FeignClient(name = "good-service")
@RequestMapping(value = "/good")
public interface GoodClient {
/**
* 獲取商品價格
*
* @param goodId 商品編號
* @return
*/
@GetMapping(value = "/{goodId}")
Double getGoodPrice(@PathVariable("goodId") Integer goodId);
}
注解解釋:
-
@FeignClient:SpringCloud Openfeign提供的接口客戶端定義注解,通過value或者name來指定GoodClient訪問的具體ServiceID,這里我們配置的value值為good-service項目spring.application.name配置參數(ServiceID=spring.application.name)。
這樣當我們通過注入GoodClient接口調用getGoodPrice方法時,底層通過Openfeign的Http代理訪問good-service的對應接口。
創建商品服務
下面我們再來創建一個名為good-service的SpringBoot項目。
添加相關依賴
在pom.xml項目配置文件內添加如下依賴:
org.minbox.frameworkapi-boot-starter-loggingorg.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-starter-netflix-eureka-clientorg.minbox.chaptercommon-openfeign0.0.1-SNAPSHOT
可以看到我們在good-service項目依賴內添加了我們在上面創建的common-openfeign依賴模塊,因為GoodClient服務接口的實現是在good-service項目內,我們需要添加common-openfeign依賴后創建對應的XxxController并實現GoodClient接口完成對應的業務邏輯實現。
商品業務實現
這里我們簡單做個示例,將價格固定返回,實現GoodClient的控制器如下所示:
package org.minbox.chapter.good.service;
import org.minbox.chapter.common.openfeign.GoodClient;
import org.springframework.web.bind.annotation.RestController;
/**
* 商品服務接口實現
*
* @author 恒宇少年
* @see GoodClient
*/
@RestController
public class GoodController implements GoodClient {
@Override
public Double getGoodPrice(Integer goodId) {
if (goodId == 1) {
return 15.6;
}
return 0D;
}
}
注冊到Eureka Server
我們需要將good-service注冊到Eureka Server,修改application.yml配置文件如下所示:
# ServiceID
spring:
application:
name: good-service
# 端口號
server:
port: 8082
# Eureka Config
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10000/eureka/
instance:
prefer-ip-address: true
配置上報的Logging Admin
我們需要將good-service的請求日志上報到Logging Admin,采用SpringCloud ServiceID的方式配置,修改application.yml配置文件如下所示:
api:
boot:
logging:
# 控制臺打印日志
show-console-log: true
# 美化打印日志
format-console-log-json: true
# 配置Logging Admin 服務編號
discovery:
service-id: logging-admin
啟用Eureka Client & Logging
最后我們在XxxApplication入口類添加注解來啟用Eureka Client以及Logging Client,如下所示:
/**
* 商品服務
*
* @author 恒宇少年
*/
@SpringBootApplication
@EnableLoggingClient
@EnableDiscoveryClient
public class GoodServiceApplication {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(GoodServiceApplication.class);
public static void main(String[] args) {
SpringApplication.run(GoodServiceApplication.class, args);
logger.info("{}服務啟動成功.", "商品");
}
}
至此我們的商品服務已經準備完成.
創建訂單服務
創建一個名為order-service的SpringBoot項目(建議參考源碼,本章采用Maven多模塊創建)。
添加相關依賴
修改pom.xml添加相關依賴如下所示:
org.minbox.frameworkapi-boot-starter-loggingorg.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-starter-netflix-eureka-clientorg.springframework.cloudspring-cloud-starter-openfeignorg.minbox.chaptercommon-openfeign0.0.1-SNAPSHOT
訂單業務實現
我們來模擬一個提交訂單的場景,創建一個名為OrderController的控制器,如下所示:
/**
* 訂單控制器
*
* @author 恒宇少年
*/
@RestController
@RequestMapping(value = "/order")
public class OrderController {
/**
* 商品接口定義注入
* {@link GoodClient}
*/
@Autowired
private GoodClient goodClient;
@PostMapping
public String submit(Integer goodId, Integer buyCount) {
Double goodPrice = goodClient.getGoodPrice(goodId);
Double orderAmount = goodPrice * buyCount;
//...
return "訂單提交成功,訂單總金額:" + orderAmount;
}
}
注冊到Eureka Server
將我們創建的order-service注冊到Eureka Server,修改application.yml配置文件如下所示:
spring:
application:
name: order-service
server:
port: 8081
# Eureka Config
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10000/eureka/
instance:
prefer-ip-address: true
配置上報的Logging Admin
我們需要將order-service的請求日志上報到Logging Admin,采用SpringCloud ServiceID的方式配置,修改application.yml配置文件如下所示:
api:
boot:
logging:
# 控制臺打印日志
show-console-log: true
# 美化打印日志
format-console-log-json: true
# 配置Logging Admin 服務編號
discovery:
service-id: logging-admin
啟用Eureka Client & Logging
修改order-service入口類OrderServiceApplication,添加啟用Eureka Client、Logging Client的注解,如下所示:
/**
* 訂單服務
*
* @author 恒宇少年
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableLoggingClient
@EnableFeignClients(basePackages = "org.minbox.chapter.common.openfeign")
public class OrderServiceApplication {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(OrderServiceApplication.class);
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
logger.info("{}服務啟動成功.", "");
}
}
注解解釋:
-
@EnableFeignClients:該注解是Openfeign提供的啟用自動掃描Client的配置,我們通過basePackages(基礎包名)的方式進行配置掃描包下配置@FeignClient注解的接口,并為每個接口生成對應的代理實現并添加到Spring IOC容器。org.minbox.chapter.common.openfeign包名在common-openfeign項目內。
運行測試
依次啟動項目,eureka-server > logging-admin > good-service > order-service。
通過curl命令訪問order-service內的提交訂單地址:/order,如下所示:
? ~ curl -X POST http://localhost:8081/order/?goodId/=1/&buyCount/=3
訂單提交成功,訂單總金額:46.8
可以看到我們已經可以成功的獲取訂單的總金額,我們在/order請求方法內調用good-service獲取商品的單價后計算得到訂單總金額。
測試點:鏈路信息傳遞
我們通過控制臺輸出的日志信息來確認下鏈路信息(traceId、spanId)的透傳是否正確。
收到order-service上報的日志
Receiving Service: 【order-service -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1573009439840,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"host":"localhost:8081",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"POST",
"requestParam":"{/"buyCount/":/"3/",/"goodId/":/"1/"}",
"requestUri":"/order",
"responseBody":"訂單提交成功,訂單總金額:46.8",
"responseHeaders":{},
"serviceId":"order-service",
"serviceIp":"127.0.0.1",
"servicePort":"8081",
"spanId":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
"startTime":1573009439301,
"timeConsuming":539,
"traceId":"3e20cc72-c880-4575-90ed-d54a6b4fe555"
}
]
收到good-service上報的日志
Receiving Service: 【good-service -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1573009439810,
"httpStatus":200,
"parentSpanId":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
"requestBody":"",
"requestHeaders":{
"minbox-logging-x-parent-span-id":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
"minbox-logging-x-trace-id":"3e20cc72-c880-4575-90ed-d54a6b4fe555",
"host":"10.180.98.156:8082",
"connection":"keep-alive",
"accept":"*/*",
"user-agent":"Java/1.8.0_211"
},
"requestIp":"10.180.98.156",
"requestMethod":"GET",
"requestParam":"{}",
"requestUri":"/good/1",
"responseBody":"15.6",
"responseHeaders":{},
"serviceId":"good-service",
"serviceIp":"127.0.0.1",
"servicePort":"8082",
"spanId":"6339664e-097d-4a01-a734-935de52a7d44",
"startTime":1573009439787,
"timeConsuming":23,
"traceId":"3e20cc72-c880-4575-90ed-d54a6b4fe555"
}
]
結果分析:
-
請求日志的入口為
order-service所以并不存在parentSpanId(上級單元編號),而spanId(單元編號)、traceId(鏈路編號)也是新生成的。 -
本次請求會經過
good-service服務,因此parentSpanId則是order-service生成的spanId,traceId同樣也是order-service生成的,透傳HttpHeader方式進行傳遞,表示在同一條請求鏈路上。
敲黑板,劃重點
ApiBoot Logging支持使用Openfeign傳遞鏈路信息,內部通過Openfeign攔截器實現,源碼詳見:org.minbox.framework.logging.client.http.openfeign.LoggingOpenFeignInterceptor。
將traceId(鏈路編號)、parentSpanId(單元編號)通過HttpHeader的形式傳遞到目標訪問服務,服務通過請求日志攔截器進行提取并設置鏈路綁定關系。
-
traceId傳遞時HttpHeader名稱為:minbox-logging-x-trace-id. -
parentSpanId傳遞時HttpHeader名稱為:minbox-logging-x-parent-span-id
審核編輯 黃昊宇 -
JAVA
+關注
關注
20文章
3001瀏覽量
116422 -
spring
+關注
關注
0文章
341瀏覽量
15935 -
MySQL
+關注
關注
1文章
905瀏覽量
29518 -
人臉識別
+關注
關注
77文章
4127瀏覽量
88459
發布評論請先 登錄
EDAS再升級!全面支持Spring Cloud應用
Dubbo Cloud Native 之路的實踐與思考
ApiBoot Logging Admin可視化界面管理日志教程
ApiBoot Logging使用Rest Template透傳鏈路信息
ApiBoot Logging整合Spring Cloud Eureka負載均衡上報日志
ApiBoot Logging忽略路徑不進行采集日志的教程
修改ApiBoot Logging日志采集前綴的教程
Spring Cloud Function基于Spring Boot的函數計算框架
RabbitRpc基于spring cloud的微服務rpc調用
ApiBoot Logging使用Spring Cloud Openfeign透傳鏈路信息
評論