当前位置: 首页 > news >正文

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源码,我们可以得到如下几种扩展增强。

  1. Servlet自身的urlPatterns机制。可以通过配置urlPatterns,决定哪些请求需要打印链路信息;
  2. TracingFilterskipPattern机制。可以通过配置skipPattern,决定哪些请求不需要打印链路信息;
  3. 装饰器ServletFilterSpanDecorator。可以提供ServletFilterSpanDecorator给到TracingFilter,这样在收到请求,返回响应和处理异常时均可以做一些扩展操作;

二. urlPatterns和skipPattern设计

在第一节中得到的TracingFilter的几种增强,其中第1和第2点的urlPatternsskipPattern,可以提供出来供用户配置,本节对这部分进行实现。

首先是配置属性类里面需要加入urlPatternsskipPattern的配置属性,如下所示。

* 分布式链路追踪配置属性类。*/
@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装饰器,可以让我们在收到请求,返回响应和处理异常时做一些扩展操作,例如记录请求urlapi和返回码等,下面实现一个装饰器HoneyServletFilterSpanDecorator,其提供如下几个功能。

收到请求时记录:

  1. 请求的host
  2. 请求的api

返回响应时记录:

  1. 响应码。

处理异常时记录:

  1. 响应码。

实现如下。

* {@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调用到Spanfinish() 方法时,我们可以从Spantags中拿到本次请求的hostapihttpCode,这些数据可以最终在打印链路日志时使用。

最后给出工程目录结构图。

总结

本文在4. 分布式链路追踪客户端工具包Starter设计的基础上,使用TracingFilter替换了我们自己实现的HoneyTracingFilter,并且基于urlPatternsskipPattern和装饰器进行了扩展增强。

相关文章:

5. 分布式链路追踪TracingFilter改造增强设计

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

C++数据类型与表达式

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

电脑ip地址设置成什么比较好

随着信息技术的快速发展&#xff0c;IP地址已成为电脑在网络世界中的“身份证”。它不仅是电脑在网络中进行通信的基础&#xff0c;也直接关系到网络连接的稳定性、安全性和效率。然而&#xff0c;面对众多IP地址设置选项&#xff0c;许多用户可能会感到困惑。那么&#xff0c;…...

vue-element-template优化升级dart-sass、pnpm

1、替换 node-sass 为 dart-sass - "node-sass": "^4.9.0","sass": "^1.75.0",替换css深度作用域写法 /deep/ >>># 替换为::v-deepVue&#xff1a;Node Sass VS. Dart Sass 2、替换npm为pnpm&#xff0c;需要补充一些依赖…...

Oracle拼接json字符串

在Oracle数据库中&#xff0c;并没有内建的JSON处理函数像其他现代数据库那样直接。但是&#xff0c;你可以使用字符串连接和格式化技巧来拼接JSON字符串。 以下是一个简单的例子&#xff0c;说明如何在Oracle中拼接一个JSON字符串&#xff1a; sql DECLARE v_json_string V…...

如何向Linux内核提交开源补丁?

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

python数据分析——pandas DataFrame基础知识2

参考资料&#xff1a;活用pandas库 1、分组方式 我们可以把分组计算看作“分割-应用-组合”&#xff08;split-apply-combine&#xff09;的过程。首先把数据分割成若干部分&#xff0c;然后把选择的函数&#xff08;或计算&#xff09;应用于各部分&#xff0c;最后把所有独立…...

TODESK远程开机的原理

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

【c1】数据类型,运算符/循环,数组/指针,结构体,main参数,static/extern,typedef

文章目录 1.数据类型&#xff1a;编译器&#xff08;compiler&#xff09;与解释器&#xff08;interpreter&#xff09;&#xff0c;中文里的汉字和标点符号是两个字节&#xff0c;不能算一个字符&#xff08;单引号&#xff09;2.运算符/循环&#xff1a;sizeof/size_t3.数组…...

word图片水印

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

kali安装及替换源

一、安装及简单配置 1.安装&#xff1a;地址就不贴了&#xff0c;自己打一下就好 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超出 浏览器承受像素会图片损害&#xff0c;只能将其切割转成小块的canvas,每一次调用html2canvas等待时间都很长累积时间更长&#xff0c;虽然最终可以做到抽取最小dom节点转canvas拼接数据&#xff0c;但是死…...

PHP关联数组[区别,组成,取值,遍历,函数]

关联数组 相较于数值数组&#xff0c;关联数组的索引可以为字符串和数字&#xff0c;关联数组元素也可称为键值对&#xff0c;索引为键&#xff0c;值为值。 源码 <?php echo "<hr>"; //水平线标签//关联数组$arr3 array(); //创建空的数组//关联数…...

JavaWeb--13Mybatis(2)

Mybatis&#xff08;2&#xff09; 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 …...

如何远程控制另一部手机:远程控制使用方法

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

x64dbg中类似于*.exe+地址偏移

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

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智能编码助手 &#x1f388;1.Baidu Comate的简介&#x1f388;2.安装Baidu Comate&#x1f388;3.Baidu Comate实现功能&#x1f388;4.使用注释进行智能代码提示&#x1f388;5.结束语 &#x1f388;1.Baidu Comate的简介 根据官网的介绍&#xff0c;我们了解到B…...

nginx自动部署-跨操作系统

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

组合模式(结构型)

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

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...