几行代码轻松搞定跨系统传递 traceId
同样是新项目开发的笔记,因为使用的是分布式架构,涉及到各个系统之间的交互
这时候就会遇到一个很常见的问题:
- 单个系统是集群部署,日志分布在多台服务器上;
- 多个系统的日志在多台机器,但是一次请求,查日志更是难上加难。
解决方案
- 使用 SkyWalking traceid 进行链路追踪;
- 使用 Elastic APM 的 trace.id 进行链路追踪;
- 自己生成 traceId 并 put 到 MDC 里面。
2
MDC
MDC(Mapped Diagnostic Context)是一个映射,用于存储运行上下文的特定线程的上下文数据。因此,如果使用log4j进行日志记录,则每个线程都可以拥有自己的MDC,该MDC对整个线程是全局的。属于该线程的任何代码都可以轻松访问线程的MDC中存在的值。
如何使用 MDC
- 在 log4j2-spring.xml 的日志格式中添加 %X{traceId} 配置。
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%X{traceId}]-[%-5level]-[%c{36}:%L]-[%m]%n
</Property>
<Property name="LOG_PATTERN_ERROR">[%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%X{traceId}]-[%-5level]-[%l:%M]-[%m]%n
</Property><!-- 省略 --><!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT" follow="true"><!--输出日志的格式--><PatternLayout charset="UTF-8" pattern="${LOG_PATTERN}"/>
</Console>
- 新增拦截器
拦截所有请求,从 header 中获取 traceId 然后放到 MDC 中,如果没有获取到,则直接用 UUID 生成一个。
@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {private static final String TRACE_ID = "traceId";@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3) throws Exception {}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView arg3) throws Exception {}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String traceId = request.getHeader(TRACE_ID);if (StringUtils.isEmpty(traceId)) {MDC.put(TRACE_ID, UUID.randomUUID().toString());} else {MDC.put(TRACE_ID, traceId);}return true;}}
- 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Resourceprivate LogInterceptor logInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(logInterceptor).addPathPatterns("/**");}
}
跨服务之间如何传递 traceId
- FeignClient
因为这边使用的是 FeignClient 进行服务之间的调用,只需要新增请求拦截器即可
@Configuration
public class FeignInterceptor implements RequestInterceptor {private static final String TRACE_ID = "traceId";@Overridepublic void apply(RequestTemplate requestTemplate) {requestTemplate.header(TRACE_ID, MDC.get(TRACE_ID));}
}
- Dubbo
如果是 Dubbo 可以通过扩展 Filter 的方式传递 traceId
- 编写 filter
@Activate(group = {"provider", "consumer"})
public class TraceIdFilter implements Filter {@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {RpcContext rpcContext = RpcContext.getContext();String traceId;if (rpcContext.isConsumerSide()) {traceId = MDC.get("traceId");if (traceId == null) {traceId = UUID.randomUUID().toString();}rpcContext.setAttachment("traceId", traceId);}if (rpcContext.isProviderSide()) {traceId = rpcContext.getAttachment("traceId");MDC.put("traceId", traceId);}return invoker.invoke(invocation);}
}
- 指定 filter
src|-main|-java|-com|-xxx|-XxxFilter.java (实现Filter接口)|-resources|-META-INF|-dubbo|-org.apache.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter)
截图如下:
测试结果如下:
" dubbo filter 相关源码地址在文末,也可以关注公众号,发送 traceid 获取。 "
其他方式
当然如果小伙伴们有使用 SkyWalking 或者 Elastic APM 也可以通过以下方式进行注入:
- SkyWalking
<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-log4j-2.x</artifactId><version>{project.release.version}</version>
</dependency
然后将 [%traceId] 配置在 log4j2.xml 文件的 pattern 中即可
- Elastic APM
- 在启动时指定 enable_log_correlation 为 true
- 将 %X{trace.id} 配置在 log4j2.xml 文件的 pattern 中
3
扩展
统一日志采集
虽然有了 traceId 可以进行全链路追踪查询日志,但是毕竟也是在多台服务器上,为了提高查询效率,可以考虑将日志汇总到一起。
常用的使用方法就是基于 ELK 的日志系统:
- 使用 filebeat 采集日志报送到 logstash
- logstash 进行分词过滤等处理,输出到 Elasticsearch
- 使用 Kinbana 或者自己开发的可视化工具从 Elasticsearch 查询日志
结束语
本文主要记录近期开发过程中的遇到的一点问题,希望对小伙伴也有所帮助。不足之处,欢迎指正。如果小伙伴有其他的建议或者观点欢迎留言讨论,共同进步。
几行代码轻松搞定跨系统传递 traceId相关推荐
- html 简繁文件转换器,几行代码轻松搞定网页的简繁转换
几行代码轻松搞定网页的简繁转换以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 对网页进行简繁字体转换的方法一般有两种 ...
- 几行代码轻松搞定网页的简繁转换
对网页进行简繁字体转换的方法一般有两种:一是使用<简繁通>这样的专业软件,另外一种是制作两套版本的网页.显然,这两种方法都较为麻烦,而且专业软件一般不能用于免费的空间.笔者在这里给 ...
- 几行代码轻松搞定网页的简繁转换(转载)
对网页进行简繁字体转换的方法一般有两种:一是使用<简繁通>这样的专业软件,另外一种是制作两套版本的网页.显然,这两种方法都较为麻烦,而且专业软件一般不能用于免费的空间.笔者在这里给大家提供 ...
- 精选10个Python库,几行代码轻松搞定探索性数据分析!
点击上方"菜鸟学Python",选择"星标"公众号 超级无敌干货,第一时间送达!!! 探索性数据分析是数据科学模型开发和数据集研究的重要组成部分之一.在拿到一个 ...
- 机器学习建模神器PyCaret已开源!提升效率,几行代码轻松搞定模型
Datawhale干货 编译:张峰,Datawhale成员 寄语:PyCaret,是一款 Python中的开源低代码(low-code)机器学习库,支持在「低代码」环境中训练和部署有监督以及无监督的机 ...
- html自动给图片加上水印 代码_如何给一千张图片去水印?还好我会python,100行代码轻松搞定...
写在前面 近期好多网友私信我,问我编程该怎么学习.怎么入门.我觉得编程学习,就像写文章一样,需要积累. 如果把代码每个字符拆开,大伙都认识,但是组合在一起,就是另外一回事了.所以我的建议是,学习编程, ...
- 几行代码轻松搞定网页简繁转换
首先在 http://www.chinahtml.com/d/file/programming/3/transform.js处下载用于简繁转换的js文件transform.js,复制到网站目录下,然后 ...
- android 蓝牙耗电量,安卓Android BLE低功耗蓝牙接受数据详解 只需100行代码轻松搞定...
做了一个安卓手机通过蓝牙获取电子秤的重量的Demo,在此写下以供大家参考和讨论. 先上代码,着急用的可以迅速参考,后面再写说明 我跳过了扫描过程,直接根据蓝牙设备地址进行连接,可以运行官方Demo来获 ...
- jquery练习03_手写扫雷(全网最强jquery练习),扫雷游戏 150行代码轻松搞定
5 扫雷 5.1 扫雷规则 展示信息:总雷数 剩余雷数(总雷数-插旗数) 用时 规格:难度增加=雷数增加+类概率增加: 10% 15% 20% 状态:被点击(触雷+周围0雷+周围n雷+插旗)+未点击 ...
最新文章
- synchronized底层原理_你用过synchronized吗?它的底层原理是什么?Java经典面试题来了...
- 原创 | 常见损失函数和评价指标总结(附公式代码)
- python pip 错误 ModuleNotFoundError: No module named pip._internal 解决办法
- TCP/IP 知识点问答(三)
- ssh 用密码连接不上、查看openSSH 的版本、CentOS - 升级openSSH,修复安全漏洞
- [云炬创业管理笔记]第6章制定创业行动测试5
- 从考勤管理需求说起,聊聊场景的思维“工具”
- 三星GalaxyNote20系列全新渲染图曝光:屏下摄像头来了?
- python多进程卡死_Python 多进程中使用logging导致死锁
- jsp+左间距_DIV间距设置
- android ogg 播放器,android如何让自己开发的播放器成为可供文件选择的播放器
- SharePoint 模拟审批Nintex工作流
- asterisk sip服务器搭建与配置
- 麦子学院项目-懒人天气App思维导图、素材下载
- 千万别活成自己最讨厌的样子
- 【MFC】MFC修改菜单名后不更新问题
- 数组结构与算法-036-042 前中后缀表达式-逆波兰计算器
- SQL之case when then用法(用于分类统计)
- 怎样搭建后缀是.gitee.io的网站?如何免费在码云Gitee中部署个人静态网站?(或者个人博客)如何建立免费网站?
- h5开发常用颜色书写汇总
热门文章
- java将csv导入hdfs_把HDFS里的json数据转换成csv格式
- rust电器元件需要什么材料_腐蚀Rust电力系统有哪些工具 腐蚀Rust电力系统工具汇总 其他工具-游侠网...
- Spring boot上传文件(图片)到阿里云OSS(直接上传到应用服务器)
- java gui介绍_IntelliJ IDE 开发Java GUI 入门
- -e mysql_root_password 无效_43万的价格,53万的面子!宝马5系对比奔驰E级
- mysql 中文 3个字节_mysql 字节问题,中文和数字
- 蜘蛛日志分析工具_如何分析蜘蛛日志?
- SSM整合 mybatis多条件查询与分页
- Easyui Datagrid的Rownumber行号显示问题
- ubuntu下nginx安装