使用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.png1.2 skywalking的配置
使用腾讯云cos文件存储的sdk时,skywalking并未将链路打印出来,从而出现了断层。
image.png在skywalking的github上查询,并未发现okHttp的插件。
image.png由上图可知,只有okhttp3的插件。这就是为什么okHttp3的调用链路可以在skywalking上显示,而腾讯云sdk的调用会出现断层。
2. 解决版本
代码按照okHttp3插件进行仿写,该项目作为多个plugins插件的编写项目,采用多模块方式。
结构图:
image.png2.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 编译打包
image.png编译打包放到服务器的
apache-skywalking-apm-bin/agent/plugins
下,重启应用服务器。即可完成自定义组件的链路追踪。
附录
附录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>
网友评论