惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
小众软件
小众软件
爱范儿
爱范儿
Y
Y Combinator Blog
博客园 - Franky
美团技术团队
博客园 - 【当耐特】
The Cloudflare Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
Jina AI
Jina AI
IT之家
IT之家
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
WordPress大学
WordPress大学
V
Visual Studio Blog
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
有赞技术团队
有赞技术团队

博客园 - Doyourself!

rocketmq 启动后 在mq console界面的consumer的Quantity数量显示为0 问题记录 python 切换版本后 提示 无法在python 3.11(.venv)(D:/my_rag_bot/.venv/Scripts/python.exe)设置 python sdk,该sdk似乎无效 记录一次日志告警随着nacos文件动态刷新而失效的问题 多个WebMvcConfigurer配置Jackson2ObjectMapperBuilder不生效问题记录 自定义拦截器不生效问题记录 记录一次nginx能通但是请求一直不了的问题 idea远程连接并本地打包到远程服务器 记一次生产环境内存溢出记录 凤凰架构总结 sentinel接入记录 JVM虚拟机总结 记录一次首页优化的经历 使用sharding-jdbc做分库分表记录 使用druid自定义拦截器 记录一次 maven 子模块相互依赖导致的父模块无法动态升级的问题 'parent.relativePath' points at wrong local POM 雪花算法snowflakeIdWorker使用记录 Spring Cloud 的ribbon的饥饿加载机制 打印mq异常消息记录 根据druid将慢sql通过钉钉的方式进行告警功能记录
全局调用链路traceId网关到业务层、feign调用统一问题记录
Doyourself! · 2023-08-28 · via 博客园 - Doyourself!

              项目里面使用的traceId是基于skywalking进行打印的,但是实际使用的过程中发现网关处的traceId为空,而且feign调用其他服务时候的traceId 都不一样。 显示如下:

              网关traceId为空:

 基于此,想要把项目里面的以及feign调用的traceId统一成一样的,且在网关显示一样。

 首先是需要在日志设置打印traceId的格式:以logback-spring.xml为例

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %tid [%-5level] [%thread] [%logger{15}:%line] %X{traceId} --- %msg%n</pattern>
            </layout>
        </encoder>
    </appender>

  %X{traceId} 即为显示的traceId

 其次是在网关出需要优先把traceId进行打印显示:

            String traceId = StringUtils.isEmpty(exchange.getRequest().getHeaders().getFirst(TraceUtils.TRACE_ID))?TraceUtils.createTraceId():
                    exchange.getRequest().getHeaders().getFirst(TraceUtils.TRACE_ID);
            logger.info("当前request traceId:" + traceId);
public class TraceUtils {
    public static final String TRACE_ID = "traceId";

    public static synchronized String createTraceId() {
        String traceId = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
        MDC.put(TRACE_ID, traceId);
        return traceId;
    }

    public static void destroyTraceId() {
        MDC.remove(TRACE_ID);
        MDC.clear();
    }


}

注意的是:如果在网关处有其他的业务日志,需要优先把traceId创建出来。否则使用的是默认的16位traceId.我自己在开发和测试环境测试发现,如果把traceId写在业务日志后面,显示的是16位的且和我本地不同的traceId.

feign时候需要通过request.getHeader("traceId")获取,且需要在网关处把生成的traceId放入header里面。大概的代码如下:

ServerHttpRequest request = exchange.getRequest().mutate()
                    .header(Constant.H_KEY_DEVICE_ID, deviceId)
                    .header(Constant.H_KEY_APP_ID, appId)
                    .header(Constant.H_KEY_BRAND, sourceApp)
                    .header(Constant.H_KEY_BRAND, sourceApp)
                    .header(Constant.H_KEY_IP, ip)
                    .header(Constant.H_URL, exchange.getRequest().getURI().toString())
                    .header(Constant.H_KEY_REQ_FROM,"outside")
                    .header(TraceUtils.TRACE_ID,traceId)
                    .build();
/**
 * FeignClient调用服务时添加广告主信息请求头
 *
 */
public class FeignAddHeadersRequestInterceptor implements RequestInterceptor {
    /**
     * 日志定义
     */
    private static final Logger LOG = LoggerFactory.getLogger(FeignAddHeadersRequestInterceptor.class);
    /**
     * 请求头名称
     */
    private static final String X_CLIENT_USER = "x-client-user";
    private static final String AUTHORIZATION = "Authorization";

    private static final String SOURCEAPP = "SourceApp";

    private static final String SOURCEAPPEGNORE= "sourceApp";
    private static final String TRACE_ID = "traceId";

    private static final String SOURCE_APP_VER = "SourceAppVer";

    private static final String SOURCE_APP_VER_IGNORE = "sourceappver";


    @Override
    public void apply(RequestTemplate template) {
        LOG.info("feign add header begin");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        String header = request.getHeader(AUTHORIZATION);
        String traceId = request.getHeader(TRACE_ID);
        String sourceApp = request.getHeader(SOURCEAPP);
        String sourceAppVer = request.getHeader(SOURCE_APP_VER);
        if (header != null) {
            // 添加请求头
            template.header(AUTHORIZATION, header);
            LOG.info("feign add header done");
        }
        if(Objects.nonNull(sourceApp)){
            template.header(SOURCEAPP, sourceApp);
            LOG.info("feign souceApp done");
        }else {
            String sourceAppIgnore = request.getHeader(SOURCEAPPEGNORE);
            if(Objects.nonNull(sourceAppIgnore)){
                template.header(SOURCEAPPEGNORE,sourceAppIgnore);
                LOG.info("fein SOURCEAPPEGNORE done");
            }
        }
        if(Objects.isNull(traceId)){
            traceId = Optional.ofNullable(request.getAttribute(TRACE_ID)).map(t->t.toString()).orElse(null);
            LOG.info("current traceId:" + traceId);
        }
        if(Objects.nonNull(traceId)){
            //添加traceId
            template.header(TRACE_ID,traceId);
            MDC.put(TRACE_ID,traceId);
            LOG.info("request traceId:" + traceId);
        }
        if(Objects.nonNull(sourceAppVer)){
            template.header(BaseCommon.SOURCE_APP_VER,sourceAppVer);
        }else{
            String sourceAppVerIgnore = request.getHeader(SOURCE_APP_VER_IGNORE);
            if(Objects.nonNull(sourceAppVerIgnore)){
                template.header(BaseCommon.SOURCE_APP_VER,sourceAppVerIgnore);
                LOG.info("feign add sourceAppVerIgnore ");
            }
        }

    }
}

通过实现RequestInterceptor接口的apply方法,把feign调用的traceId给打通。大概思路是这样。这样打通后,一个完整的请求的traceId即可打通。

网关:

业务层:feign调用显示也和网关的都一样的了