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

詳解Java中日志跟蹤的簡單實(shí)現(xiàn)

 更新時(shí)間:2022年08月30日 09:04:07   作者:noknow  
MDC?(Mapped?Diagnostic?Context,映射調(diào)試上下文)是?log4j??、logback及l(fā)og4j2??提供的一種方便在多線程條件下記錄日志的功能。本文將利用MDC實(shí)現(xiàn)簡單的日志跟蹤,需要的可以參考一下

一、前言

在編碼過程中,常常需要寫打印日志語句,我們期望的是同一個(gè)業(yè)務(wù)的日志都在一塊,在出問題的時(shí)候好根據(jù)日志來排查問題。而現(xiàn)實(shí)是在應(yīng)用運(yùn)行中,日志的輸出常常來自不同線程,甚至是在不同微服務(wù)中,各種日志記錄往往彼此穿插,很難串起來。所以往往在日志中手動(dòng)增加一些關(guān)鍵字,來對接口的調(diào)用鏈路來進(jìn)行跟蹤。但這種手動(dòng)增加關(guān)鍵字或唯一標(biāo)識(shí)的做法在微服務(wù)場景下,很難在上下游應(yīng)用的開發(fā)人員的編碼風(fēng)格形成統(tǒng)一的規(guī)范,并且手動(dòng)編寫也很難稱得上優(yōu)雅。

二、MDC介紹

MDC?(Mapped Diagnostic Context,映射調(diào)試上下文)是 log4j? 、logback及l(fā)og4j2? 提供的一種方便在多線程條件下記錄日志的功能。MDC? 可以看成是一個(gè)與當(dāng)前線程綁定的哈希表,MDC 中包含的內(nèi)容可以被同一線程中執(zhí)行的代碼所訪問。

MDC中的鍵值對是可以直接被日志框架所使用(即“打印”)的,只需要配置相應(yīng)日志pattern。例如pattern如下:

%d{HH:mm:ss.SSS} [%thread] [%X{TraceId}] %-5level %logger{50} - %msg%n

代碼如下:

public class MDCTest {

    private static final Logger log = LoggerFactory.getLogger(MDCTest.class);

    @Test
    void test() {
        MDC.put("TraceId", "123456789");
        log.info("hello {}", "world");
    }
}

此時(shí)控制臺(tái)將輸出:

21:16:04.342 [main] [123456789] INFO  com.nk.MDCTest - hello world

三、實(shí)現(xiàn)方案

1、基本思路

修改日志pattern,并在業(yè)務(wù)開始的時(shí)候?qū)race id放入到MDC,在業(yè)務(wù)結(jié)束時(shí)去除MDC的trace id。這樣的好處便是代碼簡潔,不需要手動(dòng)寫trace id,日志風(fēng)格也能保持統(tǒng)一。

業(yè)務(wù)開始的時(shí)機(jī)一般是應(yīng)用收到HTTP請求,所以可以用Filter或SpringMVC的Interceptor來對MDC中trace id進(jìn)行初始化和清除。在Dubbo調(diào)用的時(shí)候也可以通過類似功能的Filter來對MDC中trace id進(jìn)行操作,從而達(dá)到trace id傳遞的作用。

2、實(shí)現(xiàn)(以SpringBoot為例)

2.1 修改log pattern

在SpringBoot中,直接修改application.properties即可:

logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{TraceId}] %-5level %logger{50} - %msg%n

重點(diǎn)在于%X{TraceId}?,其中TraceId?需要作為key出現(xiàn)在MDC里。

2.2 業(yè)務(wù)開始

TraceId工具類,封裝MDC關(guān)于trace id的基礎(chǔ)操作:

public final class TraceIdUtil {

    private static final String TRACE_ID_KEY = "TraceId";

    private TraceIdUtil() {
    }

    public static void putIfAbsent() {
        if (StrUtil.isBlank(get())) {
            put(UUID.randomUUID().toString());
        }
    }

    public static void remove() {
        if (get() != null) {
            MDC.remove(TRACE_ID_KEY);
        }
    }

    public static String get() {
        return MDC.get(TRACE_ID_KEY);
    }

    public static void put(String traceId) {
        MDC.put(TRACE_ID_KEY, traceId);
    }
}

Filter?方式和Interceptor二選其一既可,其基本思想是一樣的。

Filter方式

@Component
public class LogFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, 
                         ServletResponse servletResponse, 
                         FilterChain filterChain) throws IOException, ServletException {
        TraceIdUtil.putIfAbsent();//生成trace id放入MDC中
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            TraceIdUtil.remove();//移除MDC中的trace id
        }
    }
}

Interceptor

@Configuration
public class LogInterceptor implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AsyncHandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, 
                                     HttpServletResponse response, 
                                     Object handler) throws Exception {
                TraceIdUtil.putIfAbsent();//生成trace id放入MDC中
                return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
            }
            
            @Override
            public void afterCompletion(HttpServletRequest request, 
                                        HttpServletResponse response, 
                                        Object handler, Exception ex) throws Exception {
                TraceIdUtil.remove();//移除MDC中的trace id
                AsyncHandlerInterceptor.super.afterCompletion(request, response, handler, ex);
            }
        });
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

2.3 業(yè)務(wù)中使用

正常使用logger,無需關(guān)心trace id。例如:

@RestController
@RequestMapping("/api/user")
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{userId}")
    public UserDto queryUser(@PathVariable Long userId) {
        log.info("query user by id:{}", userId);
        UserDto user = userService.query(userId);
        log.info("query user result:{}", user);
        return user;
    }
}

請求該接口將輸出如下的日志樣式:

2022-04-05 09:40:17.638 [http-nio-8080-exec-1] [a02b13d81c224e49956afd4efbb85ca8] INFO  com.nk.webapp.controller.UserController - ready to query user by id:1
2022-04-05 09:40:17.670 [http-nio-8080-exec-1] [a02b13d81c224e49956afd4efbb85ca8] INFO  com.nk.webapp.controller.UserController - query result:UserDto(userId=1, username=zhang3, age=23, email=abc@example.com)

四、總結(jié)

日志鏈路的跟蹤核心是使用MDC作為trace id載體,在業(yè)務(wù)開始階段一般通過攔截器就生成trace id并放入到MDC中,并根據(jù)MDC的相關(guān)特性將trace id投射到日志文本中,從而實(shí)現(xiàn)在同一個(gè)業(yè)務(wù)調(diào)用鏈路中的日志具有唯一標(biāo)識(shí)。

以上就是詳解Java中日志跟蹤的簡單實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Java 日志跟蹤的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot啟動(dòng)流程之引導(dǎo)上下文DefaultBootstrapContext的過程

    SpringBoot啟動(dòng)流程之引導(dǎo)上下文DefaultBootstrapContext的過程

    本文詳細(xì)介紹了SpringBoot版本2.7.18中SpringApplication的run方法,引導(dǎo)注冊組件初始化器BootstrapRegistryInitializer是SpringBoot的第一個(gè)擴(kuò)展點(diǎn),負(fù)責(zé)應(yīng)用啟動(dòng)早期階段的初始化和配置,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • 過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    這篇文章主要介紹了過濾器 和 攔截器的 6個(gè)區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • java ExecutorService CompletionService線程池區(qū)別與選擇

    java ExecutorService CompletionService線程池區(qū)別與選擇

    這篇文章主要為大家介紹了java ExecutorService CompletionService線程池區(qū)別與選擇使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Java如何獲取word文檔的條目化內(nèi)容

    Java如何獲取word文檔的條目化內(nèi)容

    這篇文章主要介紹了Java獲取word文檔的條目化內(nèi)容的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-05-05
  • Spring Cloud 2020.0.0正式發(fā)布再見了Netflix

    Spring Cloud 2020.0.0正式發(fā)布再見了Netflix

    這篇文章主要介紹了Spring Cloud 2020.0.0正式發(fā)布再見了Netflix,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 圖文詳解OkHttp的超時(shí)時(shí)間

    圖文詳解OkHttp的超時(shí)時(shí)間

    HTTP是現(xiàn)代應(yīng)用常用的一種交換數(shù)據(jù)和媒體的網(wǎng)絡(luò)方式,高效地使用HTTP能讓資源加載更快,節(jié)省帶寬,OkHttp是一個(gè)高效的HTTP客戶端,下面這篇文章主要給大家介紹了關(guān)于OkHttp超時(shí)時(shí)間的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用詳解

    Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用詳解

    項(xiàng)目日志記錄是項(xiàng)目開發(fā)、運(yùn)營必不可少的內(nèi)容,有了它可以對系統(tǒng)有整體的把控,出現(xiàn)任何問題都有蹤跡可尋。下面這篇文章主要給大家介紹了關(guān)于Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用的相關(guān)資料,需要的朋友可以參考下。
    2017-12-12
  • 詳解lombok @Getter @Setter 使用注意事項(xiàng)

    詳解lombok @Getter @Setter 使用注意事項(xiàng)

    這篇文章主要介紹了詳解lombok @Getter @Setter 使用注意事項(xiàng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java利用泛型實(shí)現(xiàn)折半查找法

    Java利用泛型實(shí)現(xiàn)折半查找法

    泛型是JAVA重要的特性,使用泛型編程,可以使代碼復(fù)用率提高。查找作為泛型的一個(gè)簡單應(yīng)用,本文將使用泛型實(shí)現(xiàn)折半查找法,感興趣的可以了解一下
    2022-08-08
  • Mybatis?List列表In查詢實(shí)現(xiàn)的注意事項(xiàng)說明

    Mybatis?List列表In查詢實(shí)現(xiàn)的注意事項(xiàng)說明

    這篇文章主要介紹了Mybatis?List列表In查詢實(shí)現(xiàn)的注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02

最新評論

洞口县| 剑河县| 阿城市| 贡觉县| 安庆市| 沈丘县| 乐陵市| 汶上县| 富裕县| 鄂伦春自治旗| 会同县| 桑植县| 临清市| 额济纳旗| 长春市| 拉孜县| 长沙县| 许昌市| 凤阳县| 商都县| 柯坪县| 赤水市| 逊克县| 三原县| 永丰县| 娱乐| 博爱县| 彰化县| 赣州市| 屏边| 泰兴市| 云南省| 灵丘县| 屯昌县| 逊克县| 庐江县| 榆中县| 漠河县| 宜兴市| 长泰县| 开封市|