最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能(最新推薦)

 更新時(shí)間:2023年06月06日 11:24:32   作者:ThinkPet  
這篇文章主要介紹了SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能,本文通過(guò)示例代碼給大家介紹非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能

物料準(zhǔn)備:

1.自定義1個(gè)線程MDC打點(diǎn)工具類

2.配置logback打印MDC打點(diǎn)的traceId

3.配置webMVC使用MDC打點(diǎn)

4.配置ThreadPoolTaskExecutor使用MDC打點(diǎn)

5.配置HttpClient使用MDC打點(diǎn)

6.測(cè)試MDC日志打點(diǎn)效果

線程mdc打點(diǎn)工具類代碼

package cn.ath.knowwikibackend.mdc;
import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
/**
 * 線程mdc打點(diǎn)工具類
 */
public class ThreadMdcUtil {
    public static void setTRaceIdIfAbsent() {
        if (MDC.get("traceId") == null) {
            MDC.put("traceId", UUID.fastUUID().toString());
        }
    }
    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            setTRaceIdIfAbsent();
            try {
                //最終通過(guò) callable.call執(zhí)行線程任務(wù)
                return callable.call();
            } finally {
                MDC.clear();
            }
        };
    }
    public static Runnable wrap(final Runnable runnable,final Map<String,String> context){
        return ()->{
          if (context==null){
              MDC.clear(); //mdc上下文為空 就清掉mdc
          }else {
              MDC.setContextMap(context);  // mdc上下文不為空,要設(shè)置上下文為 context
          }
          setTRaceIdIfAbsent(); //設(shè)置mdc 記錄traceId
          try {
              //最終通過(guò) runnable.run 執(zhí)行線程任務(wù)
              runnable.run();
          }finally {
              MDC.clear();
          }
        };
    }
}

配置logback 輸出的日志格式,要輸出mdc里定義的traceId

logging:
  file:
    path: ${user.home}/.${spring.application.name}/log/
  logback:
    rollingpolicy:
      max-file-size: 15MB
      max-history: 10
  pattern: # 注意這里配置的 [%X{traceId}] 即輸出mdc打點(diǎn)的traceId值
    console: "%date  %level [%thread] [%X{traceId}] %logger{10} [%file : %line] %msg%n"
    file: "%date  %level [%thread] [%X{traceId}] %logger{10} [%file : %line] %msg%n"
  level:
    cn.ath.knowwikibackend.rest: info

配置webMVC使用MDC打點(diǎn)

定義MvcTraceInterceptor,來(lái)攔截http請(qǐng)求進(jìn)行mdc打點(diǎn)

package cn.ath.knowwikibackend.mdc;
import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * mvc trace攔截器,作用是 實(shí)現(xiàn)trace打點(diǎn)
 */
public class MvcTraceInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //在請(qǐng)求頭里拿一個(gè) traceId ,拿不到就創(chuàng)建1個(gè) traceId
        String traceId = request.getHeader("traceId");
        if (traceId==null){
            traceId = UUID.fastUUID().toString();
        }
        // traceId記錄到mdc中
        MDC.put("traceId",traceId);
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //1個(gè)http請(qǐng)求 后臺(tái)處理完畢后 ,從mdc中移除 traceId
        MDC.remove("traceId");
    }
}

使用自定義的MvcTraceInterceptor

package cn.ath.knowwikibackend.mdc;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcMdcConfig implements WebMvcConfigurer {
    /**
     * 配置spring mvc啟用 mvc trace攔截器,實(shí)現(xiàn)trace打點(diǎn)
     * @param registry InterceptorRegistry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MvcTraceInterceptor())
                .addPathPatterns("/**");
    }
}

配置ThreadPoolTaskExecutor使用MDC打點(diǎn)

package cn.ath.knowwikibackend.mdc;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.io.Serializable;
import java.util.concurrent.*;
/**
 * 異步線程池 的mdc 包裝器,作用是 讓 async 異步任務(wù) 實(shí)現(xiàn)trace打點(diǎn)
 */
public class AsyncThreadPoolMdcWrapper extends ThreadPoolTaskExecutor implements Serializable {
    private static final long serialVersionUID = -1530245553055682935L;
    @Override
    public void execute(Runnable task) {
        // Runnable 類型的線程運(yùn)行時(shí)  進(jìn)行 mdc 打點(diǎn)記錄
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        // Callable 類型的線程運(yùn)行時(shí)  進(jìn)行 mdc 打點(diǎn)記錄
        return super.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));
    }
    @Override
    public Future<?> submit(Runnable task) {
        //  Runnable 類型且返回Future的 線程運(yùn)行時(shí)  進(jìn)行 mdc 打點(diǎn)記錄
        return super.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));
    }
}

配置ApacheHttpClient使用MDC打點(diǎn)

package cn.ath.knowwikibackend.mdc;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.protocol.HttpContext;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
 * 自定義 HttpRequestInterceptor,
 * 這里可以對(duì)外發(fā)的http請(qǐng)求 追加請(qǐng)求頭/請(qǐng)求參數(shù)之類的配置
 *
 * 這里 在 Header 里追加上本應(yīng)用的traceId ,便于全局排查請(qǐng)求日志
 */
@Component
@Slf4j
public class HttpClientTracedInterceptor implements HttpRequestInterceptor {
    @Override
    public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {
        //從mdc 中取出traceId 然后追加到 外發(fā)的http請(qǐng)求頭里
        String traceId = MDC.get("traceId");
        if (traceId != null){
            httpRequest.addHeader("traceId",traceId);
        }
        //打印出所有的http請(qǐng)求頭
        for (Header header : httpRequest.getAllHeaders()) {
            log.info("req header item---->{}",header);
        }
    }
}

測(cè)試MDC日志打點(diǎn)效果

修改之前的異步線程池使用AsyncThreadPoolMdcWrapper 替換掉默認(rèn)的ThreadPoolTaskExecutor

@Configuration
public class AsyncConfig {
     @Bean("asyncCountTestTaskExecutor")
    public AsyncThreadPoolMdcWrapper asyncCountTaskTest(){
        AsyncThreadPoolMdcWrapper executor = new AsyncThreadPoolMdcWrapper();
        //核心線程數(shù)5:線程池創(chuàng)建時(shí)候初始化的線程數(shù)
        executor.setCorePoolSize(5);
        //最大線程數(shù)10:線程池最大的線程數(shù),只有在緩沖隊(duì)列滿了之后才會(huì)申請(qǐng)超過(guò)核心線程數(shù)的線程
        executor.setMaxPoolSize(10);
        //緩沖隊(duì)列100:用來(lái)緩沖執(zhí)行任務(wù)的隊(duì)列
        executor.setQueueCapacity(100);
        //允許線程的空閑時(shí)間60秒:當(dāng)超過(guò)了核心線程出之外的線程在空閑時(shí)間到達(dá)之后會(huì)被銷毀
        executor.setKeepAliveSeconds(60);
        //線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
        executor.setThreadNamePrefix("countTestTaskAsync-");
        //線程池滿了后新任務(wù)由 任務(wù)發(fā)起者的線程執(zhí)行
        RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
        executor.setRejectedExecutionHandler(callerRunsPolicy);
        executor.initialize();
        return executor;
    }
    @Bean("asyncVoidTestTaskExecutor")
    public AsyncThreadPoolMdcWrapper asyncVoidTaskTest(){
        AsyncThreadPoolMdcWrapper executor = new AsyncThreadPoolMdcWrapper();
        //核心線程數(shù)5:線程池創(chuàng)建時(shí)候初始化的線程數(shù)
        executor.setCorePoolSize(5);
        //最大線程數(shù)10:線程池最大的線程數(shù),只有在緩沖隊(duì)列滿了之后才會(huì)申請(qǐng)超過(guò)核心線程數(shù)的線程
        executor.setMaxPoolSize(10);
        //緩沖隊(duì)列100:用來(lái)緩沖執(zhí)行任務(wù)的隊(duì)列
        executor.setQueueCapacity(100);
        //允許線程的空閑時(shí)間60秒:當(dāng)超過(guò)了核心線程出之外的線程在空閑時(shí)間到達(dá)之后會(huì)被銷毀
        executor.setKeepAliveSeconds(60);
        //線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
        executor.setThreadNamePrefix("voidTestTaskAsync-");
        //線程池滿了后新任務(wù)由 任務(wù)發(fā)起者的線程執(zhí)行
        RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
        executor.setRejectedExecutionHandler(callerRunsPolicy);
        executor.initialize();
        return executor;
    }
}

在API接口中測(cè)試

@Slf4j
@RestController
@RequestMapping("/third")
public class TestApi {
    @Autowired
    HttpClientTracedInterceptor httpClientTracedInterceptor;
    @Autowired
    private AsyncAllService asyncAllService
    @GetMapping("/t1")
    public String te() throws ExecutionException, InterruptedException, IOException {
        log.trace("trace---test!!!!!");
        log.info("info---test!!!!!");
        log.warn("warn---test!!!!!");
        log.debug("debug---test!!!!!");
        log.error("error---test!!!!!");
        //有返回值的async任務(wù)
        Future<Long> longFuture = asyncAllService.testCount1();
        //無(wú)返回值的async任務(wù)
        asyncAllService.testAsync2();
        //有返回值的async任務(wù),需要future執(zhí)行后,最后統(tǒng)一get返回值
        Long l605 = longFuture.get();
        log.info("async task res:{}",l605);
        //測(cè)試使用apache httpclient 外發(fā)1個(gè)http請(qǐng)求
        String content = "test.dhrth.xxx.zzzdfg.derferf.sregvreg.regetg.esrtg34gf3";
        String url = "http://10.1.5.212:8008/api/getresult";
        Map<String, String> mapData = new HashMap<String, String>();
        mapData.put("type", "NER_RE");
        mapData.put("text", content);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sid", "re");
        map.put("data", mapData);
        String reqStr = JSON.toJSONString(map);
        // 獲取httpclient
        CloseableHttpClient httpclient = HttpClients.custom()
                .addInterceptorFirst(httpClientTracedInterceptor)
                .build();
        //創(chuàng)建post請(qǐng)求
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(20*1000)
                .setConnectionRequestTimeout(1000)
                .setConnectTimeout(1000).build();
        httpPost.setConfig(requestConfig);
        StringEntity entity = new StringEntity(reqStr, ContentType.APPLICATION_JSON);
        httpPost.setEntity(entity);
        CloseableHttpResponse response = httpclient.execute(httpPost);
        // 得到響應(yīng)信息
        int statusCode = response.getStatusLine().getStatusCode();
        log.info("http-res-statusCode:{}",statusCode);
        String respStr = EntityUtils.toString(response.getEntity(), "utf-8");
        log.info("http-resp:{}",respStr);
        return "thirdTestApi測(cè)試!";
    }
}    

測(cè)試控制臺(tái)輸出的日志效果

2023-06-05 15:45:54,228  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 94] 請(qǐng)求URI:/kwb/third/t1
2023-06-05 15:45:54,251  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 107] 請(qǐng)求目標(biāo)類:String cn.ath.knowwikibackend.rest.TestApi.te()
2023-06-05 15:45:54,254  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 60] info---test!!!!!
2023-06-05 15:45:54,254  WARN [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 61] warn---test!!!!!
2023-06-05 15:45:54,255  ERROR [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 63] error---test!!!!!
2023-06-05 15:45:54,299  INFO [countTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 35] now:2023-06-05 15:45:54
2023-06-05 15:45:54,299  INFO [voidTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 52] now:2023-06-05 15:45:54
2023-06-05 15:45:54,300  INFO [countTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 36] ---exec testCount1------------
2023-06-05 15:45:54,300  INFO [voidTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 53] ---exec testAsync2------------
2023-06-05 15:45:54,300  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 73] async task res:8
2023-06-05 15:45:54,352  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.m.HttpClientTracedInterceptor [HttpClientTracedInterceptor.java : 36] req header item---->traceId: 8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4
2023-06-05 15:45:55,429  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 109] http-res-statusCode:200
2023-06-05 15:45:55,431  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 121] http-resp:{
    "status": "OK",
    "message": "提取成功",
    "result": {}
}
2023-06-05 15:45:55,432  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 125] Around請(qǐng)求耗時(shí):1227ms

從日志中可以看到,1次瀏覽器請(qǐng)求進(jìn)到app后,從切面就開始mdc打點(diǎn),之后的異步線程操作 和 外發(fā)http操作 的log日志中都顯示出了本次瀏覽器請(qǐng)求對(duì)應(yīng)的后臺(tái)日志的打點(diǎn)traceId值為 8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4

到此這篇關(guān)于SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能的文章就介紹到這了,更多相關(guān)SpringBoot日志打點(diǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于springboot集成hbase過(guò)程解析

    基于springboot集成hbase過(guò)程解析

    這篇文章主要介紹了基于springboot集成hbase過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Springboot上傳文件與物理刪除功能

    Springboot上傳文件與物理刪除功能

    文章介紹了在Springboot中實(shí)現(xiàn)文件上傳和刪除的功能,實(shí)現(xiàn)了圖片的上傳與刪除,刪除數(shù)據(jù)庫(kù)記錄時(shí),同步刪除了文件,結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Netty分布式pipeline管道Handler的添加代碼跟蹤解析

    Netty分布式pipeline管道Handler的添加代碼跟蹤解析

    這篇文章主要介紹了Netty分布式pipeline管道Handler的添加代碼跟蹤解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Java利用Spire.Doc for Java實(shí)現(xiàn)在模板的基礎(chǔ)上創(chuàng)建Word文檔

    Java利用Spire.Doc for Java實(shí)現(xiàn)在模板的基礎(chǔ)上創(chuàng)建Word文檔

    在日常開發(fā)中,我們經(jīng)常需要根據(jù)特定數(shù)據(jù)動(dòng)態(tài)生成Word文檔,本文將深入探討如何利用強(qiáng)大的Java庫(kù) Spire.Doc for Java,在預(yù)設(shè)Word模板的基礎(chǔ)上,通過(guò)替換占位符或書簽來(lái)高效創(chuàng)建定制化的Word文檔,感興趣的小伙伴可以了解下
    2025-12-12
  • java 讀寫文件[多種方法]

    java 讀寫文件[多種方法]

    前兩天用到讀寫文件的操作,上網(wǎng)搜了一些這方面的資料。很有用的。
    2008-11-11
  • 深入理解LinkedHashSet集合的底層機(jī)制

    深入理解LinkedHashSet集合的底層機(jī)制

    這篇文章主要介紹了LinkedHashSet的底層機(jī)制詳解,LinkedHashSet根據(jù)元素的hashCode值來(lái)決定元素的存儲(chǔ)位置,同時(shí)使用鏈表維護(hù)元素的次序,?這使得元素看起來(lái)是以插入順序保存的,需要的朋友可以參考下
    2023-10-10
  • Spring?WebClient從入門到精通

    Spring?WebClient從入門到精通

    本文詳解SpringWebClient非阻塞響應(yīng)式特性及優(yōu)勢(shì),涵蓋核心API、實(shí)戰(zhàn)應(yīng)用與性能優(yōu)化,對(duì)比RestTemplate,為微服務(wù)通信提供高效解決方案,本文將深入探討WebClient的核心特性、使用方法及最佳實(shí)踐,一起看看吧
    2025-07-07
  • Postman form-data、x-www-form-urlencoded的區(qū)別及說(shuō)明

    Postman form-data、x-www-form-urlencoded的區(qū)別及說(shuō)明

    這篇文章主要介紹了Postman form-data、x-www-form-urlencoded的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Shiro與Springboot整合開發(fā)的基本步驟過(guò)程詳解

    Shiro與Springboot整合開發(fā)的基本步驟過(guò)程詳解

    這篇文章主要介紹了Shiro與Springboot整合開發(fā)的基本步驟,本文結(jié)合實(shí)例代碼給大家介紹整合過(guò)程,感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • springboot 設(shè)置server.port不生效的原因及解決

    springboot 設(shè)置server.port不生效的原因及解決

    這篇文章主要介紹了springboot 設(shè)置server.port不生效的原因及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評(píng)論

双流县| 霍城县| 新野县| 临猗县| 剑川县| 昔阳县| 安新县| 南和县| 陵川县| 关岭| 象山县| 兴和县| 纳雍县| 商城县| 万州区| 上饶市| 乃东县| 尚义县| 荣成市| 加查县| 富川| 扬州市| 鹤庆县| 东乌| 平江县| 双牌县| 台北市| 雅江县| 比如县| 安宁市| 重庆市| 尉氏县| 古丈县| 塘沽区| 洛浦县| 澄江县| 游戏| 大邑县| 子洲县| 驻马店市| 桐庐县|