SkyWalking-自定义插件

当现有skywalking无法满足现有统计需求时,需要自定义统计维度,或者对自研中间件进行监控,可以通过添加skywalking的插件来实现无侵入的添加功能

执行步骤:

  • 创建一个自定义插件项目
  • pom文件继承apm-sdk-plugin
  • 继承ClassInstanceMethodsEnhancePluginDefine,用于设置需要拦截的类
  • 实现InstanceMethodsAroundInterceptor,用于对拦截的类进行额外功能扩展
  • 添加skywalking-plugin.def,指定插件拦截类路径,skywalking启动时会加载该类
  • maven打包,并把打好的包放在agent\plugins目录下面
  • 重启服务

(1)maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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>

<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-sdk-plugin</artifactId>
<version>8.5.0</version>
</parent>

<groupId>cn.aacopy.skywalking.plugin.plus</groupId>
<artifactId>skywalking-plugin-plus</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<checkstyle.skip>true</checkstyle.skip>
</properties>

</project>

(2)拦截类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package cn.aacopy.skywalking.plugin.plus;

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.PrefixMatch;

import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;

/**
* @author iseven.yang
* @date 2022/10/27 14:45
*/
public class CountTestHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

public static final String METHOD_INTERCEPTOR_CLASS = "cn.aacopy.skywalking.plugin.plus.CountTestHandlerMethodInterceptor";

@Override
protected ClassMatch enhanceClass() {
//需要对哪些类做增强
return PrefixMatch.nameStartsWith("cn.aacopy.test.simpleboot");
}

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return nameStartsWith("fun");
}

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

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

(3)拦截处理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package cn.aacopy.skywalking.plugin.plus;

import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
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.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.Method;
import java.util.HashMap;
import java.util.Map;

/**
* @author iseven.yang
* @date 2022/10/27 14:53
*/
public class CountTestHandlerMethodInterceptor implements InstanceMethodsAroundInterceptor {

private static Map<String, Long> count = new HashMap<>();
@Override
public void beforeMethod(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, MethodInterceptResult methodInterceptResult) throws Throwable {
if(count.containsKey(method.getName())) {
count.put(method.getName(), count.get(method.getName()) + 1);
} else {
count.put(method.getName(), 1L);
}
AbstractSpan span = ContextManager.createLocalSpan("CountTest:"+method.getName());
span.setComponent(ComponentsDefine.TOMCAT);
span.tag(new StringTag(1000, "params"), objects[0].toString());
span.setLayer(SpanLayer.CACHE);
}

@Override
public Object afterMethod(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Object o) throws Throwable {
System.out.println(method.getName() + "方法调用次数===========" + count.get(method.getName()));
AbstractSpan span = ContextManager.activeSpan();
Tags.STATUS_CODE.set(span, String.valueOf(count.get(method.getName())));
ContextManager.stopSpan();
return o;
}

@Override
public void handleMethodException(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Throwable throwable) {
ContextManager.activeSpan().log(throwable);
}
}

(4)skywalking-plugin.def

1
count-test-plugin=cn.aacopy.skywalking.plugin.plus.CountTestHandlerInstrumentation

测试

随便写一个springboot工程,启动加入skywalkingagent包,访问接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package cn.aacopy.test.simpleboot.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
* @author iseven.yang
* @date 2022/10/27 11:16
*/
@RestController
public class TestController {

@GetMapping("/test1")
public String test1Haha() {
System.out.println("hahaha");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hahah";
}

@GetMapping("/test2")
public String test2Haha(@RequestParam String name) {
System.out.println("hahaha2sssssssss");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hihei" + name;
}

@GetMapping("/test3")
public String test3Haha1() {
System.out.println("hihei123123213");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hihei1232312322";
}
}

访问效果:后台

skywalking控制台