skywalking agent插件开发过程中各种拦截点的写法

本文详细介绍了在开发SkyWalking插件过程中,如何利用拦截器匹配普通类、内部类、接口实现类以及注解修饰的类和方法。通过具体的代码示例,展示了net.bytebuddy.matcher.ElementMatchers和org.apache.skywalking.apm.agent.core.plugin.match等工具的使用方法,为SkyWalking插件开发者提供参考。

概述

自己在开发插件的过程中,因为书写拦截器遇到了不少问题,记录于此,以供参考。

拦截普通类

拦截普通类这个场景比较常见,可以net.bytebuddy.matcher.ElementMatchers#named(ClassName)来进行匹配,具体例子如下:

来自WebfluxWebClient插件org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine:

@Override
protected ClassMatch enhanceClass() {
    return NameMatch.byName(ENHANCE_CLASS);
}

拦截内部类

连接内部实际上和拦截不同类用的方法一样,唯一的不同点是类的写法不同,如果是普通类,直接写其路径名即可,比如

private static final String ENHANCE_CLASS = "com.package.ClassName"

而内部类则需要在内部类和外部类之间加一个#号来进行分割,而不能用.

具体写法如下:private static final String ENHANCE_CLASS = "com.package.ClassName"

拦截接口实现类

拦截接口实现类则不同,需要通过org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch#byHierarchyMatch(String ..paraentType)传入的参数是可变参数,也就是说传入拦截的接口可以是多个。具体使用方式如下:

来自light4j-plugins插件的org.apache.skywalking.apm.plugin.light4j.define.LightInstrumentation:

@Override
protected ClassMatch enhanceClass() {
    return HierarchyMatch.byHierarchyMatch(new String[] {ENHANCE_CLASS});
}

拦截注解

拦截注解,则分成两种情况:

拦截注解修饰的类

拦截指定注解修饰的类要通过org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch#byClassAnnotationMatch(String .. annotation)来进行拦截,具体例子如下:

@Override
protected ClassMatch enhanceClass() {
    return byClassAnnotationMatch(new String[] {ANNOTATION_NAME});
}

拦截注解修饰的方法

拦截指定注解修饰的类要通过org.apache.skywalking.apm.agent.core.plugin.match.MethodInheritanceAnnotationMatcher#byMethodInheritanceAnnotationMatcher(),这个方法主要是重写的getInstanceMethodsInterceptPoints()里边的,具体用法和前边的不同:

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
    return new InstanceMethodsInterceptPoint[] {
        new DeclaredInstanceMethodsInterceptPoint() {
            @Override
            public ElementMatcher<MethodDescription> getMethodsMatcher() {
                return byMethodInheritanceAnnotationMatcher(named(REQUEST_MAPPING_ENHANCE_ANNOTATION));
            }

            @Override
            public String getMethodsInterceptor() {
                return REQUEST_MAPPING_METHOD_INTERCEPTOR;
            }

            @Override
            public boolean isOverrideArgs() {
                return false;
            }
        }
    };
}

同时由于对匹配的类不作要求,因而可以统一写成如下样式:

@Override
protected ClassMatch enhanceClass() {
    return ClassAnnotationMatch.byClassAnnotationMatch(getEnhanceAnnotations());
}

总结

本文主要总结了自己写SkyWalking agent端插件的时候常用的匹配方法,并对每一个方法写了一个demo以供参考(所有demo均来自社区插件中的具体类),希望能给想开发SkyWalking插件的小伙伴以帮助。

### SkyWalking Agent 拦截数据原理及获取数据机制 #### 1. 插件机制与拦截原理 SkyWalking Agent 使用插件机制来拦截应用程序中的方法调用,从而实现对运行时数据的采集。其核心思想是通过字节码增强技术(Bytecode Instrumentation),在目标类的方法执行前后插入自定义逻辑[^2]。具体来说: - **字节码增强**:Agent 使用 ASM 或 ByteBuddy 等库对目标类的字节码进行修改,在方法执行前和执行后插入特定的逻辑代码。 - **插件配置**:插件通过 `plugin.config` 文件配置,支持多种中间件(如 Spring、Dubbo、MyBatis 等)[^3]。每个插件都定义了需要拦截的目标类和方法。 例如,以下是一个典型的插件配置示例: ```properties # 配置 Dubbo 插件 dubbo.interceptor.order=1 dubbo.methods.include=com.example.service.* ``` #### 2. 数据采集过程 当 Agent 拦截到目标方法的调用时,会收集以下类型的数据[^4]: - **性能指标**:包括方法的执行时间、调用次数、成功率等。 - **调用链路**:记录方法调用的上下文信息,例如入口点、出口点以及跨服务调用的追踪 ID。 - **异常信息**:捕获方法执行过程中抛出的异常及其堆栈信息。 以下是数据采集的核心流程: - **拦截点注册**:Agent 在应用启动时扫描所有已配置的插件,并将拦截点注册到字节码增强框架中。 - **方法拦截**:当目标方法被调用时,增强后的字节码会在方法执行前后触发自定义逻辑。 - **数据上报**:拦截到的数据会被序列化并通过 gRPC 协议发送到 OAP Server 的 11800 端口[^1]。 #### 3. 数据传输与协议 SkyWalking 使用 gRPC 作为主要的通信协议,确保数据传输的高效性和可靠性。Agent 在初始化时会连接到 OAP Server,并通过以下方式发送数据[^5]: - **实时上报**:数据采集完成后立即发送到 OAP Server。 - **批量模式**:为了减少网络开销,Agent 可以将多个数据包合并为一个批次再进行发送。 以下是 Agent 连接 OAP Server 的典型配置: ```bash -Dskywalking.collector.backend_service=collector-host:11800 ``` #### 4. 数据处理与存储 OAP Server 接收到数据后,会对数据进行解析、聚合和存储。具体的处理流程包括: - **解析数据**:将接收到的二进制数据反序列化为结构化的对象。 - **聚合分析**:对性能指标和调用链路进行统计分析,生成可视化报表。 - **存储数据**:将处理后的数据存储到后端存储系统(如 Elasticsearch 或 H2)中[^6]。 #### 5. 示例代码 以下是一个简单的拦截逻辑示例,展示了如何在方法执行前后插入自定义逻辑: ```java public class MethodInterceptor { public Object beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptContext context) throws Throwable { // 方法执行前的操作 System.out.println("Before method: " + method.getName()); return null; } public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { // 方法执行后的操作 System.out.println("After method: " + method.getName()); return ret; } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值