架构&系统设计0.面试技能gateway

利用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

上一篇下一篇

猜你喜欢

热点阅读