smartadmin mysql_ApiBoot Logging 和Logging Admin使用总结
1. 說明
ApiBoot Logging是ApiBoot提供單應用、微服務應用下的請求日志分析框架。在微服務的鏈路調用過程中,可以記錄下每次調用的鏈路信息。信息可以以日志的形式保存在數據庫中,或者也可以自己通過代碼將日志保存在其他地方,比如kafka中。
日志的格式大致如下:
[
{
"endTime":1564368219907,
"httpStatus":200,
"parentSpanId":"d9ed5130-b72c-4282-8d18-4a6f7a08275a",
"requestBody":"",
"requestHeaders":{
"api-boot-x-trace-id":"855b0f4d-7667-4e14-ac8d-6b63fb4ef64e",
"host":"localhost:9099",
"connection":"keep-alive",
"api-boot-x-parent-span-id":"d9ed5130-b72c-4282-8d18-4a6f7a08275a",
"accept":"*/*",
"user-agent":"Java/1.8.0_201"
},
"requestIp":"127.0.0.1",
"requestMethod":"GET",
"requestUri":"/levelone",
"responseBody":"levelone",
"responseHeaders":{},
"serviceId":"ahhx_jcpt",
"serviceIp":"192.168.21.101",
"servicePort":"9099",
"spanId":"d1597b46-ec21-4a37-8f40-d39d95d533a8",
"startTime":1564368219904,
"timeConsuming":3,
"traceId":"855b0f4d-7667-4e14-ac8d-6b63fb4ef64e"
}
]
1.1 traceId(鏈路ID)和spanId(跨度ID)
如果一個請求的header信息內包含traceId(鏈路ID)則加入該鏈路,如果不存在則生成新的鏈路信息
如果一個請求的header信息內包含spanId(跨度ID),則使用該spanId作為parent spanId,對兩個請求進行上下級關聯。
簡單的理解,通過traceId,可以分析出來,如果幾個日志的traceId是一樣的,那么這幾個調用是屬于一條鏈路的。然后再通過spanId和parentSpanId就可以分析出來這個幾個請求的上下級關系,是哪個調用的哪個。
1.2 體系
項目結構主要分為兩個部分,一個是ApiBoot Logging,另一個是ApiBoot Logging Admin。
ApiBoot Logging是日志采集端,就是集成了ApiBoot Logging的項目,這個項目中的接口被請求時,就會采集到日志。
ApiBoot Logging Admin是日志收集端,所有ApiBoot Logging的項目采集到的日志都會上報到ApiBoot Logging Admin。
2. 項目中導入ApiBoot Logging
2.1 引入依賴
org.minbox.framework
api-boot-starter-logging
2.1.2.RELEASE
2.2 修改配置文件
logging:
level:
org.minbox.framework.api.boot.plugin.logging: debug
root: info
com.base.web: info
api:
boot:
logging:
admin:
server-address: 127.0.0.1:20004
# 格式化上報日志
format-console-log-json: true
number-of-request-log: 2
# 顯示上報日志
show-console-report-log: true
server-address是Logging Admin的地址,Logging Admin是獨立的項目,是Logging項目的日志上報地址。這里可以先不管,等到Logging Admin創建完畢,在修改為對于的ip和port
2.3 測試接口
@Controller
public class ApiBootContorller {
@ResponseBody
@GetMapping("/levelone")
public String levelone(){
return "levelone";
}
}
通過postman調用這個接口,就可以在控制臺中看到打印的日志。
集成ApiBoot Logging 的步驟只有這些,但是可能會遇到一些問題
spring boot版本問題:
我的項目使用的是spring boot 2.0.1 但是ApiBoot 需要2.1.6,直接引入,啟動就會報錯。
10:16:58 [localhost-startStop-1] ERROR o.a.c.c.C.[Tomcat].[localhost].[/] - Exception starting filter [apiBootLoggingFilter]
java.lang.AbstractMethodError: null
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:285)
at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:112)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4598)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5241)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
于是我將項目升級到2.1.6版本,之后還是無法啟動,因為項目原先依賴的kafka無法啟動,之后又去升級kafka依賴,以及修改kafka接收數據的代碼。
總之,如果一個項目比較復雜,升級spring boot版本還是比較容易碰到坑的。
3. 創建Logging Admin 項目
Logging Admin 項目用來接口日志采集端發送過來的數據,而且一個Logging Admin可以接受多個數據采集端,可以理解為一對多的關系。
3.1 導入依賴
org.minbox.framework
api-boot-starter-logging-admin
ApiBoot Mybatis Enhance
org.minbox.framework
api-boot-starter-mybatis-enhance
MySQL驅動
mysql
mysql-connector-java
Hikari數據源
com.zaxxer
HikariCP
如果不指定依賴的version的話,需要添加依賴管理,如果指定了依賴的具體版本,就不需要添加依賴管理了,上面的ApiBoot Logging引入時也是一樣。
依賴管理:
org.minbox.framework
api-boot-dependencies
2.1.2.RELEASE
import
pom
3.2 配置文件
server.port=20004
logging.level.org.minbox.framework.api.boot.plugin.logging=debug
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.username=root
spring.datasource.password=ahhx@123
spring.datasource.url=jdbc:mysql://192.168.220.46:3306/apiboot
# 格式化上報日志
api.boot.logging.admin.format-console-log-json=true
# 顯示上報日志
api.boot.logging.admin.show-console-report-log=true
3.3 在數據庫中運行sql文件
上面的配置文件中用到了數據庫,需要初始化數據庫,創建一些表。
表結構如下,將如下語句在對應的數據庫中跑一次,即可。
SET NAMES utf8mb4 ;
--
-- Table structure for table `logging_request_logs`
--
DROP TABLE IF EXISTS `logging_request_logs`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `logging_request_logs` (
`lrl_id` varchar(36) NOT NULL COMMENT '主鍵,UUID',
`lrl_service_detail_id` varchar(36) DEFAULT NULL COMMENT '服務詳情編號,關聯logging_service_details主鍵',
`lrl_trace_id` varchar(36) DEFAULT NULL COMMENT '鏈路ID',
`lrl_parent_span_id` varchar(36) DEFAULT NULL COMMENT '上級跨度ID',
`lrl_span_id` varchar(36) DEFAULT NULL COMMENT '跨度ID',
`lrl_start_time` mediumtext COMMENT '請求開始時間',
`lrl_end_time` mediumtext COMMENT '請求結束時間',
`lrl_http_status` int(11) DEFAULT NULL COMMENT '請求響應狀態碼',
`lrl_request_body` longtext COMMENT '請求主體內容',
`lrl_request_headers` text COMMENT '請求頭信息',
`lrl_request_ip` varchar(30) DEFAULT NULL COMMENT '發起請求客戶端的IP地址',
`lrl_request_method` varchar(10) DEFAULT NULL COMMENT '請求方式',
`lrl_request_uri` varchar(200) DEFAULT NULL COMMENT '請求路徑',
`lrl_response_body` longtext COMMENT '響應內容',
`lrl_response_headers` text COMMENT '響應頭信息',
`lrl_time_consuming` int(11) DEFAULT NULL COMMENT '請求耗時',
`lrl_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '日志保存時間',
PRIMARY KEY (`lrl_id`),
KEY `logging_request_logs_LRL_SERVICE_DETAIL_ID_index` (`lrl_service_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='請求日志信息表';
--
-- Table structure for table `logging_service_details`
--
DROP TABLE IF EXISTS `logging_service_details`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `logging_service_details` (
`lsd_id` varchar(36) NOT NULL,
`lsd_service_id` varchar(200) DEFAULT NULL COMMENT '上報服務的ID,對應spring.application.name配置值',
`lsd_service_ip` varchar(50) DEFAULT NULL COMMENT '上報服務的IP地址',
`lsd_service_port` int(11) DEFAULT NULL COMMENT '上報服務的端口號',
`lsd_last_report_time` timestamp NULL DEFAULT NULL COMMENT '最后一次上報時間,每次上報更新',
`lsd_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '首次上報時創建時間',
PRIMARY KEY (`lsd_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='上報日志的客戶端服務詳情';
3.4 測試
將ApiBoot Logging配置文件中的對應的server-address: 127.0.0.1:20004指定為Logging Admin的ip和port。
使用postman調用ApiBoot Logging中的接口,可以看到的結果是ApiBoot Logging本地的控制臺打印出來了日志,同時Logging Admin也收到了日志打印在控制臺上并且存儲在了數據庫中。
4. 鏈式調用
之前引入ApiBoot Logging 的項目叫做ahhx-jcpt
spring:
application:
name: ahhx-jcpt
再創建一個ApiBoot Logging項目叫做apiboot,項目中提供一個接口
@ResponseBody
@GetMapping(value = "/index")
public String hello(){
return getStringApi.getString();
}
在apiboot中的接口中調用ahhx-jcpt,就達成了鏈式調用。
需要注意的問題是,目前最新版2.1.2,只支持spring cloud openfeign調用,對于RestTemplate等方式調用,雖然也可以采集到日志,但是并不能正確得到traceId、spanId和parentSpanId。那么就無法分析出鏈路的調用關系。
關于spring cloud openfeign的簡單使用將在后文描述。
使用postman調用apiboot的\index接口,查看ahhx-jcpt和apiboot的控制臺,可以看到他們的traceId是一樣的,并且ahhx-jcpt的parentSpanId就是apiboot的spanId。
5. spring cloud openfeign最簡單使用
5.1 引入依賴
org.springframework.cloud
spring-cloud-starter-openfeign
2.1.0.RELEASE
5.2 代碼
5.2.1 創建一個接口
@FeignClient(name = "ahhx-jcpt", url = "http://localhost:9099")
public interface GetStringApi {
@RequestMapping(value = "/levelone", method = RequestMethod.GET)
String getString();
}
5.2.2 調用
@Controller
public class IndexController {
@Autowired
private GetStringApi getStringApi;
@ResponseBody
@GetMapping(value = "/index")
public String hello(){
return getStringApi.getString();
}
}
當/index被調用,就會調用GetStringApi 的getString,而getString就會去調用http://localhost:9099/levelone接口
6. 在Logging Admin端用kafka存儲日志,并關閉自帶的存儲數據庫操作
6.1 關閉存儲數據庫操作
刪除依賴
刪除配置
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#spring.datasource.username=root
#spring.datasource.password=ahhx@123
#spring.datasource.url=jdbc:mysql://192.168.220.46:3306/apiboot
這樣admin端,在收到數據以后就只會在控制臺打印,不會存數據庫
6.2 存儲kafka
繼承SmartApplicationListener
@Component
public class LocalNoticeSample implements SmartApplicationListener {
@Autowired
private KafkaSender kafkaSender;
@Override
public boolean supportsEventType(Class extends ApplicationEvent> eventType) {
return eventType == ReportLogEvent.class;
}
@Override
public boolean supportsSourceType(Class> sourceType) {
return sourceType == LoggingEndpoint.class;
}
/**
* order 值越小執行越靠前
*
* @return
*/
@Override
public int getOrder() {
return 2;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("onApplicationEvent");
ReportLogEvent reportLogEvent = (ReportLogEvent) applicationEvent;
ApiBootLogClientNotice notice = reportLogEvent.getLogClientNotice();
kafkaSender.sendMessage(notice.getLoggers().toString());
}
}
kafka發送代碼:
@EnableBinding(Source.class)
@Component
public class KafkaSender {
private final Logger logger = LoggerFactory.getLogger(KafkaSender.class);
@Autowired
private Source source;
public void sendMessage(String msg){
try {
logger.info("準備發送數據到kafka->數據:【message:"+msg+"】");
source.output().send(MessageBuilder.withPayload(msg).build());
}catch (Exception e){
logger.info("準備發送數據到kafka->出錯");
e.printStackTrace();
}
}
}
kafka接收代碼
@Component
@EnableBinding(Sink.class)
public class KafkaReceive {
private final Logger logger = LoggerFactory.getLogger(KafkaReceive.class);
@StreamListener(Sink.INPUT)
public void process(Message message) throws Exception {
logger.info("監聽到kafka數據->輸入參數【message:"+message+"】");
String receivedString = message.getPayload();
logger.info("received kafka message : value:"+receivedString);
}
}
7. 追訴
7.1 提取日志
在admin端想要提取日志,需要寫一個類集成SmartApplicationListener 即可。
在Logging端目前無法直接提取日志(2.1.2版本),根據作者說明,在下一版本將可以直接提取日志。
并且據說下一個版本admin端將提供可視界面,以及日志上報到admin可以關閉,讓日志不上報。
8. 相關鏈接
總結
以上是生活随笔為你收集整理的smartadmin mysql_ApiBoot Logging 和Logging Admin使用总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 教你设置eclipse自动生成的auth
- 下一篇: Python 抓取数据存储到Mysql中