skywalking-agent自定义插件
SkyWalking 插件的工作机制主要基于 Java Agent,它会在应用启动时自动附加到目标应用上。插件主要实现方法拦截(Method Intercept),即在指定的方法执行之前、之后或者发生异常时进行操作,以便收集监控数据。增强类定义(Enhancement Class):指定需要增强的目标类。方法拦截器(Method Interceptor):定义拦截的逻辑,比如调用链的开始、结束、异
·
官方文档:
链接: skywalking-agent
目录
1. SkyWalking 插件架构概述
SkyWalking 插件的工作机制主要基于 Java Agent,它会在应用启动时自动附加到目标应用上。插件主要实现方法拦截(Method Intercept),即在指定的方法执行之前、之后或者发生异常时进行操作,以便收集监控数据。
每个插件通常包括以下几个模块:
- 增强类定义(Enhancement Class):指定需要增强的目标类。
- 方法拦截器(Method Interceptor):定义拦截的逻辑,比如调用链的开始、结束、异常捕获等。
- 上下文传递(Context Propagation):在分布式追踪中,将上下文信息(如 TraceId)传递到其他线程或请求中。
2. 插件工程
- 在 my-custom-plugin 中的 src/main/resources/skywalking-plugin.def 文件中定义插件的入口类。
aa=com.example.plugin.MyCustomPluginInstrumentation
3. 开发一个插件
- 需求:为特定的类方法创建span,使该方法可以在trace链路中显示出来,监控该方法
3.1 定义插件入口类
- 插件入口类(Instrumentation)用于指定目标类和目标方法。通过实现 ClassInstanceMethodsEnhancePluginDefine 接口来定义哪个类和方法需要增强。
public class DynamicInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final Map<String, List<String>> CLASS_METHOD_MAP = InterceptConfigManager.getClassMethodMap();
@Override
protected ClassMatch enhanceClass() {
// 返回所有需要增强的类
String join = String.join(",", CLASS_METHOD_MAP.keySet());
return MultiClassNameMatch.byMultiClassMatch(String.join(",", CLASS_METHOD_MAP.keySet()));
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
List<InstanceMethodsInterceptPoint> points = new ArrayList<>();
// 指定需要拦截的方法和拦截器
CLASS_METHOD_MAP.forEach((className, methods) -> {
methods.forEach(method ->{
points.add(new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(method);
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.method.statistics.ExampleMethodInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
});
});
});
InstanceMethodsInterceptPoint[] array = new InstanceMethodsInterceptPoint[points.size()];
array = points.toArray(array);
return array;
}
}
3.2 创建拦截器
- 拦截器用于定义具体的拦截逻辑。通过实现 InstanceMethodsAroundInterceptor 接口,可以定义在方法执行的前、后、异常等阶段执行的逻辑。
- 在ExampleMethodInterceptor 中:
- beforeMethod:方法开始前执行,这里创建一个新的 Span。
- afterMethod:方法执行后执行,结束当前 Span。
- handleMethodException:在方法执行中出现异常时执行,将异常记录到 Span 中,以便追踪和监控异常情况。
public class ExampleMethodInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(
EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
// 创建 LocalSpan
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
AbstractSpan span = ContextManager.createLocalSpan(className + "/"+methodName);
}
@Override
public Object afterMethod(
EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Object ret) throws Throwable {
// 结束 LocalSpan
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(
EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Throwable t) {
// 捕获异常并记录到 Span
ContextManager.activeSpan().errorOccurred().log(t);
}
}
3.3 读取特定方法,指定config文件
public class InterceptConfigManager {
private static final String CONFIG_FILE = "config/apm-test.config";
private static final Map<String, List<String>> CLASS_METHOD_MAP = new ConcurrentHashMap<>();
static {
loadConfig();
}
public static void loadConfig() {
try {
File configFile = new File(AgentPackagePath.getPath(), CONFIG_FILE);
List<String> lines = Files.readAllLines(configFile.toPath());
CLASS_METHOD_MAP.clear();
for (String line : lines) {
String[] parts = line.split("=");
if (parts.length == 2) {
String className = parts[0].trim();
String[] methods = parts[1].split(",");
CLASS_METHOD_MAP.put(className, Arrays.asList(methods));
}
}
System.out.println("Config loaded: " + CLASS_METHOD_MAP);
} catch (IOException e) {
throw new RuntimeException("Failed to load plugin configuration: " + CONFIG_FILE, e);
} catch (AgentPackageNotFoundException e) {
throw new RuntimeException(e);
}
}
public static Map<String, List<String>> getClassMethodMap() {
return CLASS_METHOD_MAP;
}
}
3.4 配置 skywalking-plugin.def
在 skywalking-plugin.def 文件中,注册插件入口类,使得 SkyWalking 可以加载该插件:
myself=org.apache.skywalking.apm.method.statistics.DynamicInstrumentation
3.4 配置 config文件
- /skywalking-agent/config 创建apm-test.config
com.xx.package.A=method1,method2
com.xx.package.B=method3,method4
3.5 重启服务重新加载agent即可,观察sw-ui,这里不在演示啦
更多推荐
所有评论(0)