本文為博主原創,未經允許不得轉載:
在開發過程中,經常會使用log記錄一下當前請求的參數,過程和結果,以便幫助定位問題。在並發量下的情況下,日志打印不會劇增,可以很快就能通過打印的日志查看執行的情況。但是在高並發大量請求的場景下,日志也會頻繁打印,刷新,通過查看日志來定位問題時就會變得很難,因為無法確定打印的日志是哪一條請求時打印的,從而影響問題的定位速度。
一種輕量級的實現,通過 MDC 機制,將請求的 trace-id 放入到MDC中,在日志打印時,通過 MDC 中的 trace-id 將同一個請求的每一條日志串聯起來。因為 MDC 是線程隔離且安全的。
logback MDC 實現日志追蹤實現:
1. 在請求剛到達網關層時,添加一個過濾器,每個請求在過濾器時,在 logback 的MDC 中放入 trace-id。
import com.baomidou.mybatisplus.core.toolkit.IdWorker; import org.slf4j.MDC; import javax.servlet.*; import java.io.IOException; public class LogFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 使用雪花算法生成一個請求Id String traceId = Long.toString(IdWorker.getId()); MDC.put("trace-id",traceId); } }
2. 在logback.xml 中配置 log 打印格式,並打印 trace-id
<!-- 控制台輸出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 輸出日志記錄格式,並打印 trace-id -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%trace-id] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
logback 中也可以使用占位符%X{ }來占位,替換到對應的 MDC 中 key 的值
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout>
<Pattern>%X{trace-id}- %m%n</Pattern>
</layout>
</appender>
3. logback mdc實現原理
logback的實現類LogbackMDCAdapter利用的ThreadLocal技術保證了每個請求線程保有自己的MDC環境變量。其使用了裝飾者模式。
MDCAdapter有三個實現類,BasicMDCAdapter、LogbackMDCAdapter,NOPMDCAdapter。Logback使用的是LogbackMDCAdapter。
LogbackMDCAdapter 中使用的時 ThreadLocal 進行線程隔離實現的。
附:在日志打印優化以及方便日志定位的過程中,也可以使用 AOP,對 controller ,service 等進行統一打印,打印每一個方法的調用請求參數,開始時間,結束時間,耗時等。這會大大提高日志的價值。