PDF书籍《手写调用链监控APM系统-Java版》第11章 插件与链路的结合:HttpClient插件实现跨进程传输TraceSegment

ops/2024/12/28 9:20:19/

本人阅读了 Skywalking 的大部分核心代码,也了解了相关的文献,对此深有感悟,特此借助巨人的思想自己手动用JAVA语言实现了一个 “调用链监控APM” 系统。本书采用边讲解实现原理边编写代码的方式,看本书时一定要跟着敲代码。

作者已经将过程写成一部书籍,奈何没有钱发表,如果您知道渠道可以联系本人。一定重谢。

本书涉及到的核心技术与思想

JavaAgent , ByteBuddy,SPI服务,类加载器的命名空间,增强JDK类,kafka,插件思想,切面,链路栈等等。实际上远不止这么多,差不多贯通了整个java体系。

适用人群

自己公司要实现自己的调用链的;写架构的;深入java编程的;阅读Skywalking源码的;

版权

本书是作者呕心沥血亲自编写的代码,不经同意切勿拿出去商用,否则会追究其责任。

原版PDF+源码请见:

本章涉及到的工具类也在这里面:

PDF书籍《手写调用链监控APM系统-Java版》第1章 开篇介绍-CSDN博客

第11章 插件与链路的结合:HttpClient插件实现跨进程传输TraceSegment

之所以要讲这个插件就是因为http调用涉及到跨进程传输,会有新的TraceSegment生成,需要把当前TraceSegment信息设置到Http请求头里面进行跨进程传输到后一个TraceSegment上面。

要想对httpclient的接口请求进行拦截,需要拦截的信息如下:

类名:org.apache.commons.httpclient.HttpClient

方法:executeMethod

非JDK类库

下面来开发这个插件,要记住前面说的插件开发四部曲。在插件模块下新增http-client-plugin项目,hadluo-apm-plugin.def内容如下:

http-client=com.hadluo.apm.httpclient.HttpClientInstrumentation

HttpClientInstrumentation代码如下:

public class HttpClientInstrumentation extends AbstractClassEnhancePluginDefine {@Overridepublic String enhanceClass() {// 拦截类return "org.apache.commons.httpclient.HttpClient";}@Overridepublic MethodsInterceptPoint[] configMethodsInterceptPoint() {return new MethodsInterceptPoint[]{new MethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {// 拦截方法return ElementMatchers.named("executeMethod").and(ElementMatchers.takesArguments(HttpMethod.class));}@Overridepublic String getMethodsInterceptor() {// 拦截处理逻辑return "com.hadluo.apm.httpclient.HttpClientInterceptor";}@Overridepublic boolean isOverrideArgs() {return false;}}};}
}

HttpClientInterceptor代码如下:

public class HttpClientInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes) throws Throwable {HttpMethod httpMethod = (HttpMethod) allArguments[0];final String remotePeer = httpMethod.getURI().getHost() + ":" + httpMethod.getURI().getPort();ContextCarrier contextCarrier = new ContextCarrier();TraceContextManager service = ServiceManager.INSTANCE.getService(TraceContextManager.class);// 创建span , 并且把当前segment的信息 设置到 contextCarrier里面AbstractSpan exitSpan = service.createExitSpan(httpMethod.getURI().getPath(), remotePeer, contextCarrier);// 设置标签等信息exitSpan.setComponent("HttpClient");exitSpan.setLayer(SpanLayer.HTTP) ;exitSpan.setTag("url" , httpMethod.getURI().toString()) ;exitSpan.setTag("method" , httpMethod.getName()) ;// 将contextCarrier 信息设置到 http请求头里面, 传递到下一个 跨进程的segment上Map<String, String> serialize = contextCarrier.serialize();for(String key : serialize.keySet()){httpMethod.setRequestHeader(key, serialize.get(key));}}@Overridepublic Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {TraceContextManager service = ServiceManager.INSTANCE.getService(TraceContextManager.class);service.stopSpan();return ret;}@Overridepublic void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {TraceContextManager service = ServiceManager.INSTANCE.getService(TraceContextManager.class);service.activeSpan().log(t) ;}
}

我们首先构造了一个空的ContextCarrier , 然后传递到createExitSpan方法里面,这个方法我们之前只实现了两个参数的,我们需要增加这个重载方法的实现。在TraceContextManager增加方法:

public AbstractSpan createExitSpan(String operationName, String remotePeer , ContextCarrier contextCarrier){AbstraceTraceContext context = getOrCreate(true) ;AbstractSpan exitSpan = context.createExitSpan(operationName, remotePeer);context.inject(contextCarrier);return exitSpan ;
}

通过inject方法,我们将context上的segment信息设置到了空的ContextCarrier 上面, inject代码如下:

 @Override
public void inject(ContextCarrier carrier) {carrier.setTraceId(traceSegment.getTraceId());carrier.setTraceSegmentId(traceSegment.getTraceSegmentId());carrier.setSpanId(acviveSpan().getSpanId());carrier.setParentServiceInstance(Config.Agent.serviceInstance);carrier.setParentServiceName(Config.Agent.serviceName);
}

经过这个设置,我们的ContextCarrier 里面就有当前的segment信息了,然后回到插件的beforeMethod, 下面将ContextCarrier 的信息序列化到map里面,serialize也是新增的,代码如下:

public Map<String, String> serialize(){Map<String, String> param = new HashMap<String, String>();for (Field f : this.getClass().getDeclaredFields()) {if(Modifier.isStatic(f.getModifiers())){continue;}f.setAccessible(true);try {param.put(SW_FLAG + f.getName() , f.get(this).toString()) ;} catch (IllegalAccessException e) {Logs.err(getClass(), "ContextCarrier serialize错误, field: " + f.getName(), e);}}return param ;
}

通过这个serialize序列化后,就把信息转存到了map里面,最后通过遍历Map,httpMethod.setRequestHeader将每个值设置到了请求头里面传递到下一个进程。

由于代码过于简单,作者就不在测试此插件,读者也应该能自己测试了,有问题的可以向作者提出,万分感谢!


http://www.ppmy.cn/ops/145622.html

相关文章

【机器学习】机器学习的基本分类-半监督学习-半监督生成对抗网络(Semi-supervised GANs)

半监督生成对抗网络&#xff08;Semi-supervised GANs&#xff0c;简称 SGAN&#xff09;是一种结合生成对抗网络&#xff08;GAN&#xff09;和半监督学习的模型&#xff0c;能够在有限标注数据和大量未标注数据的情况下训练分类器。它扩展了传统 GAN 的结构&#xff0c;使得判…

高校网络安全存在的问题与对策研究

目 录 摘 要1 第1章 引言2 1.1研究背景2 1.2研究意义2 第2章系统开发的相关技术简介3 2.1 Spring boot框架3 2.2 MySQL简介3 2.3 Vue框架3 2.4 JAVA简介3 第3章 系统需求分析4 3.1可行性分析4 3.1.1技术可行性4 3.1.2运行可行性4 3.1.3经济可行性5 3.2功能需求…

深入了解 Java 字符串:基础、操作与性能优化

在 Java 编程中&#xff0c;字符串 是最常用的数据类型之一。几乎所有的 Java 应用程序都会涉及到字符串操作&#xff0c;无论是读取用户输入、处理文件内容&#xff0c;还是与数据库进行交互。因此&#xff0c;掌握 Java 字符串的使用方式和相关技巧&#xff0c;对开发者来说至…

笔记本电脑需要一直插着电源吗?电脑一直充电的利弊介绍

笔记本电脑属于常用电子设备&#xff0c;它的便携性和功能性给我们带来了很多便利。但是&#xff0c;我们在使用笔记本电脑的时候&#xff0c;是否应该一直插着电源呢&#xff1f;这个问题可能困扰了很多人&#xff0c;因为不同的使用方式可能会对笔记本电脑的性能和寿命产生不…

AI 机器人外呼:智能沟通,开启全新营销与服务篇章

在当今数字化高速发展的时代&#xff0c;企业的营销与客户服务方式正经历着深刻变革。 AI 机器人外呼作为一项创新技术&#xff0c;正逐渐崭露头角&#xff0c;成为众多企业提升效率、优化客户体验的得力助手。 你是否接到过这样的电话&#xff1a;声音清晰流畅&#xff0c;对…

【开源免费】基于Vue和SpringBoot的海滨学院班级回忆录系统(附论文)

本文项目编号 T 114 &#xff0c;文末自助获取源码 \color{red}{T114&#xff0c;文末自助获取源码} T114&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

SLES网络

一、高级网络接口 1.理解高级网络接口的概念 Linux网络接口相关层在OSI中的位置 1.1数据链路层 定义了节点间通信的协议检测并纠正物理层产生的错误分为两个子层&#xff1a; 媒体访问控制&#xff08;MAC&#xff09;&#xff1a;节点如何获取访问物理媒体的权限并传输数据…

视频编码中的算法、技术学习

编解码小白最近在学习视频编码中各种各样的技术&#xff0c;简单记录学习到的内容&#xff0c;希望大佬们指点指点不足之处。 这里是大目录&#xff0c;会持续更新接触到的技术。 编码技术-UMVE编码技术-HMVP编码技术-RDOQ编码技术-二次变换编码技术-MCTF编码技术-AQ ------…