美文网首页
skywalking(2)自定义插件【okhttp插件-监控co

skywalking(2)自定义插件【okhttp插件-监控co

作者: 小胖学编程 | 来源:发表于2021-07-10 21:05 被阅读0次

使用skywalking时经常会出现断层,则是因为skywalking并没有提供对应的插件导致无法在链路图中体现调用流程。

1. 起因

1.1 腾讯云sdk版本

        <!--腾讯云cos最新的api文档-->
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java</artifactId>
            <!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
            <!-- 请到https://search.maven.org/search?q=tencentcloud-sdk-java查询所有版本,最新版本如下 -->
            <version>3.1.271</version>
        </dependency>

代码位置:

image.png

1.2 skywalking的配置

使用腾讯云cos文件存储的sdk时,skywalking并未将链路打印出来,从而出现了断层。

image.png

在skywalking的github上查询,并未发现okHttp的插件。

image.png

由上图可知,只有okhttp3的插件。这就是为什么okHttp3的调用链路可以在skywalking上显示,而腾讯云sdk的调用会出现断层。

2. 解决版本

代码按照okHttp3插件进行仿写,该项目作为多个plugins插件的编写项目,采用多模块方式。

结构图:

image.png

2.1 父pom依赖

这些依赖必须存在,可以根据项目实际的skywalking版本设置skywalking.version版本号。

代码详见—附录1

2.2 okhttp插件编写

2.2.1 配置文件

skywalking首先去skywalking-plugin.def配置中定位将要增强的类。

okhttp=com.tellme.define.CallInstrumentation

key:不限定,可自由定义
value:ClassInstanceMethodsEnhancePluginDefine的实现类

2.2.2 ClassInstanceMethodsEnhancePluginDefine实现类

声明增强的类,以及将要拦截的方法。

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;

import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.named;

/**
 * okHttp插件入口
 *
 */
public class CallInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

    /**
     * 将要增强的类
     */
    private static final String ENHANCE_CLASS = "com.squareup.okhttp.Call";

    /**
     * 增强代码的拦截器
     */
    private static final String INTERCEPT_CLASS = "com.xdf.pscommon.CallInterceptor";


    /**
     * 声明需要增强的类
     */
    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }

    /**
     * 要拦截的构造方法
     */
    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[]{
                new ConstructorInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getConstructorMatcher() {
                        return any();
                    }

                    @Override
                    public String getConstructorInterceptor() {
                        return INTERCEPT_CLASS;
                    }
                }
        };
    }

    /**
     * 要拦截的普通方法
     */
    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return named("execute");
                    }

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

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

}

2.2.3 增强方法的拦截器

本质上采用的是AOP对方法进行增强,并将Span的数据设置到header中传递到别的服务。

import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;

/**
 * 增强方法的拦截器
 */
public class CallInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {

    /**
     * 拦截构造方法,将第二个参数request对象传递下去
     */
    @Override
    public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
        //设置第一个参数
        objInst.setSkyWalkingDynamicField(allArguments[1]);
    }

    /**
     * 前置通知
     */
    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
        Request request = (Request) objInst.getSkyWalkingDynamicField();

        ContextCarrier contextCarrier = new ContextCarrier();


        URL requestUrl = request.url();

        AbstractSpan span = ContextManager.createExitSpan(requestUrl.toURI()
                .getPath(), contextCarrier, requestUrl.getHost() + ":" + requestUrl
                .getPort());
        span.setComponent(ComponentsDefine.OKHTTP);
        Tags.HTTP.METHOD.set(span, request.method());
        Tags.URL.set(span, requestUrl.toURI().toString());
        SpanLayer.asHttp(span);


        Field headersField = Request.class.getDeclaredField("headers");
        headersField.setAccessible(true);

        Headers.Builder headerBuilder = request.headers().newBuilder();
        CarrierItem next = contextCarrier.items();
        while (next.hasNext()) {
            next = next.next();
            headerBuilder.set(next.getHeadKey(), next.getHeadValue());
        }
        headersField.set(request, headerBuilder.build());
    }

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
        Response response = (Response) ret;
        if (response != null) {
            int statusCode = response.code();
            AbstractSpan span = ContextManager.activeSpan();
            if (statusCode >= 400) {
                span.errorOccurred();
                Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
            }
        }

        ContextManager.stopSpan();

        return ret;
    }

    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
        AbstractSpan abstractSpan = ContextManager.activeSpan();
        abstractSpan.log(t);
    }
}

2.2.4 编译打包

编译打包放到服务器的apache-skywalking-apm-bin/agent/plugins下,重启应用服务器。即可完成自定义组件的链路追踪。

image.png

附录

附录1—父pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xdf.pscommon</groupId>
    <artifactId>skywalking-plugins</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0-SNAPSHOT</version>
    <modules>
        <module>apm-okhttp-plugin</module>
    </modules>

    <properties>
        <skywalking.version>8.2.0</skywalking.version>
        <shade.package>org.apache.skywalking.apm.dependencies</shade.package>
        <shade.net.bytebuddy.source>net.bytebuddy</shade.net.bytebuddy.source>
        <shade.net.bytebuddy.target>${shade.package}.${shade.net.bytebuddy.source}</shade.net.bytebuddy.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
            <optional>true</optional>
        </dependency>


        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-agent-core</artifactId>
            <version>${skywalking.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-util</artifactId>
            <version>${skywalking.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
    
    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.0.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>


            <plugin>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <shadedArtifactAttached>false</shadedArtifactAttached>
                            <createDependencyReducedPom>true</createDependencyReducedPom>
                            <createSourcesJar>true</createSourcesJar>
                            <shadeSourcesContent>true</shadeSourcesContent>
                            <relocations>
                                <relocation>
                                    <pattern>${shade.net.bytebuddy.source}</pattern>
                                    <shadedPattern>${shade.net.bytebuddy.target}</shadedPattern>
                                </relocation>
                            </relocations>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

附录2—子pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>skywalking-plugins</artifactId>
        <groupId>com.xdf.pscommon</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <artifactId>okhttp-plugin</artifactId>


    <dependencies>
        <dependency>
            <groupId>com.squareup.okhttp</groupId>
            <artifactId>okhttp</artifactId>
            <version>2.5.0</version>
        </dependency>
    </dependencies>

</project>

推荐阅读

手把手教你编写Skywalking插件
Skywalking 6.2.0中文文档

相关文章

网友评论

      本文标题:skywalking(2)自定义插件【okhttp插件-监控co

      本文链接:https://www.haomeiwen.com/subject/falfpltx.html