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

推荐订阅源

有赞技术团队
有赞技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
C
Cisco Blogs
The Hacker News
The Hacker News
T
Threatpost
S
Schneier on Security
K
Kaspersky official blog
Spread Privacy
Spread Privacy
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
Security Latest
Security Latest
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
博客园 - 叶小钗
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News and Events Feed by Topic
爱范儿
爱范儿
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
T
Tenable Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
博客园 - 三生石上(FineUI控件)
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News and Events Feed by Topic
V
V2EX
Webroot Blog
Webroot Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
Scott Helme
Scott Helme
Simon Willison's Weblog
Simon Willison's Weblog
L
LangChain Blog
W
WeLiveSecurity
Cloudbric
Cloudbric

博客园 - 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调用显示也和网关的都一样的了