国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

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

3天內不再提示

手動實現SpringBoot日志鏈路追蹤

jf_ro2CN3Fa ? 來源:csdn ? 作者:CSDN ? 2022-12-15 15:04 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

  • 前言
  • 正文
3abca07e-7c3d-11ed-8abf-dac502259ad0.jpg

前言

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

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

3b060c64-7c3d-11ed-8abf-dac502259ad0.png

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

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

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

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

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

3b14d7d0-7c3d-11ed-8abf-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/

正文

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

3b58db1a-7c3d-11ed-8abf-dac502259ad0.png

①pom.xml 依賴

<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>

<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.10version>
dependency>
dependencies>

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


<configurationdebug="false">

<propertyname="log"value="D:/test/log"/>

<appendername="console"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

<pattern>[%X{TRACE_ID}]%d{yyyy-MM-ddHHss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>
encoder>
appender>

<appendername="file"class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<FileNamePattern>${log}/%d{yyyy-MM-dd}.logFileNamePattern>

<MaxHistory>30MaxHistory>
rollingPolicy>
<encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%X{TRACE_ID}]%d{yyyy-MM-ddHHss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>
encoder>

<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MBMaxFileSize>
triggeringPolicy>
appender>


<rootlevel="INFO">
<appender-refref="console"/>
<appender-refref="file"/>
root>
configuration>

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的):

3b7c2340-7c3d-11ed-8abf-dac502259ad0.png

還沒完。

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

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

3bb25adc-7c3d-11ed-8abf-dac502259ad0.png

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

3bc97a14-7c3d-11ed-8abf-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,重啟服務,再看看效果:

3be73004-7c3d-11ed-8abf-dac502259ad0.png

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



審核編輯 :李倩


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

    關注

    0

    文章

    341

    瀏覽量

    15936
  • 日志
    +關注

    關注

    0

    文章

    146

    瀏覽量

    11065
  • SpringBoot
    +關注

    關注

    0

    文章

    177

    瀏覽量

    688

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

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    SDV域控器日志追蹤與解析技術 – DLT

    從研發到測試SDV域控制器的調試日志在汽車軟件復雜度不斷攀升的今天,對不同核或分區上運行的復雜軟件進行調試或追蹤極具挑戰性,并且在POSIX系統或車輛上的復雜軟件進行分步調試往往更具挑戰。所以
    的頭像 發表于 01-21 10:04 ?1845次閱讀
    SDV域控器<b class='flag-5'>日志</b><b class='flag-5'>追蹤</b>與解析技術 – DLT

    模組日志功能技術概覽

    模組日志功能技術方案以低侵入、高可用為原則,提供統一的日志API、多級日志分類與條件輸出機制。通過集成該技術,開發者可在不干擾業務邏輯的前提下,全面掌握模組的執行狀態與異常行為。 一、本文討論的邊界
    的頭像 發表于 01-14 15:32 ?130次閱讀
    模組<b class='flag-5'>日志</b>功能技術概覽

    BLE SoC,如何助力管理者實現高效的資產追蹤

    基于BLE SoC的資產追蹤方案,具備低功耗、高集成和生態成熟,實現高效資產定位與管理。
    的頭像 發表于 12-22 14:16 ?286次閱讀
    BLE SoC,如何助力管理者<b class='flag-5'>實現</b>高效的資產<b class='flag-5'>追蹤</b>?

    RT-Thread ULOG: 創建多個文件后端并保存不同日志方法 | 技術集結

    目錄前言使用場景實現功能具體操作1前言在項目開發中需要使用到日志功能來調試和查看問題。有些問題并不會在我們實時查看的時候發生,而是在你上個廁所的功夫可能就發生了。如果上位機的緩沖區不夠大,可能錯誤
    的頭像 發表于 12-15 19:22 ?4924次閱讀
    RT-Thread ULOG: 創建多個文件后端并保存不同<b class='flag-5'>日志</b>方法 | 技術集結

    電能質量在線監測裝置數據日志能加密存儲嗎?

    加密的技術實現方式 1. 加密算法與分級策略 日志類型 推薦加密算法 密鑰管理方式 適用場景 敏感日志(事件記錄、故障數據、用戶信息) AES-256 (高級加密標準) 硬件安全模塊(HSM/TPM/SE)管理密鑰 電網關口、新
    的頭像 發表于 12-05 10:16 ?612次閱讀
    電能質量在線監測裝置數據<b class='flag-5'>日志</b>能加密存儲嗎?

    如何使用SpringBoot、Vue2.0、MySQL開發一套云診所系統?

    (RESTful)等。 對于云診所系統,SpringBoot可以用于實現患者管理、預約掛號、電子病歷、藥品管理、收費管理等核心功能。 前端:V
    的頭像 發表于 11-27 16:02 ?287次閱讀
    如何使用<b class='flag-5'>SpringBoot</b>、Vue2.0、MySQL開發一套云診所系統?

    電能質量在線監測裝置的備用切換機制是否支持遠程控制?

    現代電能質量在線監測裝置的備用切換機制 普遍支持遠程控制 ,主流廠商通過協議指令、軟件平臺和硬件冗余設計,實現了從狀態查詢、策略配置
    的頭像 發表于 11-06 16:48 ?1406次閱讀

    電能質量在線監測裝置的備用切換需要手動干預嗎?

    電能質量在線監測裝置的備用切換 通常無需手動干預 ,主流設備通過硬件冗余設計、協議層自動切換機制和智能算法實現全流程自動化。以下是關鍵實現
    的頭像 發表于 11-06 16:29 ?1336次閱讀

    資源狀態感知是如何實現對網絡狀態的實時感知的?

    資源狀態感知對網絡狀態的實時監測是通過硬件底層檢測、協議層交互、算法模型分析的多層協同實現的,具體技術路徑如下: 一、硬件層:物理信號的實時捕獲 PHY 芯片的直接感知以太網 PHY 芯片(如
    的頭像 發表于 11-06 14:49 ?674次閱讀

    目標追蹤的簡易實現:模板匹配

    一、目標追蹤和圖像識別 一般來說,提到機器視覺這個概念都會想到圖像識別,比如人臉識別、文本識別等等,目標追蹤這個概念在平時接觸的相對比較少。但實際上,目標追蹤可以理解為圖像識別的動態過程:圖像識別
    發表于 10-28 07:21

    拼多多商品推廣鏈接生成API:社交裂變的轉化追蹤利器

    ? 在社交電商時代,拼多多通過 商品推廣鏈接生成API 為商家提供了精準的流量轉化解決方案。該工具不僅簡化了社交裂變活動的落地,更實現了全轉化效果追蹤,成為提升營銷效率的核心引擎。
    的頭像 發表于 09-08 16:22 ?753次閱讀
    拼多多商品推廣鏈接生成API:社交裂變的轉化<b class='flag-5'>追蹤</b>利器

    如何使用樹莓派與OpenCV實現面部和運動追蹤的云臺系統?

    大家好,這是一個樹莓派和OpenCV的連載專題。使用樹莓派與OpenCV實現姿態估計和面部特征點追蹤使用樹莓派與OpenCV實現面部和運動追蹤的云臺系統使用樹莓派和OpenCV
    的頭像 發表于 08-14 17:45 ?1574次閱讀
    如何使用樹莓派與OpenCV<b class='flag-5'>實現</b>面部和運動<b class='flag-5'>追蹤</b>的云臺系統?

    手把手教你配置遠程errDump調試:日志追蹤不求人!

    如果您對遠程errDump調試功能感到陌生,本教程將通過一步步操作演示,教您如何配置遠程日志采集、解析errDump文件,以及定位關鍵錯誤信息,讓您輕松獨立完成調試任務。 下文特別分享errDump
    的頭像 發表于 06-05 18:32 ?1134次閱讀
    手把手教你配置遠程errDump調試:<b class='flag-5'>日志</b><b class='flag-5'>追蹤</b>不求人!

    詳解journalctl日志管理

    systemd 提供了自己的日志系統(logging system),稱為 journal。使用 systemd 日志,無需額外安裝日志服務(syslog)。
    的頭像 發表于 06-05 17:22 ?1546次閱讀
    詳解journalctl<b class='flag-5'>日志</b>管理

    愛立信攜手Telstra、高通刷新5G上行速度紀錄

    愛立信、Telstra、高通近日攜手創下5G上行516 Mbps速度新紀錄,成為目前在商用Sub-6GHz 5G SA現網實現的最高上行
    的頭像 發表于 03-26 16:31 ?1.3w次閱讀