spring cloud脚手架项目(十三)Fegin微服务应用之间请求追踪链路开发

前言

在之前的一篇文章中,我写了一个aop日志打印的功能,通过注解的实现,可以让接口直接打印出入参和出参,并且在日志上添加uuid。因为当服务器的请求很多的时候,会发现日志都挤在一起,自己都不知道这个日志信息对应的调用链路的情况了。
相关文章:spring cloud脚手架项目(五)日志模块之出入参数和日志链路追踪UUID

2 实现效果

上一篇文章的实现效果

[430c8ee7-6d34-4414-8ccc-9042c4cc340c][2020-10-23 22:14:24.948][http-nio-8761-exec-5][INFO ][com.chen.common.logAop.ParamsLog2Aspect]:ClassMethod:com.chen.core.service.impl.CommonServiceImpl.test15,RequestArgs:["111"]
[430c8ee7-6d34-4414-8ccc-9042c4cc340c][2020-10-23 22:14:24.959][http-nio-8761-exec-5][INFO ][c.c.core.service.impl.CommonServiceImpl]:resultTest:{"code":"200","msg":"成功","data":"hello"}
[430c8ee7-6d34-4414-8ccc-9042c4cc340c][2020-10-23 22:14:24.960][http-nio-8761-exec-5][INFO ][com.chen.common.logAop.ParamsLog2Aspect]:ClassMethod:com.chen.core.service.impl.CommonServiceImpl.test15,ResponseArgs:{"code":"200","msg":"成功","data":"success"},Time-Consuming:12ms

应用A代码

	//A应用调用一个B应用远程Feign接口,并且打印出结果值,远程接口很简单,也是一个返回成功的意思
    @ParamsLog2(logTrace=true)
    public Result<String> test15(String name) {
        ResultTest<String> resultTest = chenTestService.test1();
        log.info("resultTest:{}",new Gson().toJson(resultTest));
        return Result.success("success");
    }

被调用的B应用代码

    @Override
    public ResultTest<String> test1() {
        log.info("test1");
        return ResultTest.success("hello");
    }

优化以及改进

那么现在有一个问题。当我们的整个系统是微服务的情况下。我A应用的日志是找到了。但是调用B应用的时候要怎么这个B应用的这个请求就是我这个A应用请求进来的,那么应该怎么办呢?
那么方案就是使用request的head头。在A应用请求进来的时候,产生一个UUID,然后把这个UUID放入head头中再传给B应用。B应用再获得这个head头中的UUID,以此反复。
至于线程中实现打印UUID,使用的是MCD这个功能

4 实现代码

WebConfig

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private LogInterceptor logInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(logInterceptor);
    }
}

LogInterceptor


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@Component
@Slf4j
public class LogInterceptor extends HandlerInterceptorAdapter {
    private static final String HEAD_ID = "HEAD_ID";
    private static final String REQUEST_HEAD_ID = "head_id";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String headId = request.getHeader(REQUEST_HEAD_ID);
        log.info("preHandle before headId:{}",headId);
        if (headId == null) {
            headId = UUID.randomUUID().toString();
            request.setAttribute(REQUEST_HEAD_ID,headId);
        }
        if (StringUtils.isEmpty(MDC.get(HEAD_ID))) {
            MDC.put(HEAD_ID, headId);
        }
        log.info("preHandle after headId:{}",headId);
        return true;
    }
}

FeignTrackInterceptor

import com.google.gson.Gson;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Slf4j
public class FeignTrackInterceptor implements RequestInterceptor {
    private static final String HEAD_ID = "head_id";

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("request:{}", new Gson().toJson(request.getHeader(HEAD_ID)));
        log.info("feign:{}", new Gson().toJson(requestTemplate.header(HEAD_ID)));
        String headId = request.getHeader(HEAD_ID);
        if(headId==null){
            headId = (String)request.getAttribute(HEAD_ID);
        }
        requestTemplate.header(HEAD_ID, headId);
    }
}

FeignSupportConfig

import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *
 **/
@Configuration
public class FeignSupportConfig {
    /**
     * feign请求拦截器
     *
     * @return
     */
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new FeignTrackInterceptor();
    }
}

结果

A应用日志

[][][2020-10-23 22:59:11.594][http-nio-8761-exec-8][INFO ][com.chen.core.interceptor.LogInterceptor]:preHandle before headId:null
[5bb3322c-34ff-4dc2-b605-02bd68b36790][][2020-10-23 22:59:11.594][http-nio-8761-exec-8][INFO ][com.chen.core.interceptor.LogInterceptor]:preHandle after headId:5bb3322c-34ff-4dc2-b605-02bd68b36790
[5bb3322c-34ff-4dc2-b605-02bd68b36790][4176a364-2369-4ef9-83c6-42e979d8cdfd][2020-10-23 22:59:11.595][http-nio-8761-exec-8][INFO ][com.chen.common.logAop.ParamsLog2Aspect]:ClassMethod:com.chen.core.service.impl.CommonServiceImpl.test15,RequestArgs:["222"]
[5bb3322c-34ff-4dc2-b605-02bd68b36790][4176a364-2369-4ef9-83c6-42e979d8cdfd][2020-10-23 22:59:11.595][http-nio-8761-exec-8][INFO ][c.c.c.interceptor.FeignTrackInterceptor]:request:null
[5bb3322c-34ff-4dc2-b605-02bd68b36790][4176a364-2369-4ef9-83c6-42e979d8cdfd][2020-10-23 22:59:11.595][http-nio-8761-exec-8][INFO ][c.c.c.interceptor.FeignTrackInterceptor]:feign:{"queries":{},"headers":{"head_id":[]},"method":"GET","url":"/hi/test1","decodeSlash":true}
[5bb3322c-34ff-4dc2-b605-02bd68b36790][4176a364-2369-4ef9-83c6-42e979d8cdfd][2020-10-23 22:59:11.606][http-nio-8761-exec-8][INFO ][c.c.core.service.impl.CommonServiceImpl]:resultTest:{"code":"200","msg":"成功","data":"hello"}
[5bb3322c-34ff-4dc2-b605-02bd68b36790][4176a364-2369-4ef9-83c6-42e979d8cdfd][2020-10-23 22:59:11.606][http-nio-8761-exec-8][INFO ][com.chen.common.logAop.ParamsLog2Aspect]:ClassMethod:com.chen.core.service.impl.CommonServiceImpl.test15,ResponseArgs:{"code":"200","msg":"成功","data":"success"},Time-Consuming:12ms

B应用日志

[][][2020-10-23 22:59:11.603][http-nio-8762-exec-3][INFO ][com.chen.hi.interceptor.LogInterceptor]:preHandle before headId:5bb3322c-34ff-4dc2-b605-02bd68b36790
[5bb3322c-34ff-4dc2-b605-02bd68b36790][][2020-10-23 22:59:11.603][http-nio-8762-exec-3][INFO ][com.chen.hi.interceptor.LogInterceptor]:preHandle after headId:5bb3322c-34ff-4dc2-b605-02bd68b36790
[5bb3322c-34ff-4dc2-b605-02bd68b36790][][2020-10-23 22:59:11.603][http-nio-8762-exec-3][INFO ][c.c.hi.service.impl.ChenTestService2Impl]:test1

至于请求还是上面的实现代码。
可以看到A应用产生了一个UUID为5bb3322c-34ff-4dc2-b605-02bd68b36790的调用链
然后B应用获得到了A应用产生的这个UUID。

logback配置

MCD相关代码

//MCD设置参数HEAD_ID
MDC.put(HEAD_ID, headId);

logback配置

<property name="FILE_LOG_PATTERN" value="[%X{HEAD_ID}][%X{TRACE_ID}][%d{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger{40}]:%msg%n"/>

%X{HEAD_ID}就是在MCD中传入的参数,然后会在日志格式中打印出来

补充

logback先关配置文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值