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)是一种结构型设计模式,将对象组合成树形结构以表示“部分-整体”得层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 组合模式由以下角色组成…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...
