SLF4J MDC ☞ 將使用者資訊新增到日誌資訊中
你是否有過排查某個使用者的操作出現 BUG 時, 從茫茫日誌中尋找這個使用者操作的痛苦經歷, SLF4J 為我們提供了一種基於 ThreadLocal
來實現的 MDC
功能, 用來將自定義資訊放入到日誌中.
你可能沒太明白啥意思, 那麼先來看看效果把:
普通日誌:

加上MDC的日誌:

食用方式
可以使用過濾器, 攔截器或 AOP 等方式來實現, 即在使用者請求時, 將使用者資訊寫入到 MDC
中, 然後在請求完成後, 清空此 MDC.
我這裡使用 SpringMVC 的攔截器 HandlerInterceptor
來演示下, (我這裡使用了 Shiro, 所以會呼叫 Shiro 的程式碼來獲取當前登入使用者):
@Component public class LogInterceptor implements HandlerInterceptor { private final static String MDC_USERNAME = "username"; private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { // 如已進行登入, 則獲取當前登入者的使用者名稱放入 MDC 中. String username = ""; if (SecurityUtils.getSubject().getPrincipal() != null) { username = ((User) SecurityUtils.getSubject().getPrincipal()).getUsername(); } MDC.put(MDC_USERNAME, username); LOGGER.debug("MDC : PUT MDC_USERNAME ({}) in logger", username); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { String username = MDC.get(MDC_USERNAME); LOGGER.debug("MDC : remove MDC_USERNAME ({}) from logger", username); MDC.remove(username); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
再將其配置到 Spring 攔截器中:
@Configuration public class WebMvcConfigurer extends WebMvcConfigurerAdapter { @Autowired private LogInterceptor logInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(logInterceptor); super.addInterceptors(registry); } }
然後在日誌格式中使用 %X{username}
將 MDC 新增進去即可, 由於我使用的是 SpringBoot 的 logback
, 所以在保留原 SpringBoot 預設格式的同時, 加上了 MDC:
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} [%10.10X{username}] %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}