日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

手動(dòng)實(shí)現(xiàn)SpringBoot日志鏈路追蹤

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

掃碼添加小助手

加入工程師交流群

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

前言

從文章標(biāo)題就知道,這篇文章是介紹些什么。

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

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

好像是的,確實(shí)這種現(xiàn)象是普遍存在的。

有時(shí)候一個(gè)業(yè)務(wù)調(diào)用鏈場景,很長,調(diào)了各種各樣的方法,看日志的時(shí)候,各個(gè)接口的日志穿插,確實(shí)讓人頭大。

模糊匹配搜索日志能解決嗎? 能解決一點(diǎn)點(diǎn)。 但是不能完全呈現(xiàn)出整個(gè)鏈路相關(guān)的日志。

那要做到方便,很顯然,我們需要的是把同一次的業(yè)務(wù)調(diào)用鏈上的日志串起來。

什么效果? 先看一個(gè)實(shí)現(xiàn)后的效果圖:

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

這樣下來,我們?cè)倥浜夏:ヅ洳檎胰罩?,效果不就剛剛的了?/p>

cat-ninfo.log|grep"a415ad50dbf84e99b1b56a31aacd209c"

或者

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

不多說,開整。

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

正文

慣例,先看一眼這次實(shí)戰(zhàn)最終工程的結(jié)構(gòu):

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,但需保證一定的復(fù)雜度唯一性;如果沒使用默認(rèn)UUID自動(dòng)生成
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提供的一個(gè)支持動(dòng)態(tài)打印日志信息的工具。

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());
//可以具體制定哪些需要攔截,哪些不攔截,其實(shí)也可以使用自定義注解更靈活完成
//.addPathPatterns("/**")
//.excludePathPatterns("/testxx.html");
}
}

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

到這時(shí)候,其實(shí)已經(jīng)完成,就是這么簡單。

我們寫個(gè)測試接口,看下效果:

@PostMapping("doTest")
publicStringdoTest(@RequestParam("name")Stringname)throwsInterruptedException{
log.info("入?yún)ame={}",name);
testTrace();
log.info("調(diào)用結(jié)束name={}",name);
return"Hello,"+name;
}
privatevoidtestTrace(){
log.info("這是一行info日志");
log.error("這是一行error日志");
testTrace2();
}
privatevoidtestTrace2(){
log.info("這也是一行info日志");

}

效果(OK的):

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

還沒完。

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

故意寫一個(gè)異步線程,加入這個(gè)調(diào)用里面:

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

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

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

所以我們需要針對(duì)子線程使用情形,做調(diào)整,思路: 將父線程的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{
/**
*聲明一個(gè)線程池
*
*@return執(zhí)行器
*/
@Bean("MyExecutor")
publicExecutorasyncExecutor(){
MyThreadPoolTaskExecutorexecutor=newMyThreadPoolTaskExecutor();
//核心線程數(shù)5:線程池創(chuàng)建時(shí)候初始化的線程數(shù)
executor.setCorePoolSize(5);
//最大線程數(shù)5:線程池最大的線程數(shù),只有在緩沖隊(duì)列滿了之后才會(huì)申請(qǐng)超過核心線程數(shù)的線程
executor.setMaxPoolSize(5);
//緩沖隊(duì)列500:用來緩沖執(zhí)行任務(wù)的隊(duì)列
executor.setQueueCapacity(500);
//允許線程的空閑時(shí)間60秒:當(dāng)超過了核心線程出之外的線程在空閑時(shí)間到達(dá)之后會(huì)被銷毀
executor.setKeepAliveSeconds(60);
//線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
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";

//獲取唯一性標(biāo)識(shí)
publicstaticStringgenerateTraceId(){
returnUUID.randomUUID().toString();
}

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

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

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

OK,重啟服務(wù),再看看效果:

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

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



審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    341

    瀏覽量

    16060
  • 日志
    +關(guān)注

    關(guān)注

    0

    文章

    149

    瀏覽量

    11098
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    178

    瀏覽量

    718

原文標(biāo)題:手動(dòng)實(shí)現(xiàn) SpringBoot 日志鏈路追蹤,無需引入組件,日志定位更方便!

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    為什么無法刷新 MCU 固件?

    了MCU探針,并嘗試使用安全配置工具來刷新MCU固件。但寫入映像選項(xiàng)已被禁用。我不確定自己遺漏了哪些步驟。在此方面,懇請(qǐng)得到您的幫助。
    發(fā)表于 04-30 07:06

    NXP數(shù)字鑰匙 3.0-真正實(shí)現(xiàn)手動(dòng)汽車門禁

    NXP數(shù)字鑰匙3.0-真正實(shí)現(xiàn)手動(dòng)汽車門禁
    發(fā)表于 04-14 14:11 ?0次下載

    SDV域控器日志追蹤與解析技術(shù) – DLT

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

    模組日志功能技術(shù)概覽

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

    BLE SoC,如何助力管理者實(shí)現(xiàn)高效的資產(chǎn)追蹤

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

    電能質(zhì)量在線監(jiān)測裝置數(shù)據(jù)日志能加密存儲(chǔ)嗎?

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

    如何使用SpringBoot、Vue2.0、MySQL開發(fā)一套云診所系統(tǒng)?

    (RESTful)等。 對(duì)于云診所系統(tǒng),SpringBoot可以用于實(shí)現(xiàn)患者管理、預(yù)約掛號(hào)、電子病歷、藥品管理、收費(fèi)管理等核心功能。 前端:V
    的頭像 發(fā)表于 11-27 16:02 ?421次閱讀
    如何使用<b class='flag-5'>SpringBoot</b>、Vue2.0、MySQL開發(fā)一套云診所系統(tǒng)?

    電能質(zhì)量在線監(jiān)測裝置的備用切換機(jī)制是否支持遠(yuǎn)程控制?

    現(xiàn)代電能質(zhì)量在線監(jiān)測裝置的備用切換機(jī)制 普遍支持遠(yuǎn)程控制 ,主流廠商通過協(xié)議指令、軟件平臺(tái)和硬件冗余設(shè)計(jì),實(shí)現(xiàn)了從狀態(tài)查詢、策略配置
    的頭像 發(fā)表于 11-06 16:48 ?1618次閱讀

    電能質(zhì)量在線監(jiān)測裝置的備用切換需要手動(dòng)干預(yù)嗎?

    電能質(zhì)量在線監(jiān)測裝置的備用切換 通常無需手動(dòng)干預(yù) ,主流設(shè)備通過硬件冗余設(shè)計(jì)、協(xié)議層自動(dòng)切換機(jī)制和智能算法實(shí)現(xiàn)全流程自動(dòng)化。以下是關(guān)鍵實(shí)現(xiàn)
    的頭像 發(fā)表于 11-06 16:29 ?1461次閱讀

    資源狀態(tài)感知是如何實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)狀態(tài)的實(shí)時(shí)感知的?

    資源狀態(tài)感知對(duì)網(wǎng)絡(luò)狀態(tài)的實(shí)時(shí)監(jiān)測是通過硬件底層檢測、協(xié)議層交互、算法模型分析的多層協(xié)同實(shí)現(xiàn)的,具體技術(shù)路徑如下: 一、硬件層:物理信號(hào)的實(shí)時(shí)捕獲 PHY 芯片的直接感知以太網(wǎng) PHY 芯片(如
    的頭像 發(fā)表于 11-06 14:49 ?891次閱讀

    目標(biāo)追蹤的簡易實(shí)現(xiàn):模板匹配

    一、目標(biāo)追蹤和圖像識(shí)別 一般來說,提到機(jī)器視覺這個(gè)概念都會(huì)想到圖像識(shí)別,比如人臉識(shí)別、文本識(shí)別等等,目標(biāo)追蹤這個(gè)概念在平時(shí)接觸的相對(duì)比較少。但實(shí)際上,目標(biāo)追蹤可以理解為圖像識(shí)別的動(dòng)態(tài)過程:圖像識(shí)別
    發(fā)表于 10-28 07:21

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

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

    如何使用樹莓派與OpenCV實(shí)現(xiàn)面部和運(yùn)動(dòng)追蹤的云臺(tái)系統(tǒng)?

    大家好,這是一個(gè)樹莓派和OpenCV的連載專題。使用樹莓派與OpenCV實(shí)現(xiàn)姿態(tài)估計(jì)和面部特征點(diǎn)追蹤使用樹莓派與OpenCV實(shí)現(xiàn)面部和運(yùn)動(dòng)追蹤的云臺(tái)系統(tǒng)使用樹莓派和OpenCV
    的頭像 發(fā)表于 08-14 17:45 ?2515次閱讀
    如何使用樹莓派與OpenCV<b class='flag-5'>實(shí)現(xiàn)</b>面部和運(yùn)動(dòng)<b class='flag-5'>追蹤</b>的云臺(tái)系統(tǒng)?

    手把手教你配置遠(yuǎn)程errDump調(diào)試:日志追蹤不求人!

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

    詳解journalctl日志管理

    systemd 提供了自己的日志系統(tǒng)(logging system),稱為 journal。使用 systemd 日志,無需額外安裝日志服務(wù)(syslog)。
    的頭像 發(fā)表于 06-05 17:22 ?1976次閱讀
    詳解journalctl<b class='flag-5'>日志</b>管理
    敖汉旗| 临夏县| 林州市| 湟源县| 襄城县| 靖远县| 新营市| 勃利县| 娱乐| 富锦市| 宁波市| 水城县| 双峰县| 南漳县| 甘肃省| 东平县| 青岛市| 社旗县| 隆尧县| 页游| 乌苏市| 延安市| 宜阳县| 泽普县| 尚志市| 玉环县| 永吉县| 宣城市| 尼勒克县| 茶陵县| 娱乐| 项城市| 东明县| 抚宁县| 铁岭县| 吴江市| 灵璧县| 兴隆县| 嘉峪关市| 枣庄市| 定南县|