如何為L(zhǎng)ogback日志添加唯一追蹤ID
為L(zhǎng)ogback日志添加唯一追蹤ID
平常在測(cè)試的時(shí)候,不容易定位報(bào)錯(cuò)信息,這個(gè)時(shí)候給日志加上唯一的追蹤ID,查找日志的時(shí)候就非常方便了。
像這樣:

每個(gè)請(qǐng)求打印的日志都會(huì)有不同的ID,哪個(gè)請(qǐng)求出錯(cuò),根據(jù)ID來(lái)定位日志就行了。
這個(gè)ID還會(huì)返回給前端,前端發(fā)現(xiàn)報(bào)錯(cuò)讓后臺(tái)找原因的話(huà)只需要給個(gè)ID,后臺(tái)開(kāi)發(fā)人員就能根據(jù)
環(huán)境:
- SpringBoot - 2.1.5.RELEASE
- JDK8
一、創(chuàng)建過(guò)濾器
- LogMDCFilter.java
public class LogMDCFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String requestIdKey = "requestId";
String requestId = UUID.randomUUID().toString();
MDC.put(requestIdKey, requestId);
String levelName = "logLevel";
String value = servletRequest.getParameter(levelName);
if (StringUtils.isNotBlank(value)) {
//org.slf4j.MDC
MDC.put(levelName, value.toUpperCase());
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
MDC.remove(requestIdKey);
MDC.remove(levelName);
}
}
@Override
public void destroy() {
}
}- DebugLogTurboFilter.java
public class DebugLogTurboFilter extends TurboFilter {
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
int levelInt = level.toInt();
String levelName = MDC.get("logLevel");
if (StringUtils.isBlank(levelName) || "DEBUG,INFO,TRACE,WARN".indexOf(levelName) == -1) {
return FilterReply.NEUTRAL;
}
if ((Level.TRACE.levelStr.equals(levelName) && levelInt >= Level.TRACE_INT)
|| (Level.DEBUG.levelStr.equals(levelName) && levelInt >= Level.DEBUG_INT)
|| (Level.INFO.levelStr.equals(levelName) && levelInt >= Level.INFO_INT)
|| (Level.WARN.levelStr.equals(levelName) && levelInt >= Level.WARN_INT)) {
return FilterReply.ACCEPT;
}
return FilterReply.DENY;
}
}二、注冊(cè)過(guò)濾器
- FilterConfiguration.java
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean logFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
//注入過(guò)濾器
registration.setFilter(new LogMDCFilter());
//攔截規(guī)則
registration.addUrlPatterns("/*");
//過(guò)濾器名稱(chēng)
registration.setName("logMDCFilter");
//過(guò)濾器順序
registration.setOrder(0);
return registration;
}
}
三、Logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg %X{requestId}%n
</pattern>
</encoder>
</appender>
//上面的 DebugLogTurboFilter
<turboFilter class="com.example.common.config.DebugLogTurboFilter">
</turboFilter>
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/logs/merchant/common-merchant.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/home/logs/merchant/history/merchant.%d{yyyy-MM-dd HH}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>3MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg %X{requestId}%n
</pattern>
</encoder>
</appender>
<!-- project default level -->
<logger name="com.version" level="DEBUG"/>
<logger name="org.springframework.web.servlet.handler" level="INFO"/>
<logger name="com.example.user.mapper" level="DEBUG"/>
<!--log4jdbc -->
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO"/>
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="rollingFile"/>
</root>
</configuration>注意配置中的{requestId}占位符,這個(gè)就會(huì)替換為生成的唯一日志ID。
四、返回值封裝
- ResponseModel.java
public class ResponseModel implements Serializable {
private static final long serialVersionUID = -8972819161141262263L;
@ApiModelProperty(value = "是否處理成功", name = "success", example = "true")
private Boolean success;
@ApiModelProperty(value = "返回碼", name = "code", example = "200")
private Integer code;
@ApiModelProperty(value = "處理消息", name = "msg", example = "處理成功")
private String msg;
@ApiModelProperty(value = "返回?cái)?shù)據(jù)", name = "data", example = "{}")
private Object data;
private String requestId = MDC.get("requestId");
}代碼寫(xiě)完了,前端每次請(qǐng)求,如果有返回值的話(huà),都會(huì)收到唯一日志ID,如圖:

可以根據(jù)requestId,通過(guò)此命令在日志文件中查找對(duì)應(yīng)的日志
cat common-user.log | grep -C 10 f11819ea-6169-4c13-8032-979a88977575

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Java基于logback?MessageConverter實(shí)現(xiàn)日志脫敏方案分析
- idea項(xiàng)目啟動(dòng)報(bào)錯(cuò),日志包沖突slf4j和logback沖突問(wèn)題
- SpringBoot整合日志功能(slf4j+logback)詳解(最新推薦)
- springboot項(xiàng)目配置logback-spring.xml實(shí)現(xiàn)按日期歸檔日志的方法
- SpringBoot3配置Logback日志滾動(dòng)文件的方法
- 如何為?Spring?Boot?項(xiàng)目配置?Logback?日志
- 解決logback使用${spring.application.name}日志打印路徑的問(wèn)題
相關(guān)文章
如何查找YUM安裝的JAVA_HOME環(huán)境變量詳解
這篇文章主要給大家介紹了關(guān)于如何查找YUM安裝的JAVA_HOME環(huán)境變量的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
淺談Java中的final關(guān)鍵字與C#中的const, readonly關(guān)鍵字
下面小編就為大家?guī)?lái)一篇淺談Java中的final關(guān)鍵字與C#中的const, readonly關(guān)鍵字。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
java selenium教程環(huán)境搭建基于Maven
本文主要介紹Java selenium 環(huán)境的安裝,這里介紹了基于Maven的環(huán)境搭建,有需要的小伙伴可以參考下2016-08-08
Spring中Bean初始化和銷(xiāo)毀的方式總結(jié)
這篇文章主要為大家整理了Spring中Bean初始化和銷(xiāo)毀的多種方式,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下2023-04-04
Java工廠模式用法之如何動(dòng)態(tài)選擇對(duì)象詳解
工廠設(shè)計(jì)模式可能是最常用的設(shè)計(jì)模式之一,我想大家在自己的項(xiàng)目中都用到過(guò)。本文不僅僅是關(guān)于工廠模式的基本知識(shí),更是討論如何在運(yùn)行時(shí)動(dòng)態(tài)選擇不同的方法進(jìn)行執(zhí)行,你們可以看看是不是和你們項(xiàng)目中用的一樣2023-03-03
深入淺析 Spring Security 緩存請(qǐng)求問(wèn)題
這篇文章主要介紹了 Spring Security 緩存請(qǐng)求問(wèn)題,本文通過(guò)實(shí)例文字相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-04-04
java文件操作代碼片斷實(shí)例實(shí)現(xiàn)統(tǒng)計(jì)文件中字母出現(xiàn)的個(gè)數(shù)功能
本文介紹java讀文件實(shí)例,實(shí)現(xiàn)統(tǒng)計(jì)某一目錄下每個(gè)文件中出現(xiàn)的字母?jìng)€(gè)數(shù)、數(shù)字個(gè)數(shù)、空格個(gè)數(shù)及行數(shù),除此之外沒(méi)有其他字符,大家參考使用吧2014-01-01

