5. 分布式链路追踪TracingFilter改造增强设计
前言
在4. 分布式链路追踪客户端工具包Starter设计一文中,我们实现了基础的Starter包,里面提供了我们自己定义的Servlet过滤器和RestTemplate拦截器,其中Servlet过滤器叫做HoneyTracingFilter,仅提供了提取SpanContext,创建Span和开启Span的基础功能,所以本文将围绕如何增强Servlet过滤器展开讨论。
相关版本依赖如下。
opentracing-api版本:0.33.0
opentracing-spring-web版本:4.1.0
jaeger-client版本:1.8.1
Springboot版本:2.7.6
github地址:honey-tracing
正文
一. Opentracing提供的TracingFilter
其实最简单的增强方式,就是使用TracingFilter来替换我们自己实现的HoneyTracingFilter,下面给出TracingFilter的源码实现。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;if (!isTraced(httpRequest, httpResponse)) {chain.doFilter(httpRequest, httpResponse);return;}if (servletRequest.getAttribute(SERVER_SPAN_CONTEXT) != null) {chain.doFilter(servletRequest, servletResponse);} else {SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS,new HttpServletRequestExtractAdapter(httpRequest));final Span span = tracer.buildSpan(httpRequest.getMethod()).asChildOf(extractedContext).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER).start();httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context());for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {spanDecorator.onRequest(httpRequest, span);}try (Scope scope = tracer.activateSpan(span)) {chain.doFilter(servletRequest, servletResponse);if (!httpRequest.isAsyncStarted()) {for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {spanDecorator.onResponse(httpRequest, httpResponse, span);}}} catch (Throwable ex) {for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {spanDecorator.onError(httpRequest, httpResponse, ex, span);}throw ex;} finally {if (httpRequest.isAsyncStarted()) {httpRequest.getAsyncContext().addListener(new AsyncListener() {@Overridepublic void onComplete(AsyncEvent event) throws IOException {HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {spanDecorator.onResponse(httpRequest,httpResponse,span);}span.finish();}@Overridepublic void onTimeout(AsyncEvent event) throws IOException {HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {spanDecorator.onTimeout(httpRequest,httpResponse,event.getAsyncContext().getTimeout(),span);}}@Overridepublic void onError(AsyncEvent event) throws IOException {HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {spanDecorator.onError(httpRequest,httpResponse,event.getThrowable(),span);}}@Overridepublic void onStartAsync(AsyncEvent event) throws IOException {}});} else {span.finish();}}}
}
通过阅读TracingFilter源码,我们可以得到如下几种扩展增强。
- Servlet自身的urlPatterns机制。可以通过配置urlPatterns,决定哪些请求需要打印链路信息;
- TracingFilter的skipPattern机制。可以通过配置skipPattern,决定哪些请求不需要打印链路信息;
- 装饰器ServletFilterSpanDecorator。可以提供ServletFilterSpanDecorator给到TracingFilter,这样在收到请求,返回响应和处理异常时均可以做一些扩展操作;
二. urlPatterns和skipPattern设计
在第一节中得到的TracingFilter的几种增强,其中第1和第2点的urlPatterns和skipPattern,可以提供出来供用户配置,本节对这部分进行实现。
首先是配置属性类里面需要加入urlPatterns和skipPattern的配置属性,如下所示。
* 分布式链路追踪配置属性类。*/
@ConfigurationProperties("honey.tracing")
public class HoneyTracingProperties {private boolean enabled;private HttpUrlProperties httpUrl = new HttpUrlProperties();public boolean isEnabled() {return enabled;}public void setEnabled(boolean enabled) {this.enabled = enabled;}public HttpUrlProperties getHttpUrl() {return httpUrl;}public void setHttpUrl(HttpUrlProperties httpUrl) {this.httpUrl = httpUrl;}public static class HttpUrlProperties {* 按照/url1,/url2这样配置。*/private String urlPattern = "/*";* 按照/url1|/honey.*这样配置。*/private String skipPattern = "";public String getUrlPattern() {return urlPattern;}public void setUrlPattern(String urlPattern) {this.urlPattern = urlPattern;}public String getSkipPattern() {return skipPattern;}public void setSkipPattern(String skipPattern) {this.skipPattern = skipPattern;}}}
然后注册过滤器的配置类HoneyTracingFilterConfig需要做如下修改。
* Servlet过滤器配置类。*/
@Configuration
@AutoConfigureAfter(HoneyTracingConfig.class)
public class HoneyTracingFilterConfig {@Autowiredprivate HoneyTracingProperties honeyTracingProperties;@Beanpublic FilterRegistrationBean<TracingFilter> honeyTracingFilter(Tracer tracer) {String urlPattern = honeyTracingProperties.getHttpUrl().getUrlPattern();String skipPatternStr = honeyTracingProperties.getHttpUrl().getSkipPattern();Pattern skipPattern = Pattern.compile(skipPatternStr);FilterRegistrationBean<TracingFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.addUrlPatterns(urlPattern);registrationBean.setOrder(Integer.MIN_VALUE);registrationBean.setFilter(new TracingFilter(tracer, new ArrayList<>(), skipPattern));return registrationBean;}}
三. TracingFilter的装饰器设计
通过为TracingFilter注册ServletFilterSpanDecorator装饰器,可以让我们在收到请求,返回响应和处理异常时做一些扩展操作,例如记录请求url,api和返回码等,下面实现一个装饰器HoneyServletFilterSpanDecorator,其提供如下几个功能。
收到请求时记录:
- 请求的host;
- 请求的api。
返回响应时记录:
- 响应码。
处理异常时记录:
- 响应码。
实现如下。
* {@link TracingFilter}的装饰器。*/
public class HoneyServletFilterSpanDecorator implements ServletFilterSpanDecorator {@Overridepublic void onRequest(HttpServletRequest httpServletRequest, Span span) {span.setTag(FIELD_HOST, getHostFromRequest(httpServletRequest));span.setTag(FIELD_API, httpServletRequest.getRequestURI());}@Overridepublic void onResponse(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Span span) {span.setTag(FIELD_HTTP_CODE, httpServletResponse.getStatus());}@Overridepublic void onError(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Throwable exception, Span span) {span.setTag(FIELD_HTTP_CODE, httpServletResponse.getStatus());}@Overridepublic void onTimeout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, long timeout, Span span) {}private String getHostFromRequest(HttpServletRequest httpServletRequest) {return httpServletRequest.getScheme()+ "://"+ httpServletRequest.getServerName()+ ":"+ httpServletRequest.getServerPort();}}
相关的常量字段记录在CommonConstants中,如下所示。
public class CommonConstants {public static final double DEFAULT_SAMPLE_RATE = 1.0;public static final String HONEY_TRACER_NAME = "HoneyTracer";public static final String HONEY_REST_TEMPLATE_NAME = "HoneyRestTemplate";public static final String FIELD_HOST = "host";public static final String FIELD_API = "api";public static final String FIELD_HTTP_CODE = "httpCode";}
在注册TracingFilter时需要将HoneyServletFilterSpanDecorator设置给TracingFilter,对应的配置类HoneyTracingFilterConfig修改如下。
* Servlet过滤器配置类。*/
@Configuration
@AutoConfigureAfter(HoneyTracingConfig.class)
public class HoneyTracingFilterConfig {@Autowiredprivate HoneyTracingProperties honeyTracingProperties;@Beanpublic FilterRegistrationBean<TracingFilter> honeyTracingFilter(Tracer tracer,List<ServletFilterSpanDecorator> decorators) {String urlPattern = honeyTracingProperties.getHttpUrl().getUrlPattern();String skipPatternStr = honeyTracingProperties.getHttpUrl().getSkipPattern();Pattern skipPattern = Pattern.compile(skipPatternStr);FilterRegistrationBean<TracingFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.addUrlPatterns(urlPattern);registrationBean.setOrder(Integer.MIN_VALUE);registrationBean.setFilter(new TracingFilter(tracer, decorators, skipPattern));return registrationBean;}@Beanpublic ServletFilterSpanDecorator honeyServletFilterSpanDecorator() {return new HoneyServletFilterSpanDecorator();}}
至此,我们就使用装饰器装饰了TracingFilter,效果就是最终在TracingFilter调用到Span的finish() 方法时,我们可以从Span的tags中拿到本次请求的host,api和httpCode,这些数据可以最终在打印链路日志时使用。
最后给出工程目录结构图。
总结
本文在4. 分布式链路追踪客户端工具包Starter设计的基础上,使用TracingFilter替换了我们自己实现的HoneyTracingFilter,并且基于urlPatterns,skipPattern和装饰器进行了扩展增强。
相关文章:

5. 分布式链路追踪TracingFilter改造增强设计
前言 在4. 分布式链路追踪客户端工具包Starter设计一文中,我们实现了基础的Starter包,里面提供了我们自己定义的Servlet过滤器和RestTemplate拦截器,其中Servlet过滤器叫做HoneyTracingFilter,仅提供了提取SpanContext࿰…...

C++数据类型与表达式
一 C中的数据类型 二 基本数据类型 三 类型转换 各种类型的高低顺序如下所述; 四 构造数据类型 类类型...

电脑ip地址设置成什么比较好
随着信息技术的快速发展,IP地址已成为电脑在网络世界中的“身份证”。它不仅是电脑在网络中进行通信的基础,也直接关系到网络连接的稳定性、安全性和效率。然而,面对众多IP地址设置选项,许多用户可能会感到困惑。那么,…...
vue-element-template优化升级dart-sass、pnpm
1、替换 node-sass 为 dart-sass - "node-sass": "^4.9.0","sass": "^1.75.0",替换css深度作用域写法 /deep/ >>># 替换为::v-deepVue:Node Sass VS. Dart Sass 2、替换npm为pnpm,需要补充一些依赖…...
Oracle拼接json字符串
在Oracle数据库中,并没有内建的JSON处理函数像其他现代数据库那样直接。但是,你可以使用字符串连接和格式化技巧来拼接JSON字符串。 以下是一个简单的例子,说明如何在Oracle中拼接一个JSON字符串: sql DECLARE v_json_string V…...

如何向Linux内核提交开源补丁?
2021年,我曾经在openEuler社区上看到一项改进Linux内核工具的需求,因此参与过Linux内核社区的开源贡献。贡献开源社区的流程都可以在内核社区文档中找到,但是,单独学习需要一个较长的过程,新手难以入门,因此…...

python数据分析——pandas DataFrame基础知识2
参考资料:活用pandas库 1、分组方式 我们可以把分组计算看作“分割-应用-组合”(split-apply-combine)的过程。首先把数据分割成若干部分,然后把选择的函数(或计算)应用于各部分,最后把所有独立…...

TODESK远程开机的原理
在现代计算机技术飞速发展的背景下,远程控制软件成为我们日常工作中不可或缺的工具。其中,ToDesk作为一款高效且易用的远程控制软件,备受用户青睐。那么,ToDesk远程开机的原理是什么呢?本文将为你揭晓这个秘密。 KKVie…...

【c1】数据类型,运算符/循环,数组/指针,结构体,main参数,static/extern,typedef
文章目录 1.数据类型:编译器(compiler)与解释器(interpreter),中文里的汉字和标点符号是两个字节,不能算一个字符(单引号)2.运算符/循环:sizeof/size_t3.数组…...

word图片水印
一、word中旧水印如何删除 打开word模板,想要删除旧水印,如下图所示操作,但是旧水印删除不掉。 以为上传新水印图片会替换掉旧水印,结果显示了2个水印,要怎么删除呢? 如下截图所示,双击打开页…...

kali安装及替换源
一、安装及简单配置 1.安装:地址就不贴了,自己打一下就好 2.虚拟机中打开kali 3.替换包源 (1)使用指令打开/etc/apt/sources.list mousepad /etc/apt/sources.list (2)将内容替换成阿里云源 deb http://mirrors.aliyun.com/kali kali-rolling main n…...

JSpdf,前端下载大量表格数据pdf文件,不创建dom
数据量太大使用dom》canvas》image》pdf.addimage方法弊端是canvas超出 浏览器承受像素会图片损害,只能将其切割转成小块的canvas,每一次调用html2canvas等待时间都很长累积时间更长,虽然最终可以做到抽取最小dom节点转canvas拼接数据,但是死…...
PHP关联数组[区别,组成,取值,遍历,函数]
关联数组 相较于数值数组,关联数组的索引可以为字符串和数字,关联数组元素也可称为键值对,索引为键,值为值。 源码 <?php echo "<hr>"; //水平线标签//关联数组$arr3 array(); //创建空的数组//关联数…...

JavaWeb--13Mybatis(2)
Mybatis(2) 1 Mybatis基础操作1.1 需求和准备工作1.2 删除员工日志输入参数占位符 1.3 新增员工1.4 修改员工信息1.5 查询员工1.5.1 根据ID查询数据封装 1.5.3 条件查询 2 XML配置文件规范3 MyBatis动态SQL3.1 什么是动态SQL3.2 动态SQL-if更新员工 3.3 …...

如何远程控制另一部手机:远程控制使用方法
在现今高科技的社会中,远程控制手机的需求在某些情境下变得越来越重要。不论是为了协助远在他乡的家人解决问题,还是为了确保孩子的在线安全,了解如何实现这一功能都是有益的。本文将为您简要介绍几种远程控制手机的方法及其使用要点。 KKVi…...

x64dbg中类似于*.exe+地址偏移
在CE和xdb中,形如*.exe数字偏移形式的地址被称为模块地址,CE附加到进程后点击查看内存,显示如下图 这种地址学名叫做模块地址,在x64dbg中显示如下图: CE中可以关闭,从而显示绝对的虚拟地址,如下…...

ICode国际青少年编程竞赛- Python-1级训练场-基础训练1
ICode国际青少年编程竞赛- Python-1级训练场-基础训练1 1、 Dev.step(4)2、 Dev.step(-4) Dev.step(8)3、 Dev.turnLeft() Dev.step(4)4、 Dev.step(3) Dev.turnLeft() Dev.step(-1) Dev.step(4)5、 Dev.step(-1) Dev.step(3) Dev.step(-2) Dev.turnLeft() Dev.step(…...

Baidu Comate智能编码助手
Baidu Comate智能编码助手 🎈1.Baidu Comate的简介🎈2.安装Baidu Comate🎈3.Baidu Comate实现功能🎈4.使用注释进行智能代码提示🎈5.结束语 🎈1.Baidu Comate的简介 根据官网的介绍,我们了解到B…...

nginx自动部署-跨操作系统
项目里面有一个需求,就是需要用让nginx进程提供给系统管理一个start,stop和getPid方法,这样系统管理可以自动拉起来nginx,达到自动部署的目的。离线部署同样适用 这样一来,我就需要提供windows版本linux不同版本的nginx源码包&am…...

组合模式(结构型)
目录 一、前言 二、透明组合模式 三、安全组合模式 四、总结 一、前言 组合模式(Composite Pattern)是一种结构型设计模式,将对象组合成树形结构以表示“部分-整体”得层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 组合模式由以下角色组成…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...

基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...