dubbo项目traceId链路传递(MDC方案及重复traceId处理)

1.traceId用途

        主要用于项目dubbo接口调用链日志追踪使用,可以获取完整的链路日志,协助排查问题。

2.traceId传递及代码实现

        本方案是基于 org.slf4j.MDC 进行实现,会出现线程池中线程复用导致traceId重复问题,后面会说解决方案。

  • web项目(CONSUMER)

    • com.alibaba.dubbo.rpc.Filter 文件,路径在src\main\resources\META-INF\dubbo目录下面,文件内容就是对应项目中指定的过滤器类路径
      • globalTraceFilter=com.xxx.filter.GlobalTraceFilter

  • GlobalTraceFilter类里面代码如下,实现dubbo的Filter接口:

    package com.xxx.filter;import lombok.extern.slf4j.Slf4j;
    import org.apache.dubbo.common.constants.CommonConstants;
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.*;
    import org.slf4j.MDC;import java.util.UUID;/*** @Description 过滤器传递tradeId(消费者)* @Version v1.0*/
    @Activate(group = {CommonConstants.CONSUMER})
    @Slf4j
    public class GlobalTraceFilter implements Filter {private static final String TRACE_ID = "TraceId";@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {RpcContext rpcContext = RpcContext.getContext();String traceId;if (rpcContext.isConsumerSide()) {traceId = MDC.get(TRACE_ID);if (traceId == null) {traceId = UUID.randomUUID().toString().replace("-", "");}MDC.put(TRACE_ID, traceId);rpcContext.setAttachment(TRACE_ID, traceId);}return invoker.invoke(invocation);}
    }
    
  • logback-spring.xml配置
     

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration><include resource="org/springframework/boot/logging/logback/defaults.xml" /><springProperty scope="context" name="PORT" source="server.port" default = ""/><property name="log_dir" value="/data/logs/sso/${PORT}" /><property name="default_log" value="${log_dir}/xxx-web"/><property name="error_log" value="${log_dir}/xxx-web-error"/><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder charset="UTF-8"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS},[%X{TraceId}] [%thread] %highlight(%-5level) %cyan(%logger{15}) - %highlight(%msg) %n%exception</pattern></encoder></appender><!-- 默认日志 按日切分 --><appender name="default" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${default_log}</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${default_log}.%d{yyyy-MM-dd}</fileNamePattern><maxHistory>60</maxHistory><totalSizeCap>50GB</totalSizeCap></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS},[%X{TraceId}] [%thread] %-5level %logger{36} %method:%L - %msg %n</pattern></encoder></appender><!-- ERROR --><appender name="common-error" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${error_log}</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${error_log}.%d{yyyy-MM-dd}</fileNamePattern><maxHistory>60</maxHistory><totalSizeCap>10GB</totalSizeCap></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS},[%X{TraceId}] [%thread] %-5level %logger{36} %method:%L - %msg%n%exception</pattern></encoder><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><logger name="com.xxx" level="DEBUG"/><!-- ROOT --><root level="INFO"><appender-ref ref="default"/><appender-ref ref="common-error"/><appender-ref ref="console"/></root></configuration>
    • api项目(CONSUMER&PROVIDER)

      • com.alibaba.dubbo.rpc.Filter 文件,路径在src\main\resources\META-INF\dubbo目录下面,文件内容就是对应项目中指定的过滤器类路径
        • globalTraceFilter=com.xxx.filter.GlobalTraceFilter

  • GlobalTraceFilter类里面代码如下,实现dubbo的Filter接口:
     

    package com.xxx.filter;import org.apache.dubbo.common.constants.CommonConstants;
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.*;
    import org.slf4j.MDC;import java.util.UUID;/*** @Description 过滤器传递tradeId(消费者和生产者)* @Version v1.0*/
    @Activate(group = {CommonConstants.CONSUMER, CommonConstants.PROVIDER})
    public class GlobalTraceFilter implements Filter {private static final String TRACE_ID = "TraceId";@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {RpcContext rpcContext = RpcContext.getContext();String traceId;if (rpcContext.isConsumerSide()) {traceId = MDC.get(TRACE_ID);if (traceId == null) {traceId = UUID.randomUUID().toString();}rpcContext.setAttachment(TRACE_ID, traceId);}else if (rpcContext.isProviderSide()) {traceId = rpcContext.getAttachment(TRACE_ID);if (traceId == null) {traceId = UUID.randomUUID().toString();}MDC.put(TRACE_ID, traceId);}return invoker.invoke(invocation);}
    }

  • logback-spring.xml配置和上面一样

3.traceId重复的处理

通过AOP进行处理,controller方法执行完后清除MDC,避免日志线程池中的线程复用导致MDC中traceId还存在则不会生成新的traceId;

web项目中RequestTraceIdAspect类代码如下:

package com.xxx.aspectj;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;/*** @Description* @Create 2023/8/31*/
@Aspect
@Component
public class RequestTraceIdAspect {@After("execution(public * com.xxx.controller..*.*(..)) && !execution(* com.xxx.controller.BaseController.*(..))")public void afterRequest() {// 在请求结束时执行的逻辑,清空MDC中的TraceId,避免线程池中因线程复用导致上次请求的TraceId在后续请求中重复使用MDC.clear();}
}

特别说明一下 !execution(* com.xxx.controller.BaseController.*(..))排查BaseController中的方法,因为这里项目中Controller有继承BaseController做通用处理,会先调用里面的方法,如果在里面就清空了MDC,再到对应Controller执行真正业务逻辑的时候就没有traceId了;如果没有这种继承关系就不需要这段了

4.mybatis日志未记录到日志中的处理

现象如下图,api项目中sql日志并未显示traceId

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis日志标准输出改为如下通过slf4j的日志实现输出即可
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl

希望能帮到各位小伙伴哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/114089.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

头歌MYSQL——课后作业1 数据库和数据表的建立、修改和删除

第1关&#xff1a;建立数据库 任务描述 本关任务&#xff1a;建立数据库 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 如何创建数据库&#xff0c;显示已经建立的数据库 相关知识 创建数据库 创建数据库是在系统磁盘上划分一块区域用于数据的存储和管理。 命令格…

应用TortoiseSVN的SubWCRev管理VisualStudio C#项目编译版本号

首先要安装 TortoiseSVN, 并确保TortoiseSVN的bin目录被加入到系统环境变量Path中。 1、拷贝Porperties目录下的文件AssemblyInfo.cs生成副本AssemblyInfo.template, 作为版本管理的模板文件。 2、修改模板文件中的想要管理的版本号信息 // [assembly: AssemblyVersion(&quo…

使用spring自带的发布订阅来实现发布订阅

背景 公司的项目以前代码里面有存在使用spring自带发布订阅的代码&#xff0c;因此稍微学习一下如何使用&#xff0c;并了解一下这种实现方式的优缺点。 优点 实现方便&#xff0c;代码方面基本只需要定义消息体和消费者&#xff0c;适用于小型应用程序。不依赖外部中间件&a…

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第一节、二节:图像描述概述和特征点

文章目录 一&#xff1a;图像描述概述&#xff08;1&#xff09;图像描述&#xff08;2&#xff09;描述子 二&#xff1a;特征点&#xff08;1&#xff09;Moravec角点检测A&#xff1a;原理B&#xff1a;程序 &#xff08;2&#xff09;Harris角点检测A&#xff1a;原理B&…

尚硅谷宋红康MySQL笔记 14-18

是记录&#xff0c;不会太详细&#xff0c;受本人知识限制会有错误&#xff0c;会有个人的理解在里面 第14章 视图 了解一下&#xff0c;数据库的常见对象 对象描述表(TABLE)表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记…

排序之插入排序

文章目录 前言一、直接插入排序1、基本思想2、直接插入排序的代码实现3、直接插入排序总结 二、希尔排序1、希尔排序基本思想2、希尔排序的代码实现3、希尔排序时间复杂度 前言 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大…

【Vue】vue2预览显示quill富文本内容,vue-quill-editor回显页面,v-html回显富文本内容

文章目录 前言一、下载二、使用步骤1.引入样式2.html代码 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; vue后台框架&#xff0c;若依系统里有一个富文本编辑器&#xff0c;效果如下 在package.json里面查看&#xff0c;发现插件名叫quill 插件的…

基于食肉植物算法优化的BP神经网络(预测应用) - 附代码

基于食肉植物算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于食肉植物算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.食肉植物优化BP神经网络2.1 BP神经网络参数设置2.2 食肉植物算法应用 4.测试结果&#xff1a;5…

【Leetcode】130.被围绕的区域

一、题目 1、题目描述 给你一个 m x n 的矩阵 board ,由若干字符 X 和 O ,找到所有被 X 围绕的区域,并将这些区域里所有的 O 用 X 填充。 示例1: 输入:board = [[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”],[“X”,“X”,“O”,“X”],[“X”,“O”,“X”,“…

海外ios应用商店优化排名因素之视频预览与截图

当我们找到感兴趣的应用程序并转到该应用程序的页面时&#xff0c;首先引起注意的是预览视频。视频旨在以更具吸引力的方式展示应用程序的用户体验和UI。视频长度最多为30秒&#xff0c;其中前5秒最为重要&#xff0c;一定要让它尽可能引人注目。 1、关于优化预览视频的提示。…

【C语言】循环语句详解

✨个人主页&#xff1a; Anmia.&#x1f389;所属专栏&#xff1a; C Language &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 目录 1.什么是循环结构&#xff1f; 2.while循环 while流程图 while语句中的break和continue break continue 3.for循环 for流…

进程Start

Linux中的命令解释器和Windows的程序管理器explorer.exe一样地位,都是在用户态下运行的进程 共享变量发生不同进程间的指令交错&#xff0c;就可能会数据出错 进程只作为除CPU之外系统资源的分配单位 CPU的分配单位是线程 每个进程都有自己的独立用户空间 内核空间是OS内核的…

PyCharm切换虚拟环境

PyCharm切换虚拟环境 为了满足不同任务需要不同版本的包&#xff0c;可以在Anaconda或者Miniconda创建多个虚拟环境文件夹&#xff0c;并在PyCharm下切换虚拟环境。 解决方案 1、打开Ananconda Prompt 2、创建自己的虚拟环境 格式&#xff1a;conda create -n 虚拟环境名字…

PSP - 蛋白质结构预测 OpenFold Multimer 模型训练参数与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132575709 OpenFold Multimer 是用于预测蛋白质多聚体结构的计算方法。基于OpenFold 的单体预测框架&#xff0c;利用深度学习技术&#xff0c;结…

dayjs格式转换成日期

目录 方法一&#xff1a; ​编辑方法二&#xff1a; 这个项目在筛选订单时间的时候是由前端进行筛选的&#xff0c;用的是adt-design-pro进行二开的&#xff0c;其中在用日期组件的时候遇到了一个问题&#xff0c;组件返回的是&#xff1a; 但是我需要的是年-月-日&#xff…

java八股文面试[数据库]——MySql聚簇索引和非聚簇索引区别

聚集索引和非聚集索引 聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。 1、聚集索引 聚集索引表记录的排列顺序和索引的排列顺序一致&#xff08;以InnoDB聚集索引的主键索引来说&#xff0c;叶子节点中存储的就是行数据&#xff0c;行数据在…

LeetCode 面试题 02.04. 分割链表

文章目录 一、题目二、C# 题解 一、题目 给你一个链表的头节点 head 和一个特定值 x&#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你不需要 保留 每个分区中各节点的初始相对位置。 点击此处跳转题目。 示例 1&#…

c# 本地化中英文切换

区域 线程默认区域为当前计算机所选区域 设置当前区域&#xff1a; Thread.CurrentThread.CurrentCulture new CultureInfo(“zh-cn”); 获取当前区域&#xff1a; Console.WriteLine(Thread.CurrentThread.CurrentCulture.ToString()); 区域名称&#xff1a; “zh-cn” 中文…

Spooling的原理

脱机技术 程序猿先用纸带机把自己的程序数据输入到磁带中&#xff0c;这个输入的过程是由一台专门的外围控制机实现的。之后CPU直接从快速的磁带中读取想要的这些输入数据。输出也类似。 假脱机技术&#xff08;Spooling技术&#xff09; 即用软件的方式来模拟脱机技术。要…

python爬虫14:总结

python爬虫14&#xff1a;总结 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…