在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Spring Boot如何實現日志鏈路追蹤

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-05-16 11:33 ? 次閱讀

前言

正文

前言

從文章標題就知道,這篇文章是介紹些什么。

這是我一位朋友的問題反饋:

aa554736-f395-11ed-90ce-dac502259ad0.png

好像是的,確實這種現象是普遍存在的。

有時候一個業務調用鏈場景,很長,調了各種各樣的方法,看日志的時候,各個接口的日志穿插,確實讓人頭大。

模糊匹配搜索日志能解決嗎? 能解決一點點。 但是不能完全呈現出整個鏈路相關的日志。

那要做到方便,很顯然,我們需要的是把同一次的業務調用鏈上的日志串起來。

什么效果? 先看一個實現后的效果圖:

aa5ba7a2-f395-11ed-90ce-dac502259ad0.png

這樣下來,我們再配合模糊匹配查找日志,效果不就剛剛的了。

cat-ninfo.log|grep"a415ad50dbf84e99b1b56a31aacd209c"

或者

grep-10'a415ad50dbf84e99b1b56a31aacd209c'info.log(10是指上下10行)

不多說,開整。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

項目地址:https://github.com/YunaiV/ruoyi-vue-pro

視頻教程:https://doc.iocoder.cn/video/

正文

慣例,先看一眼這次實戰最終工程的結構:

aa615652-f395-11ed-90ce-dac502259ad0.png

①pom.xml 依賴



org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-test
test


org.springframework.boot
spring-boot-starter-logging

 

org.projectlombok
lombok
1.16.10


②整合logback,打印日志,logback-spring.xml (簡單配置下)



 

 


 
[%X{TRACE_ID}]%d{yyyy-MM-ddHHss.SSS}[%thread]%-5level%logger{50}-%msg%n


 


 
${log}/%d{yyyy-MM-dd}.log
 
30


[%X{TRACE_ID}]%d{yyyy-MM-ddHHss.SSS}[%thread]%-5level%logger{50}-%msg%n

 

10MB



 





application.yml

server:
port:8826
logging:
config:classpath:logback-spring.xml

③自定義日志攔截器 LogInterceptor.java

用途:每一次鏈路,線程維度,添加最終的鏈路ID TRACE_ID。

importorg.slf4j.MDC;
importorg.springframework.lang.Nullable;
importorg.springframework.util.StringUtils;
importorg.springframework.web.servlet.HandlerInterceptor;

importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.util.UUID;

/**
*@Author:JCccc
*@Date:2022-5-3010:45
*@Description:
*/
publicclassLogInterceptorimplementsHandlerInterceptor{

privatestaticfinalStringTRACE_ID="TRACE_ID";

@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){
Stringtid=UUID.randomUUID().toString().replace("-","");
//可以考慮讓客戶端傳入鏈路ID,但需保證一定的復雜度唯一性;如果沒使用默認UUID自動生成
if(!StringUtils.isEmpty(request.getHeader("TRACE_ID"))){
tid=request.getHeader("TRACE_ID");
}
MDC.put(TRACE_ID,tid);
returntrue;
}

@Override
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,
@NullableExceptionex){
MDC.remove(TRACE_ID);
}

}

MDC(Mapped Diagnostic Context)診斷上下文映射,是@Slf4j提供的一個支持動態打印日志信息的工具。

WebConfigurerAdapter.java 添加攔截器

importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;
importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
*@Author:JCccc
*@Date:2022-5-3010:47
*@Description:
*/
@Configuration
publicclassWebConfigurerAdapterimplementsWebMvcConfigurer{
@Bean
publicLogInterceptorlogInterceptor(){
returnnewLogInterceptor();
}

@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(logInterceptor());
//可以具體制定哪些需要攔截,哪些不攔截,其實也可以使用自定義注解更靈活完成
//.addPathPatterns("/**")
//.excludePathPatterns("/testxx.html");
}
}

ps: 其實這個攔截的部分改為使用自定義注解+aop也是很靈活的。

到這時候,其實已經完成,就是這么簡單。

我們寫個測試接口,看下效果:

@PostMapping("doTest")
publicStringdoTest(@RequestParam("name")Stringname)throwsInterruptedException{
log.info("入參name={}",name);
testTrace();
log.info("調用結束name={}",name);
return"Hello,"+name;
}
privatevoidtestTrace(){
log.info("這是一行info日志");
log.error("這是一行error日志");
testTrace2();
}
privatevoidtestTrace2(){
log.info("這也是一行info日志");

}

效果(OK的):

aa6b1296-f395-11ed-90ce-dac502259ad0.png

還沒完。

接下來看一個場景, 使用子線程的場景:

故意寫一個異步線程,加入這個調用里面:

aa70c1fa-f395-11ed-90ce-dac502259ad0.png

再次執行看開效果,顯然子線程丟失了trackId:

aa7805aa-f395-11ed-90ce-dac502259ad0.png

所以我們需要針對子線程使用情形,做調整,思路: 將父線程的trackId傳遞下去給子線程即可。

①ThreadPoolConfig.java 定義線程池,交給spring管理

importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.scheduling.annotation.EnableAsync;
importjava.util.concurrent.Executor;

/**
*@Author:JCccc
*@Date:2022-5-3011:07
*@Description:
*/
@Configuration
@EnableAsync
publicclassThreadPoolConfig{
/**
*聲明一個線程池
*
*@return執行器
*/
@Bean("MyExecutor")
publicExecutorasyncExecutor(){
MyThreadPoolTaskExecutorexecutor=newMyThreadPoolTaskExecutor();
//核心線程數5:線程池創建時候初始化的線程數
executor.setCorePoolSize(5);
//最大線程數5:線程池最大的線程數,只有在緩沖隊列滿了之后才會申請超過核心線程數的線程
executor.setMaxPoolSize(5);
//緩沖隊列500:用來緩沖執行任務的隊列
executor.setQueueCapacity(500);
//允許線程的空閑時間60秒:當超過了核心線程出之外的線程在空閑時間到達之后會被銷毀
executor.setKeepAliveSeconds(60);
//線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池
executor.setThreadNamePrefix("asyncJCccc");
executor.initialize();
returnexecutor;
}
}

② MyThreadPoolTaskExecutor.java 是我們自己寫的,重寫了一些方法:

importorg.slf4j.MDC;
importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

importjava.util.concurrent.Callable;
importjava.util.concurrent.Future;

/**
*@Author:JCccc
*@Date:2022-5-3011:13
*@Description:
*/
publicfinalclassMyThreadPoolTaskExecutorextendsThreadPoolTaskExecutor{
publicMyThreadPoolTaskExecutor(){
super();
}

@Override
publicvoidexecute(Runnabletask){
super.execute(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));
}


@Override
publicFuturesubmit(Callabletask){
returnsuper.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));
}

@Override
publicFuturesubmit(Runnabletask){
returnsuper.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));
}
}

③ThreadMdcUtil.java

importorg.slf4j.MDC;

importjava.util.Map;
importjava.util.UUID;
importjava.util.concurrent.Callable;

/**
*@Author:JCccc
*@Date:2022-5-3011:14
*@Description:
*/
publicfinalclassThreadMdcUtil{
privatestaticfinalStringTRACE_ID="TRACE_ID";

//獲取唯一性標識
publicstaticStringgenerateTraceId(){
returnUUID.randomUUID().toString();
}

publicstaticvoidsetTraceIdIfAbsent(){
if(MDC.get(TRACE_ID)==null){
MDC.put(TRACE_ID,generateTraceId());
}
}

/**
*用于父線程向線程池中提交任務時,將自身MDC中的數據復制給子線程
*
*@paramcallable
*@paramcontext
*@param
*@return
*/
publicstaticCallablewrap(finalCallablecallable,finalMapcontext){
return()->{
if(context==null){
MDC.clear();
}else{
MDC.setContextMap(context);
}
setTraceIdIfAbsent();
try{
returncallable.call();
}finally{
MDC.clear();
}
};
}

/**
*用于父線程向線程池中提交任務時,將自身MDC中的數據復制給子線程
*
*@paramrunnable
*@paramcontext
*@return
*/
publicstaticRunnablewrap(finalRunnablerunnable,finalMapcontext){
return()->{
if(context==null){
MDC.clear();
}else{
MDC.setContextMap(context);
}
setTraceIdIfAbsent();
try{
runnable.run();
}finally{
MDC.clear();
}
};
}
}

OK,重啟服務,再看看效果:

aa7e694a-f395-11ed-90ce-dac502259ad0.png

可以看的,子線程的日志也被串起來了。

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8596

    瀏覽量

    151145
  • spring
    +關注

    關注

    0

    文章

    340

    瀏覽量

    14343

原文標題:Spring Boot 實現日志鏈路追蹤,無需引入組件,讓日志定位更方便!

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Spring Boot如何實現異步任務

    Spring Boot 提供了多種方式來實現異步任務,這里介紹三種主要實現方式。 1、基于注解 @Async @Async 注解是 Spring
    的頭像 發表于 09-30 10:32 ?1441次閱讀

    啟動Spring Boot項目應用的三種方法

    的讀取,開啟注解4)配置日志文件...配置完成之后部署tomcat 調試。但是如果使用spring boot呢?很簡單,我僅僅只需要非常少的幾個配置就可以迅速方便的搭建起來一套web項目或者是構建一個
    發表于 01-14 17:33

    java 日志框架Spring Boot分析

    引言:我們需要在已有的微服務代碼中添加日志功能,用于輸出需要關注的內容,這是最平常的技術需求了。由于我們的微服務代碼是基于SpringBoot開發的,那么問題就轉換為如何在Spring Boot
    發表于 09-28 14:58 ?0次下載

    Spring Boot從零入門1 詳述

    在開始學習Spring Boot之前,我之前從未接觸過Spring相關的項目,Java基礎還是幾年前自學的,現在估計也忘得差不多了吧,寫Spring
    的頭像 發表于 12-10 22:18 ?639次閱讀

    Spring Boot特有的實踐

    Spring Boot是最流行的用于開發微服務的Java框架。在本文中,我將與你分享自2016年以來我在專業開發中使用Spring Boot所采用的最佳實踐。這些內容是基于我的個人經驗
    的頭像 發表于 09-29 10:24 ?912次閱讀

    強大的Spring Boot 3.0要來了

    來源:OSC開源社區(ID:oschina2013) Spring Boot 3.0 首個 RC 已發布,此外還為兩個分支發布了更新:2.7.5 2.6.13。 3.0.0-RC1: https
    的頭像 發表于 10-31 11:17 ?1874次閱讀

    手動實現SpringBoot日志追蹤

    基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
    的頭像 發表于 12-15 15:04 ?1138次閱讀

    用這4招 優雅的實現Spring Boot異步線程間數據傳遞

    Spring Boot 自定義線程池實現異步開發相信看過陳某的文章都了解,但是在實際開發中需要在父子線程之間傳遞一些數據,比如用戶信息,
    的頭像 發表于 01-30 10:40 ?1136次閱讀

    Spring Boot Web相關的基礎知識

    Boot的第一個接口。接下來將會將會介紹使用Spring Boot開發Web應用的相關內容,其主要包括使用spring-boot-starter-web組件來
    的頭像 發表于 03-17 15:03 ?658次閱讀

    Spring Boot日志框架使用

    目前市面上常見的日志框架有:slf4j(Simple Logging Facade for Java)、logback、log4j、log4j2、commons-logging(Spring默認日志框架)、JUL(java.ut
    的頭像 發表于 06-02 10:59 ?949次閱讀
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>的<b class='flag-5'>日志</b>框架使用

    Spring Boot如何優雅實現數據加密存儲、模糊匹配和脫敏

    近來我們都在圍繞著使用Spring Boot開發業務系統時如何保證數據安全性這個主題展開總結,當下大部分的B/S架構的系統也都是基于Spring Boot + SpringMVC三層架
    的頭像 發表于 06-19 14:42 ?1960次閱讀
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>如何優雅<b class='flag-5'>實現</b>數據加密存儲、模糊匹配和脫敏

    Spring Boot Actuator快速入門

    不知道大家在寫 Spring Boot 項目的過程中,使用過 Spring Boot Actuator 嗎?知道 Spring
    的頭像 發表于 10-09 17:11 ?638次閱讀

    Spring Boot啟動 Eureka流程

    在上篇中已經說過了 Eureka-Server 本質上是一個 web 應用的項目,今天就來看看 Spring Boot 是怎么啟動 Eureka 的。 Spring Boot 啟動 E
    的頭像 發表于 10-10 11:40 ?894次閱讀
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>啟動 Eureka流程

    Spring Boot的啟動原理

    可能很多初學者會比較困惑,Spring Boot 是如何做到將應用代碼和所有的依賴打包成一個獨立的 Jar 包,因為傳統的 Java 項目打包成 Jar 包之后,需要通過 -classpath 屬性
    的頭像 發表于 10-13 11:44 ?650次閱讀
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>的啟動原理

    Spring Boot 的設計目標

    什么是Spring Boot Spring BootSpring 開源組織下的一個子項目,也是 S
    的頭像 發表于 10-13 14:56 ?587次閱讀
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b> 的設計目標
    主站蜘蛛池模板: 韩国理论片在线看2828dy| 午夜男人视频| 99精品热视频| 一区二区三区中文国产亚洲| 亚洲成人激情片| 日韩高清一级| 在线播放免费| 国产在线观看午夜不卡| susu成人影院| 色丁香六月| 久久精品国产四虎| 理论片毛片| 伊人色婷婷综在合线亚洲| 日本三级全黄| 国产高清免费| 午夜dy888理论三级| 天堂网. www在线资源| 黄色激情小说视频| 国产精品偷伦费观看| 日本不卡免费高清视频| 五月婷婷色| 一级特黄a视频| 亚洲高清网站| 久碰香蕉精品视频在线观看| 夜夜操狠狠干| 欧美性色xo影院69| 精品国产三级a∨在线| 97精品伊人久久久大香线焦| 国产亚洲自在精品久久| 精品国产三级a∨在线| 在线观看亚洲专3333| 色婷婷色综合缴情在线| 俺去啦最新官网| 182tv免费视视频线路一二三| 五月亭亭免费高清在线| 午夜视频免费看| 美女扒开尿口给男人桶| 你懂的网址在线| 深夜久久| 午夜伦理片在线观看| 羞羞影院男女午夜爽爽影视|