利用Slf4j的MDC跟踪方法调用链
2020-04-13 本文已影响0人
archerdu
原文链接:https://blog.csdn.net/xxssyyyyssxx/article/details/81135383
在log-pattern中增加 %X{METHOD-INVOKE-KEY}
在入口方法或者拦截器中增加
MDC.put("METHOD-INVOKE-KEY", logId);
和
MDC.remove("METHOD-INVOKE-KEY");
就可以实现方法调用链的日志使用同一个logId来标识,方便在日志中查找方法调用链。
package interceptor;
import org.slf4j.MDC;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
/**
* 日志处理拦截器
*
* @author duxuefu
* @since 2020-04-14
*/
public class LogInterceptor extends HandlerInterceptorAdapter {
public final static String METHOD_INVOKE_KEY = "METHOD-INVOKE-KEY";
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o) throws Exception {
MDC.put(METHOD_INVOKE_KEY, UUID.randomUUID().toString());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
MDC.remove(METHOD_INVOKE_KEY);
super.afterCompletion(request, response, handler, ex);
}
}
切面方法
package aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* 类日志切面
*
* @author duxuefu
* @since 2020-11-18
*/
@Aspect
@Component
public class LogAspect {
public final static String METHOD_INVOKE_KEY = "METHOD-INVOKE-KEY";
/**
* Pointcut 切入点
* 匹配cn.controller包下面的所有方法
*/
@Pointcut("execution(public * com..*Controller.*(..))")
public void webLog() {
}
/**
* 方法执行前
*/
@Before(value = "webLog()")
public void before(JoinPoint joinPoint) {
MDC.put(METHOD_INVOKE_KEY, UUID.randomUUID().toString());
}
/**
* 方法执行结束,不管是抛出异常或者正常退出都会执行
*/
@After(value = "webLog()")
public void after(JoinPoint joinPoint) {
MDC.remove(METHOD_INVOKE_KEY);
}
}
logback-spring.xml 中的配置,主要关注%X{METHOD-INVOKE-KEY}部分
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{METHOD-INVOKE-KEY} %-5level %logger{50}[%line] - %msg%n</pattern>
</encoder>
package handler;
import interceptor.LogInterceptor;
import org.slf4j.MDC;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 返回对象处理
*
* @author duxuefu
* @since 2020-04-14
*/
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, org.springframework.http.server.ServerHttpRequest serverHttpRequest, org.springframework.http.server.ServerHttpResponse serverHttpResponse) {
// TODO BasicResult是业务实现中的基础返回对象,可以自己实现,统一返回业务标识:sn
if (o instanceof BasicResult) {
((BasicResult) o).setSn(MDC.get(LogInterceptor.METHOD_INVOKE_KEY));
}
return o;
}
}
详细方法参考:
原文链接:https://blog.csdn.net/xxssyyyyssxx/article/details/81135383