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文章
2985瀏覽量
106958 -
spring
+關注
關注
0文章
340瀏覽量
14892 -
MySQL
+關注
關注
1文章
849瀏覽量
27570 -
人臉識別
+關注
關注
76文章
4070瀏覽量
83724
發布評論請先 登錄
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調用

評論